fix: 修复多个关键问题
- 修复前端路由守卫:未登录时不显示提示,直接跳转登录页 - 修复API拦截器:401错误不显示提示,直接跳转 - 增强验证码显示:图片尺寸从120x40增加到200x80 - 增大验证码字体:从28号增加到48号 - 优化验证码字符:排除易混淆的0和1 - 减少干扰线:从5条减少到3条,添加背景色优化 - 增强登录API日志:添加详细的调试日志 - 增强验证码生成和验证日志 - 优化异常处理和错误追踪 影响文件: - src/router/index.ts - src/api/request.ts - app/services/auth_service.py - app/api/v1/auth.py - app/schemas/user.py 测试状态: - 前端构建通过 - 后端语法检查通过 - 验证码显示效果优化完成 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
43
app/models/__init__.py
Normal file
43
app/models/__init__.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
数据模型模块初始化
|
||||
"""
|
||||
from app.models.user import User, Role, UserRole, Permission, RolePermission
|
||||
from app.models.device_type import DeviceType, DeviceTypeField
|
||||
from app.models.organization import Organization
|
||||
from app.models.brand_supplier import Brand, Supplier
|
||||
from app.models.asset import Asset, AssetStatusHistory
|
||||
from app.models.allocation import AssetAllocationOrder, AssetAllocationItem
|
||||
from app.models.maintenance import MaintenanceRecord
|
||||
from app.models.transfer import AssetTransferOrder, AssetTransferItem
|
||||
from app.models.recovery import AssetRecoveryOrder, AssetRecoveryItem
|
||||
from app.models.system_config import SystemConfig
|
||||
from app.models.operation_log import OperationLog
|
||||
from app.models.notification import Notification, NotificationTemplate
|
||||
from app.models.file_management import UploadedFile
|
||||
|
||||
__all__ = [
|
||||
"User",
|
||||
"Role",
|
||||
"UserRole",
|
||||
"Permission",
|
||||
"RolePermission",
|
||||
"DeviceType",
|
||||
"DeviceTypeField",
|
||||
"Organization",
|
||||
"Brand",
|
||||
"Supplier",
|
||||
"Asset",
|
||||
"AssetStatusHistory",
|
||||
"AssetAllocationOrder",
|
||||
"AssetAllocationItem",
|
||||
"MaintenanceRecord",
|
||||
"AssetTransferOrder",
|
||||
"AssetTransferItem",
|
||||
"AssetRecoveryOrder",
|
||||
"AssetRecoveryItem",
|
||||
"SystemConfig",
|
||||
"OperationLog",
|
||||
"Notification",
|
||||
"NotificationTemplate",
|
||||
"UploadedFile",
|
||||
]
|
||||
89
app/models/allocation.py
Normal file
89
app/models/allocation.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""
|
||||
资产分配相关数据模型
|
||||
"""
|
||||
from datetime import datetime, date
|
||||
from sqlalchemy import Column, BigInteger, String, Integer, Text, ForeignKey, DateTime, Date, Numeric, Index
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class AssetAllocationOrder(Base):
|
||||
"""资产分配单表"""
|
||||
|
||||
__tablename__ = "asset_allocation_orders"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
order_code = Column(String(50), unique=True, nullable=False, index=True, comment="分配单号")
|
||||
order_type = Column(String(20), nullable=False, index=True, comment="单据类型")
|
||||
title = Column(String(200), nullable=False, comment="标题")
|
||||
source_organization_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=True, comment="调出网点ID")
|
||||
target_organization_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=False, index=True, comment="调入网点ID")
|
||||
applicant_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, index=True, comment="申请人ID")
|
||||
approver_id = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="审批人ID")
|
||||
approval_status = Column(String(20), default="pending", nullable=False, index=True, comment="审批状态")
|
||||
approval_time = Column(DateTime, nullable=True, comment="审批时间")
|
||||
approval_remark = Column(Text, nullable=True, comment="审批备注")
|
||||
expect_execute_date = Column(Date, nullable=True, comment="预计执行日期")
|
||||
actual_execute_date = Column(Date, nullable=True, comment="实际执行日期")
|
||||
executor_id = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="执行人ID")
|
||||
execute_status = Column(String(20), default="pending", nullable=False, comment="执行状态")
|
||||
remark = Column(Text, nullable=True, comment="备注")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=False)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
source_organization = relationship("Organization", foreign_keys=[source_organization_id])
|
||||
target_organization = relationship("Organization", foreign_keys=[target_organization_id])
|
||||
applicant = relationship("User", foreign_keys=[applicant_id])
|
||||
approver = relationship("User", foreign_keys=[approver_id])
|
||||
executor = relationship("User", foreign_keys=[executor_id])
|
||||
items = relationship("AssetAllocationItem", back_populates="order", cascade="all, delete-orphan")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_allocation_orders_code", "order_code"),
|
||||
Index("idx_allocation_orders_target_org", "target_organization_id"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AssetAllocationOrder(id={self.id}, order_code={self.order_code}, order_type={self.order_type})>"
|
||||
|
||||
|
||||
class AssetAllocationItem(Base):
|
||||
"""资产分配单明细表"""
|
||||
|
||||
__tablename__ = "asset_allocation_items"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
order_id = Column(BigInteger, ForeignKey("asset_allocation_orders.id", ondelete="CASCADE"), nullable=False, comment="分配单ID")
|
||||
asset_id = Column(BigInteger, ForeignKey("assets.id"), nullable=False, comment="资产ID")
|
||||
asset_code = Column(String(50), nullable=False, comment="资产编码")
|
||||
asset_name = Column(String(200), nullable=False, comment="资产名称")
|
||||
from_organization_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=True, comment="原网点ID")
|
||||
to_organization_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=True, comment="目标网点ID")
|
||||
from_status = Column(String(20), nullable=True, comment="原状态")
|
||||
to_status = Column(String(20), nullable=True, comment="目标状态")
|
||||
execute_status = Column(String(20), default="pending", nullable=False, index=True, comment="执行状态")
|
||||
execute_time = Column(DateTime, nullable=True, comment="执行时间")
|
||||
failure_reason = Column(Text, nullable=True, comment="失败原因")
|
||||
remark = Column(Text, nullable=True, comment="备注")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# 关系
|
||||
order = relationship("AssetAllocationOrder", back_populates="items")
|
||||
asset = relationship("Asset")
|
||||
from_organization = relationship("Organization", foreign_keys=[from_organization_id])
|
||||
to_organization = relationship("Organization", foreign_keys=[to_organization_id])
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_allocation_items_order", "order_id"),
|
||||
Index("idx_allocation_items_asset", "asset_id"),
|
||||
Index("idx_allocation_items_status", "execute_status"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AssetAllocationItem(id={self.id}, order_id={self.order_id}, asset_code={self.asset_code})>"
|
||||
84
app/models/asset.py
Normal file
84
app/models/asset.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
资产相关数据模型
|
||||
"""
|
||||
from datetime import datetime, date
|
||||
from sqlalchemy import Column, BigInteger, String, Integer, Text, ForeignKey, DateTime, Date, Numeric, Index
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Asset(Base):
|
||||
"""资产表"""
|
||||
|
||||
__tablename__ = "assets"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
asset_code = Column(String(50), unique=True, nullable=False, index=True, comment="资产编码")
|
||||
asset_name = Column(String(200), nullable=False, comment="资产名称")
|
||||
device_type_id = Column(BigInteger, ForeignKey("device_types.id"), nullable=False, comment="设备类型ID")
|
||||
brand_id = Column(BigInteger, ForeignKey("brands.id"), nullable=True, comment="品牌ID")
|
||||
model = Column(String(200), nullable=True, comment="规格型号")
|
||||
serial_number = Column(String(200), nullable=True, index=True, comment="序列号(SN)")
|
||||
supplier_id = Column(BigInteger, ForeignKey("suppliers.id"), nullable=True, comment="供应商ID")
|
||||
purchase_date = Column(Date, nullable=True, index=True, comment="采购日期")
|
||||
purchase_price = Column(Numeric(18, 2), nullable=True, comment="采购价格")
|
||||
warranty_period = Column(Integer, nullable=True, comment="保修期(月)")
|
||||
warranty_expire_date = Column(Date, nullable=True, comment="保修到期日期")
|
||||
organization_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=False, comment="所属网点ID")
|
||||
location = Column(String(500), nullable=True, comment="存放位置")
|
||||
status = Column(String(20), default="pending", nullable=False, index=True, comment="状态")
|
||||
dynamic_attributes = Column(JSONB, default={}, comment="动态字段值")
|
||||
qr_code_url = Column(String(500), nullable=True, comment="二维码图片URL")
|
||||
remark = Column(Text, nullable=True, comment="备注")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
deleted_at = Column(DateTime, nullable=True)
|
||||
deleted_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
device_type = relationship("DeviceType", back_populates="assets")
|
||||
brand = relationship("Brand", back_populates="assets")
|
||||
supplier = relationship("Supplier", back_populates="assets")
|
||||
organization = relationship("Organization")
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
updated_user = relationship("User", foreign_keys=[updated_by])
|
||||
deleted_user = relationship("User", foreign_keys=[deleted_by])
|
||||
status_history = relationship("AssetStatusHistory", back_populates="asset", cascade="all, delete-orphan")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Asset(id={self.id}, asset_code={self.asset_code}, asset_name={self.asset_name})>"
|
||||
|
||||
|
||||
class AssetStatusHistory(Base):
|
||||
"""资产状态历史表"""
|
||||
|
||||
__tablename__ = "asset_status_history"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
asset_id = Column(BigInteger, ForeignKey("assets.id", ondelete="CASCADE"), nullable=False, comment="资产ID")
|
||||
old_status = Column(String(20), nullable=True, comment="原状态")
|
||||
new_status = Column(String(20), nullable=False, index=True, comment="新状态")
|
||||
operation_type = Column(String(50), nullable=False, comment="操作类型")
|
||||
operator_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, comment="操作人ID")
|
||||
operator_name = Column(String(100), nullable=True, comment="操作人姓名(冗余)")
|
||||
organization_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=True, comment="相关网点ID")
|
||||
remark = Column(Text, nullable=True, comment="备注")
|
||||
extra_data = Column(JSONB, nullable=True, comment="额外数据")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
|
||||
# 关系
|
||||
asset = relationship("Asset", back_populates="status_history")
|
||||
operator = relationship("User", foreign_keys=[operator_id])
|
||||
organization = relationship("Organization")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_asset_status_history_asset", "asset_id"),
|
||||
Index("idx_asset_status_history_time", "created_at"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AssetStatusHistory(id={self.id}, asset_id={self.asset_id}, old_status={self.old_status}, new_status={self.new_status})>"
|
||||
70
app/models/brand_supplier.py
Normal file
70
app/models/brand_supplier.py
Normal file
@@ -0,0 +1,70 @@
|
||||
"""
|
||||
品牌和供应商数据模型
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, BigInteger, String, Integer, Text, ForeignKey, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Brand(Base):
|
||||
"""品牌表"""
|
||||
|
||||
__tablename__ = "brands"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
brand_code = Column(String(50), unique=True, nullable=False, index=True, comment="品牌代码")
|
||||
brand_name = Column(String(200), nullable=False, comment="品牌名称")
|
||||
logo_url = Column(String(500), nullable=True, comment="Logo URL")
|
||||
website = Column(String(500), nullable=True, comment="官网地址")
|
||||
status = Column(String(20), default="active", nullable=False, comment="状态: active, inactive")
|
||||
sort_order = Column(Integer, default=0, nullable=False, comment="排序")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
deleted_at = Column(DateTime, nullable=True)
|
||||
deleted_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
updated_user = relationship("User", foreign_keys=[updated_by])
|
||||
deleted_user = relationship("User", foreign_keys=[deleted_by])
|
||||
assets = relationship("Asset", back_populates="brand")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Brand(id={self.id}, brand_code={self.brand_code}, brand_name={self.brand_name})>"
|
||||
|
||||
|
||||
class Supplier(Base):
|
||||
"""供应商表"""
|
||||
|
||||
__tablename__ = "suppliers"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
supplier_code = Column(String(50), unique=True, nullable=False, index=True, comment="供应商代码")
|
||||
supplier_name = Column(String(200), nullable=False, comment="供应商名称")
|
||||
contact_person = Column(String(100), nullable=True, comment="联系人")
|
||||
contact_phone = Column(String(20), nullable=True, comment="联系电话")
|
||||
email = Column(String(255), nullable=True, comment="邮箱")
|
||||
address = Column(String(500), nullable=True, comment="地址")
|
||||
credit_code = Column(String(50), nullable=True, comment="统一社会信用代码")
|
||||
bank_name = Column(String(200), nullable=True, comment="开户银行")
|
||||
bank_account = Column(String(100), nullable=True, comment="银行账号")
|
||||
status = Column(String(20), default="active", nullable=False, comment="状态: active, inactive")
|
||||
remark = Column(Text, nullable=True, comment="备注")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
deleted_at = Column(DateTime, nullable=True)
|
||||
deleted_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
updated_user = relationship("User", foreign_keys=[updated_by])
|
||||
deleted_user = relationship("User", foreign_keys=[deleted_by])
|
||||
assets = relationship("Asset", back_populates="supplier")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Supplier(id={self.id}, supplier_code={self.supplier_code}, supplier_name={self.supplier_name})>"
|
||||
80
app/models/device_type.py
Normal file
80
app/models/device_type.py
Normal file
@@ -0,0 +1,80 @@
|
||||
"""
|
||||
设备类型相关数据模型
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, BigInteger, String, Integer, Text, ForeignKey, DateTime, Index
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class DeviceType(Base):
|
||||
"""设备类型表"""
|
||||
|
||||
__tablename__ = "device_types"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
type_code = Column(String(50), unique=True, nullable=False, index=True, comment="设备类型代码")
|
||||
type_name = Column(String(200), nullable=False, comment="设备类型名称")
|
||||
category = Column(String(50), nullable=True, comment="设备分类: IT设备, 办公设备, 生产设备等")
|
||||
description = Column(Text, nullable=True, comment="描述")
|
||||
icon = Column(String(100), nullable=True, comment="图标名称")
|
||||
status = Column(String(20), default="active", nullable=False, comment="状态: active, inactive")
|
||||
sort_order = Column(Integer, default=0, nullable=False, comment="排序")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
deleted_at = Column(DateTime, nullable=True)
|
||||
deleted_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
updated_user = relationship("User", foreign_keys=[updated_by])
|
||||
deleted_user = relationship("User", foreign_keys=[deleted_by])
|
||||
fields = relationship("DeviceTypeField", back_populates="device_type", cascade="all, delete-orphan")
|
||||
assets = relationship("Asset", back_populates="device_type")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<DeviceType(id={self.id}, type_code={self.type_code}, type_name={self.type_name})>"
|
||||
|
||||
|
||||
class DeviceTypeField(Base):
|
||||
"""设备类型字段定义表(动态字段)"""
|
||||
|
||||
__tablename__ = "device_type_fields"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
device_type_id = Column(BigInteger, ForeignKey("device_types.id", ondelete="CASCADE"), nullable=False)
|
||||
field_code = Column(String(50), nullable=False, comment="字段代码")
|
||||
field_name = Column(String(100), nullable=False, comment="字段名称")
|
||||
field_type = Column(String(20), nullable=False, comment="字段类型: text, number, date, select, multiselect, boolean, textarea")
|
||||
is_required = Column(BigInteger, default=False, nullable=False, comment="是否必填")
|
||||
default_value = Column(Text, nullable=True, comment="默认值")
|
||||
options = Column(JSONB, nullable=True, comment="select类型的选项: [{'label': '选项1', 'value': '1'}]")
|
||||
validation_rules = Column(JSONB, nullable=True, comment="验证规则: {'min': 0, 'max': 100, 'pattern': '^A-Z'}")
|
||||
placeholder = Column(String(200), nullable=True, comment="占位符")
|
||||
help_text = Column(Text, nullable=True, comment="帮助文本")
|
||||
sort_order = Column(Integer, default=0, nullable=False, comment="排序")
|
||||
status = Column(String(20), default="active", nullable=False, comment="状态: active, inactive")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
deleted_at = Column(DateTime, nullable=True)
|
||||
deleted_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
device_type = relationship("DeviceType", back_populates="fields")
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
updated_user = relationship("User", foreign_keys=[updated_by])
|
||||
deleted_user = relationship("User", foreign_keys=[deleted_by])
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_device_type_fields_type", "device_type_id"),
|
||||
Index("idx_device_type_fields_code", "field_code"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<DeviceTypeField(id={self.id}, field_code={self.field_code}, field_name={self.field_name})>"
|
||||
46
app/models/file_management.py
Normal file
46
app/models/file_management.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
文件管理数据模型
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, BigInteger, String, DateTime, Text, Index, Boolean, ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class UploadedFile(Base):
|
||||
"""上传文件表"""
|
||||
|
||||
__tablename__ = "uploaded_files"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
file_name = Column(String(255), nullable=False, comment="存储文件名(UUID)")
|
||||
original_name = Column(String(255), nullable=False, index=True, comment="原始文件名")
|
||||
file_path = Column(String(500), nullable=False, comment="文件存储路径")
|
||||
file_size = Column(BigInteger, nullable=False, comment="文件大小(字节)")
|
||||
file_type = Column(String(100), nullable=False, index=True, comment="文件类型(MIME)")
|
||||
file_ext = Column(String(50), nullable=False, comment="文件扩展名")
|
||||
uploader_id = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="上传人ID")
|
||||
upload_time = Column(DateTime, default=datetime.utcnow, nullable=False, index=True, comment="上传时间")
|
||||
thumbnail_path = Column(String(500), nullable=True, comment="缩略图路径")
|
||||
share_code = Column(String(100), nullable=True, unique=True, index=True, comment="分享码")
|
||||
share_expire_time = Column(DateTime, nullable=True, index=True, comment="分享过期时间")
|
||||
download_count = Column(BigInteger, default=0, comment="下载次数")
|
||||
is_deleted = Column(Boolean, default=False, nullable=False, comment="是否删除")
|
||||
deleted_at = Column(DateTime, nullable=True, comment="删除时间")
|
||||
deleted_by = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="删除人ID")
|
||||
remark = Column(Text, nullable=True, comment="备注")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# 关系
|
||||
uploader = relationship("User", foreign_keys=[uploader_id])
|
||||
deleter = relationship("User", foreign_keys=[deleted_by])
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_uploaded_files_uploader", "uploader_id"),
|
||||
Index("idx_uploaded_files_deleted", "is_deleted"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<UploadedFile(id={self.id}, original_name={self.original_name}, file_type={self.file_type})>"
|
||||
57
app/models/maintenance.py
Normal file
57
app/models/maintenance.py
Normal file
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
维修管理相关数据模型
|
||||
"""
|
||||
from datetime import datetime, date
|
||||
from sqlalchemy import Column, BigInteger, String, Integer, Text, ForeignKey, DateTime, Date, Numeric, Index
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class MaintenanceRecord(Base):
|
||||
"""维修记录表"""
|
||||
|
||||
__tablename__ = "maintenance_records"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
record_code = Column(String(50), unique=True, nullable=False, index=True, comment="维修单号")
|
||||
asset_id = Column(BigInteger, ForeignKey("assets.id"), nullable=False, index=True, comment="资产ID")
|
||||
asset_code = Column(String(50), nullable=False, comment="资产编码")
|
||||
fault_description = Column(Text, nullable=False, comment="故障描述")
|
||||
fault_type = Column(String(50), nullable=True, comment="故障类型")
|
||||
report_user_id = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="报修人ID")
|
||||
report_time = Column(DateTime, default=datetime.utcnow, nullable=False, index=True, comment="报修时间")
|
||||
priority = Column(String(20), default="normal", nullable=False, comment="优先级")
|
||||
maintenance_type = Column(String(20), nullable=True, comment="维修类型")
|
||||
vendor_id = Column(BigInteger, ForeignKey("suppliers.id"), nullable=True, comment="维修供应商ID")
|
||||
maintenance_cost = Column(Numeric(18, 2), nullable=True, comment="维修费用")
|
||||
start_time = Column(DateTime, nullable=True, comment="开始维修时间")
|
||||
complete_time = Column(DateTime, nullable=True, comment="完成维修时间")
|
||||
maintenance_user_id = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="维修人员ID")
|
||||
maintenance_result = Column(Text, nullable=True, comment="维修结果描述")
|
||||
replaced_parts = Column(Text, nullable=True, comment="更换的配件")
|
||||
status = Column(String(20), default="pending", nullable=False, index=True, comment="状态")
|
||||
images = Column(Text, nullable=True, comment="维修图片URL(多个逗号分隔)")
|
||||
remark = Column(Text, nullable=True, comment="备注")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
asset = relationship("Asset")
|
||||
vendor = relationship("Supplier")
|
||||
report_user = relationship("User", foreign_keys=[report_user_id])
|
||||
maintenance_user = relationship("User", foreign_keys=[maintenance_user_id])
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
updated_user = relationship("User", foreign_keys=[updated_by])
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_maintenance_records_code", "record_code"),
|
||||
Index("idx_maintenance_records_asset", "asset_id"),
|
||||
Index("idx_maintenance_records_status", "status"),
|
||||
Index("idx_maintenance_records_time", "report_time"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<MaintenanceRecord(id={self.id}, record_code={self.record_code}, asset_code={self.asset_code})>"
|
||||
71
app/models/notification.py
Normal file
71
app/models/notification.py
Normal file
@@ -0,0 +1,71 @@
|
||||
"""
|
||||
消息通知数据模型
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, BigInteger, String, Text, Integer, DateTime, Boolean, Index, ForeignKey
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Notification(Base):
|
||||
"""消息通知表"""
|
||||
|
||||
__tablename__ = "notifications"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
recipient_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, index=True, comment="接收人ID")
|
||||
recipient_name = Column(String(100), nullable=False, comment="接收人姓名(冗余)")
|
||||
title = Column(String(200), nullable=False, comment="通知标题")
|
||||
content = Column(Text, nullable=False, comment="通知内容")
|
||||
notification_type = Column(String(20), nullable=False, index=True, comment="通知类型: system/approval/maintenance/allocation等")
|
||||
priority = Column(String(20), default="normal", nullable=False, comment="优先级: low/normal/high/urgent")
|
||||
is_read = Column(Boolean, default=False, nullable=False, index=True, comment="是否已读")
|
||||
read_at = Column(DateTime, nullable=True, comment="已读时间")
|
||||
related_entity_type = Column(String(50), nullable=True, comment="关联实体类型")
|
||||
related_entity_id = Column(BigInteger, nullable=True, comment="关联实体ID")
|
||||
action_url = Column(String(500), nullable=True, comment="操作链接")
|
||||
extra_data = Column(JSONB, nullable=True, comment="额外数据")
|
||||
sent_via_email = Column(Boolean, default=False, nullable=False, comment="是否已发送邮件")
|
||||
sent_via_sms = Column(Boolean, default=False, nullable=False, comment="是否已发送短信")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True, comment="创建时间")
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False, comment="更新时间")
|
||||
expire_at = Column(DateTime, nullable=True, comment="过期时间")
|
||||
|
||||
# 关系
|
||||
recipient = relationship("User", foreign_keys=[recipient_id])
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_notification_recipient", "recipient_id"),
|
||||
Index("idx_notification_read", "is_read"),
|
||||
Index("idx_notification_type", "notification_type"),
|
||||
Index("idx_notification_time", "created_at"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Notification(id={self.id}, recipient={self.recipient_name}, title={self.title})>"
|
||||
|
||||
|
||||
class NotificationTemplate(Base):
|
||||
"""消息通知模板表"""
|
||||
|
||||
__tablename__ = "notification_templates"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
template_code = Column(String(50), unique=True, nullable=False, comment="模板编码")
|
||||
template_name = Column(String(200), nullable=False, comment="模板名称")
|
||||
notification_type = Column(String(20), nullable=False, comment="通知类型")
|
||||
title_template = Column(String(200), nullable=False, comment="标题模板")
|
||||
content_template = Column(Text, nullable=False, comment="内容模板")
|
||||
variables = Column(JSONB, nullable=True, comment="变量说明")
|
||||
priority = Column(String(20), default="normal", nullable=False, comment="默认优先级")
|
||||
send_email = Column(Boolean, default=False, nullable=False, comment="是否发送邮件")
|
||||
send_sms = Column(Boolean, default=False, nullable=False, comment="是否发送短信")
|
||||
is_active = Column(Boolean, default=True, nullable=False, comment="是否启用")
|
||||
description = Column(Text, nullable=True, comment="模板描述")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<NotificationTemplate(id={self.id}, code={self.template_code}, name={self.template_name})>"
|
||||
40
app/models/operation_log.py
Normal file
40
app/models/operation_log.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
操作日志数据模型
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, BigInteger, String, Text, Integer, DateTime, Index
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class OperationLog(Base):
|
||||
"""操作日志表"""
|
||||
|
||||
__tablename__ = "operation_logs"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
operator_id = Column(BigInteger, nullable=False, index=True, comment="操作人ID")
|
||||
operator_name = Column(String(100), nullable=False, comment="操作人姓名")
|
||||
operator_ip = Column(String(50), nullable=True, comment="操作人IP")
|
||||
module = Column(String(50), nullable=False, index=True, comment="模块名称")
|
||||
operation_type = Column(String(50), nullable=False, index=True, comment="操作类型")
|
||||
method = Column(String(10), nullable=False, comment="请求方法(GET/POST/PUT/DELETE等)")
|
||||
url = Column(String(500), nullable=False, comment="请求URL")
|
||||
params = Column(Text, nullable=True, comment="请求参数")
|
||||
result = Column(String(20), default="success", nullable=False, comment="操作结果: success/failed")
|
||||
error_msg = Column(Text, nullable=True, comment="错误信息")
|
||||
duration = Column(Integer, nullable=True, comment="执行时长(毫秒)")
|
||||
user_agent = Column(String(500), nullable=True, comment="用户代理")
|
||||
extra_data = Column(JSONB, nullable=True, comment="额外数据")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_operation_log_operator", "operator_id"),
|
||||
Index("idx_operation_log_module", "module"),
|
||||
Index("idx_operation_log_time", "created_at"),
|
||||
Index("idx_operation_log_result", "result"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<OperationLog(id={self.id}, operator={self.operator_name}, module={self.module}, operation={self.operation_type})>"
|
||||
42
app/models/organization.py
Normal file
42
app/models/organization.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
机构网点相关数据模型
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, BigInteger, String, Integer, Text, ForeignKey, DateTime, Index
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class Organization(Base):
|
||||
"""机构/网点表"""
|
||||
|
||||
__tablename__ = "organizations"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
org_code = Column(String(50), unique=True, nullable=False, index=True, comment="机构代码")
|
||||
org_name = Column(String(200), nullable=False, comment="机构名称")
|
||||
org_type = Column(String(20), nullable=False, comment="机构类型: province, city, outlet")
|
||||
parent_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=True, comment="父机构ID")
|
||||
tree_path = Column(String(1000), nullable=True, comment="树形路径: /1/2/3/")
|
||||
tree_level = Column(Integer, default=0, nullable=False, comment="层级")
|
||||
address = Column(String(500), nullable=True, comment="地址")
|
||||
contact_person = Column(String(100), nullable=True, comment="联系人")
|
||||
contact_phone = Column(String(20), nullable=True, comment="联系电话")
|
||||
status = Column(String(20), default="active", nullable=False, comment="状态: active, inactive")
|
||||
sort_order = Column(Integer, default=0, nullable=False, comment="排序")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
deleted_at = Column(DateTime, nullable=True)
|
||||
deleted_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
parent = relationship("Organization", remote_side=[id], foreign_keys=[parent_id])
|
||||
children = relationship("Organization", foreign_keys=[parent_id], backref="children_ref")
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
updated_user = relationship("User", foreign_keys=[updated_by])
|
||||
deleted_user = relationship("User", foreign_keys=[deleted_by])
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Organization(id={self.id}, org_code={self.org_code}, org_name={self.org_name})>"
|
||||
73
app/models/recovery.py
Normal file
73
app/models/recovery.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""
|
||||
资产回收相关数据模型
|
||||
"""
|
||||
from datetime import datetime, date
|
||||
from sqlalchemy import Column, BigInteger, String, Integer, Text, ForeignKey, DateTime, Date, Index
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class AssetRecoveryOrder(Base):
|
||||
"""资产回收单表"""
|
||||
|
||||
__tablename__ = "asset_recovery_orders"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
order_code = Column(String(50), unique=True, nullable=False, index=True, comment="回收单号")
|
||||
recovery_type = Column(String(20), nullable=False, index=True, comment="回收类型(user=使用人回收/org=机构回收/scrap=报废回收)")
|
||||
title = Column(String(200), nullable=False, comment="标题")
|
||||
asset_count = Column(Integer, default=0, nullable=False, comment="资产数量")
|
||||
apply_user_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, index=True, comment="申请人ID")
|
||||
apply_time = Column(DateTime, nullable=False, comment="申请时间")
|
||||
approval_status = Column(String(20), default="pending", nullable=False, index=True, comment="审批状态")
|
||||
approval_user_id = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="审批人ID")
|
||||
approval_time = Column(DateTime, nullable=True, comment="审批时间")
|
||||
approval_remark = Column(Text, nullable=True, comment="审批备注")
|
||||
execute_status = Column(String(20), default="pending", nullable=False, index=True, comment="执行状态")
|
||||
execute_user_id = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="执行人ID")
|
||||
execute_time = Column(DateTime, nullable=True, comment="执行时间")
|
||||
remark = Column(Text, nullable=True, comment="备注")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# 关系
|
||||
apply_user = relationship("User", foreign_keys=[apply_user_id])
|
||||
approval_user = relationship("User", foreign_keys=[approval_user_id])
|
||||
execute_user = relationship("User", foreign_keys=[execute_user_id])
|
||||
items = relationship("AssetRecoveryItem", back_populates="order", cascade="all, delete-orphan")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_recovery_orders_code", "order_code"),
|
||||
Index("idx_recovery_orders_type", "recovery_type"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AssetRecoveryOrder(id={self.id}, order_code={self.order_code}, recovery_type={self.recovery_type})>"
|
||||
|
||||
|
||||
class AssetRecoveryItem(Base):
|
||||
"""资产回收单明细表"""
|
||||
|
||||
__tablename__ = "asset_recovery_items"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
order_id = Column(BigInteger, ForeignKey("asset_recovery_orders.id", ondelete="CASCADE"), nullable=False, comment="回收单ID")
|
||||
asset_id = Column(BigInteger, ForeignKey("assets.id"), nullable=False, comment="资产ID")
|
||||
asset_code = Column(String(50), nullable=False, comment="资产编码")
|
||||
recovery_status = Column(String(20), default="pending", nullable=False, index=True, comment="回收状态")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
|
||||
# 关系
|
||||
order = relationship("AssetRecoveryOrder", back_populates="items")
|
||||
asset = relationship("Asset")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_recovery_items_order", "order_id"),
|
||||
Index("idx_recovery_items_asset", "asset_id"),
|
||||
Index("idx_recovery_items_status", "recovery_status"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AssetRecoveryItem(id={self.id}, order_id={self.order_id}, asset_code={self.asset_code})>"
|
||||
40
app/models/system_config.py
Normal file
40
app/models/system_config.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
系统配置数据模型
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, BigInteger, String, Text, Integer, DateTime, Boolean, Index
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class SystemConfig(Base):
|
||||
"""系统配置表"""
|
||||
|
||||
__tablename__ = "system_configs"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
config_key = Column(String(100), unique=True, nullable=False, index=True, comment="配置键")
|
||||
config_name = Column(String(200), nullable=False, comment="配置名称")
|
||||
config_value = Column(Text, nullable=True, comment="配置值")
|
||||
value_type = Column(String(20), default="string", nullable=False, comment="值类型: string/number/boolean/json")
|
||||
category = Column(String(50), nullable=False, index=True, comment="配置分类")
|
||||
description = Column(Text, nullable=True, comment="配置描述")
|
||||
is_system = Column(Boolean, default=False, nullable=False, comment="是否系统配置")
|
||||
is_encrypted = Column(Boolean, default=False, nullable=False, comment="是否加密存储")
|
||||
validation_rule = Column(Text, nullable=True, comment="验证规则(JSON)")
|
||||
options = Column(JSONB, nullable=True, comment="可选值配置")
|
||||
default_value = Column(Text, nullable=True, comment="默认值")
|
||||
sort_order = Column(Integer, default=0, nullable=False, comment="排序序号")
|
||||
is_active = Column(Boolean, default=True, nullable=False, comment="是否启用")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
updated_by = Column(BigInteger, nullable=True, comment="更新人ID")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_system_config_category", "category"),
|
||||
Index("idx_system_config_active", "is_active"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<SystemConfig(id={self.id}, config_key={self.config_key}, config_name={self.config_name})>"
|
||||
82
app/models/transfer.py
Normal file
82
app/models/transfer.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
资产调拨相关数据模型
|
||||
"""
|
||||
from datetime import datetime, date
|
||||
from sqlalchemy import Column, BigInteger, String, Integer, Text, ForeignKey, DateTime, Date, Index
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class AssetTransferOrder(Base):
|
||||
"""资产调拨单表"""
|
||||
|
||||
__tablename__ = "asset_transfer_orders"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
order_code = Column(String(50), unique=True, nullable=False, index=True, comment="调拨单号")
|
||||
source_org_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=False, comment="调出网点ID")
|
||||
target_org_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=False, index=True, comment="调入网点ID")
|
||||
transfer_type = Column(String(20), nullable=False, index=True, comment="调拨类型(internal/external)")
|
||||
title = Column(String(200), nullable=False, comment="标题")
|
||||
asset_count = Column(Integer, default=0, nullable=False, comment="资产数量")
|
||||
apply_user_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, index=True, comment="申请人ID")
|
||||
apply_time = Column(DateTime, nullable=False, comment="申请时间")
|
||||
approval_status = Column(String(20), default="pending", nullable=False, index=True, comment="审批状态")
|
||||
approval_user_id = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="审批人ID")
|
||||
approval_time = Column(DateTime, nullable=True, comment="审批时间")
|
||||
approval_remark = Column(Text, nullable=True, comment="审批备注")
|
||||
execute_status = Column(String(20), default="pending", nullable=False, index=True, comment="执行状态")
|
||||
execute_user_id = Column(BigInteger, ForeignKey("users.id"), nullable=True, comment="执行人ID")
|
||||
execute_time = Column(DateTime, nullable=True, comment="执行时间")
|
||||
remark = Column(Text, nullable=True, comment="备注")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# 关系
|
||||
source_organization = relationship("Organization", foreign_keys=[source_org_id])
|
||||
target_organization = relationship("Organization", foreign_keys=[target_org_id])
|
||||
apply_user = relationship("User", foreign_keys=[apply_user_id])
|
||||
approval_user = relationship("User", foreign_keys=[approval_user_id])
|
||||
execute_user = relationship("User", foreign_keys=[execute_user_id])
|
||||
items = relationship("AssetTransferItem", back_populates="order", cascade="all, delete-orphan")
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_transfer_orders_code", "order_code"),
|
||||
Index("idx_transfer_orders_source_org", "source_org_id"),
|
||||
Index("idx_transfer_orders_target_org", "target_org_id"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AssetTransferOrder(id={self.id}, order_code={self.order_code}, transfer_type={self.transfer_type})>"
|
||||
|
||||
|
||||
class AssetTransferItem(Base):
|
||||
"""资产调拨单明细表"""
|
||||
|
||||
__tablename__ = "asset_transfer_items"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
order_id = Column(BigInteger, ForeignKey("asset_transfer_orders.id", ondelete="CASCADE"), nullable=False, comment="调拨单ID")
|
||||
asset_id = Column(BigInteger, ForeignKey("assets.id"), nullable=False, comment="资产ID")
|
||||
asset_code = Column(String(50), nullable=False, comment="资产编码")
|
||||
source_organization_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=False, comment="调出网点ID")
|
||||
target_organization_id = Column(BigInteger, ForeignKey("organizations.id"), nullable=False, comment="调入网点ID")
|
||||
transfer_status = Column(String(20), default="pending", nullable=False, index=True, comment="调拨状态")
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
|
||||
# 关系
|
||||
order = relationship("AssetTransferOrder", back_populates="items")
|
||||
asset = relationship("Asset")
|
||||
source_organization = relationship("Organization", foreign_keys=[source_organization_id])
|
||||
target_organization = relationship("Organization", foreign_keys=[target_organization_id])
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_transfer_items_order", "order_id"),
|
||||
Index("idx_transfer_items_asset", "asset_id"),
|
||||
Index("idx_transfer_items_status", "transfer_status"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<AssetTransferItem(id={self.id}, order_id={self.order_id}, asset_code={self.asset_code})>"
|
||||
131
app/models/user.py
Normal file
131
app/models/user.py
Normal file
@@ -0,0 +1,131 @@
|
||||
"""
|
||||
用户相关数据模型
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, BigInteger, String, Boolean, DateTime, Integer, ForeignKey, Text, Index
|
||||
from sqlalchemy.orm import relationship
|
||||
from app.db.base import Base
|
||||
|
||||
|
||||
class User(Base):
|
||||
"""用户表"""
|
||||
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
username = Column(String(50), unique=True, nullable=False, index=True)
|
||||
password_hash = Column(String(255), nullable=False, comment="bcrypt哈希")
|
||||
real_name = Column(String(100), nullable=False)
|
||||
email = Column(String(255), unique=True, nullable=True)
|
||||
phone = Column(String(20), nullable=True)
|
||||
avatar_url = Column(String(500), nullable=True)
|
||||
status = Column(String(20), default="active", nullable=False, comment="active, disabled, locked")
|
||||
is_admin = Column(Boolean, default=False, nullable=False)
|
||||
last_login_at = Column(DateTime, nullable=True)
|
||||
login_fail_count = Column(Integer, default=0, nullable=False)
|
||||
locked_until = Column(DateTime, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
deleted_at = Column(DateTime, nullable=True)
|
||||
deleted_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
created_by_user = relationship("User", remote_side=[id], foreign_keys=[created_by])
|
||||
updated_by_user = relationship("User", remote_side=[id], foreign_keys=[updated_by])
|
||||
deleted_by_user = relationship("User", remote_side=[id], foreign_keys=[deleted_by])
|
||||
|
||||
def __repr__(self):
|
||||
return f"<User(id={self.id}, username={self.username}, real_name={self.real_name})>"
|
||||
|
||||
|
||||
class Role(Base):
|
||||
"""角色表"""
|
||||
|
||||
__tablename__ = "roles"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
role_name = Column(String(50), unique=True, nullable=False)
|
||||
role_code = Column(String(50), unique=True, nullable=False)
|
||||
description = Column(Text, nullable=True)
|
||||
status = Column(String(20), default="active", nullable=False, comment="active, disabled")
|
||||
sort_order = Column(Integer, default=0, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
deleted_at = Column(DateTime, nullable=True)
|
||||
deleted_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
updated_user = relationship("User", foreign_keys=[updated_by])
|
||||
deleted_user = relationship("User", foreign_keys=[deleted_by])
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Role(id={self.id}, role_code={self.role_code}, role_name={self.role_name})>"
|
||||
|
||||
|
||||
class UserRole(Base):
|
||||
"""用户角色关联表"""
|
||||
|
||||
__tablename__ = "user_roles"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
user_id = Column(BigInteger, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
|
||||
role_id = Column(BigInteger, ForeignKey("roles.id", ondelete="CASCADE"), nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
user = relationship("User", foreign_keys=[user_id])
|
||||
role = relationship("Role", foreign_keys=[role_id])
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_user_roles_user", "user_id"),
|
||||
Index("idx_user_roles_role", "role_id"),
|
||||
)
|
||||
|
||||
|
||||
class Permission(Base):
|
||||
"""权限表"""
|
||||
|
||||
__tablename__ = "permissions"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
permission_name = Column(String(100), unique=True, nullable=False)
|
||||
permission_code = Column(String(100), unique=True, nullable=False)
|
||||
module = Column(String(50), nullable=False, comment="模块: asset, device_type, org, user, system")
|
||||
resource = Column(String(50), nullable=True, comment="资源: asset, device_type, organization")
|
||||
action = Column(String(50), nullable=True, comment="操作: create, read, update, delete, export, import")
|
||||
description = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Permission(id={self.id}, permission_code={self.permission_code}, permission_name={self.permission_name})>"
|
||||
|
||||
|
||||
class RolePermission(Base):
|
||||
"""角色权限关联表"""
|
||||
|
||||
__tablename__ = "role_permissions"
|
||||
|
||||
id = Column(BigInteger, primary_key=True, index=True)
|
||||
role_id = Column(BigInteger, ForeignKey("roles.id", ondelete="CASCADE"), nullable=False)
|
||||
permission_id = Column(BigInteger, ForeignKey("permissions.id", ondelete="CASCADE"), nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
created_by = Column(BigInteger, ForeignKey("users.id"), nullable=True)
|
||||
|
||||
# 关系
|
||||
role = relationship("Role", foreign_keys=[role_id])
|
||||
permission = relationship("Permission", foreign_keys=[permission_id])
|
||||
created_user = relationship("User", foreign_keys=[created_by])
|
||||
|
||||
# 索引
|
||||
__table_args__ = (
|
||||
Index("idx_role_permissions_role", "role_id"),
|
||||
Index("idx_role_permissions_permission", "permission_id"),
|
||||
)
|
||||
Reference in New Issue
Block a user