6d70520e79
- 新增后端模块:Alert、APIAsset、Compliance、Lineage、Masking、Risk、SchemaChange、Unstructured、Watermark - 新增前端模块页面与API接口 - 新增Alembic迁移脚本(002-014)覆盖全量业务表 - 新增测试数据生成脚本与集成测试脚本 - 修复metadata模型JSON类型导入缺失导致启动失败的问题 - 修复前端Alert/APIAsset页面request模块路径错误 - 更新docker-compose与开发计划文档
121 lines
4.9 KiB
Python
121 lines
4.9 KiB
Python
from datetime import datetime
|
|
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, Float, Enum as SAEnum
|
|
from sqlalchemy.orm import relationship
|
|
import enum
|
|
|
|
from app.core.database import Base
|
|
|
|
|
|
class ProjectStatus(str, enum.Enum):
|
|
CREATED = "created"
|
|
SCANNING = "scanning"
|
|
ASSIGNING = "assigning"
|
|
LABELING = "labeling"
|
|
REVIEWING = "reviewing"
|
|
ACCEPTING = "accepting"
|
|
PUBLISHED = "published"
|
|
|
|
|
|
class TaskStatus(str, enum.Enum):
|
|
PENDING = "pending"
|
|
IN_PROGRESS = "in_progress"
|
|
COMPLETED = "completed"
|
|
REJECTED = "rejected"
|
|
|
|
|
|
class ResultStatus(str, enum.Enum):
|
|
AUTO = "auto"
|
|
MANUAL = "manual"
|
|
REVIEWED = "reviewed"
|
|
PUBLISHED = "published"
|
|
CONFLICT = "conflict"
|
|
|
|
|
|
class ClassificationProject(Base):
|
|
__tablename__ = "classification_project"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String(200), nullable=False)
|
|
template_id = Column(Integer, ForeignKey("classification_template.id"))
|
|
description = Column(Text)
|
|
status = Column(String(20), default=ProjectStatus.CREATED.value)
|
|
target_source_ids = Column(Text) # comma separated source ids
|
|
target_database_ids = Column(Text)
|
|
target_table_ids = Column(Text)
|
|
planned_start = Column(DateTime)
|
|
planned_end = Column(DateTime)
|
|
created_by = Column(Integer, ForeignKey("sys_user.id"), nullable=False)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
# Async classification tracking
|
|
celery_task_id = Column(String(100), nullable=True)
|
|
scan_progress = Column(Text, nullable=True) # JSON: {"scanned": 0, "matched": 0, "total": 0}
|
|
|
|
template = relationship("ClassificationTemplate")
|
|
tasks = relationship("ClassificationTask", back_populates="project", cascade="all, delete-orphan")
|
|
results = relationship("ClassificationResult", back_populates="project", cascade="all, delete-orphan")
|
|
|
|
|
|
class ClassificationTask(Base):
|
|
__tablename__ = "classification_task"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
project_id = Column(Integer, ForeignKey("classification_project.id"), nullable=False)
|
|
name = Column(String(200))
|
|
assigner_id = Column(Integer, ForeignKey("sys_user.id"))
|
|
assignee_id = Column(Integer, ForeignKey("sys_user.id"))
|
|
target_type = Column(String(20), default="table") # table, column, file
|
|
target_ids = Column(Text) # comma separated ids
|
|
status = Column(String(20), default=TaskStatus.PENDING.value)
|
|
deadline = Column(DateTime)
|
|
completed_at = Column(DateTime)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
project = relationship("ClassificationProject", back_populates="tasks")
|
|
assigner = relationship("User", foreign_keys=[assigner_id])
|
|
assignee = relationship("User", foreign_keys=[assignee_id])
|
|
|
|
|
|
class ClassificationResult(Base):
|
|
__tablename__ = "classification_result"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
project_id = Column(Integer, ForeignKey("classification_project.id"), nullable=False)
|
|
column_id = Column(Integer, ForeignKey("meta_column.id"), nullable=True)
|
|
file_id = Column(Integer, ForeignKey("unstructured_file.id"), nullable=True)
|
|
category_id = Column(Integer, ForeignKey("category.id"))
|
|
level_id = Column(Integer, ForeignKey("data_level.id"))
|
|
source = Column(String(20), default="auto") # auto, manual, ml
|
|
confidence = Column(Float, default=0.0) # 0-1
|
|
labeler_id = Column(Integer, ForeignKey("sys_user.id"))
|
|
reviewer_id = Column(Integer, ForeignKey("sys_user.id"))
|
|
status = Column(String(20), default=ResultStatus.AUTO.value)
|
|
label_time = Column(DateTime)
|
|
review_time = Column(DateTime)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
project = relationship("ClassificationProject", back_populates="results")
|
|
column = relationship("DataColumn")
|
|
category = relationship("Category")
|
|
level = relationship("DataLevel")
|
|
|
|
|
|
class ClassificationChange(Base):
|
|
__tablename__ = "classification_change"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
result_id = Column(Integer, ForeignKey("classification_result.id"), nullable=False)
|
|
change_type = Column(String(20), nullable=False) # category, level, both
|
|
old_category_id = Column(Integer, ForeignKey("category.id"))
|
|
new_category_id = Column(Integer, ForeignKey("category.id"))
|
|
old_level_id = Column(Integer, ForeignKey("data_level.id"))
|
|
new_level_id = Column(Integer, ForeignKey("data_level.id"))
|
|
reason = Column(Text)
|
|
applicant_id = Column(Integer, ForeignKey("sys_user.id"))
|
|
approver_id = Column(Integer, ForeignKey("sys_user.id"))
|
|
approval_status = Column(String(20), default="pending") # pending, approved, rejected
|
|
approval_comment = Column(Text)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|