Files
hiderfong 6d70520e79 feat: 全量功能模块开发与集成测试修复
- 新增后端模块:Alert、APIAsset、Compliance、Lineage、Masking、Risk、SchemaChange、Unstructured、Watermark
- 新增前端模块页面与API接口
- 新增Alembic迁移脚本(002-014)覆盖全量业务表
- 新增测试数据生成脚本与集成测试脚本
- 修复metadata模型JSON类型导入缺失导致启动失败的问题
- 修复前端Alert/APIAsset页面request模块路径错误
- 更新docker-compose与开发计划文档
2026-04-25 08:51:38 +08:00

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)