refactor: 清理无用模块、修复前后端对齐、添加注册页面
- 删除后端 risk_exceptions 模块(API/Model/Schema/迁移/测试) - 删除后端 metrics 模块(API/测试) - 删除后端 ManualTask 模型和相关 Schema - 修复搜索接口响应缺少 total 字段的问题 - 统一 Platform 枚举(前端去掉后端不支持的 weibo/wechat) - 新增前端注册页面 /register,登录页添加注册链接 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a32102f583
commit
4a3c7e7923
@@ -9,10 +9,8 @@ from app.models.project import Project, project_agency_association
|
||||
from app.models.task import Task, TaskStage, TaskStatus
|
||||
from app.models.brief import Brief
|
||||
from app.models.ai_config import AIConfig
|
||||
from app.models.review import ReviewTask, ManualTask, Platform
|
||||
from app.models.review import ReviewTask, Platform
|
||||
from app.models.rule import ForbiddenWord, WhitelistItem, Competitor
|
||||
from app.models.risk_exception import RiskException
|
||||
|
||||
# 保留 Tenant 兼容旧代码,但新代码应使用 Brand
|
||||
from app.models.tenant import Tenant
|
||||
|
||||
@@ -37,15 +35,13 @@ __all__ = [
|
||||
"Brief",
|
||||
# AI 配置
|
||||
"AIConfig",
|
||||
# 审核(旧模型,保留兼容)
|
||||
# 审核
|
||||
"ReviewTask",
|
||||
"ManualTask",
|
||||
"Platform",
|
||||
# 规则
|
||||
"ForbiddenWord",
|
||||
"WhitelistItem",
|
||||
"Competitor",
|
||||
"RiskException",
|
||||
# 兼容
|
||||
"Tenant",
|
||||
]
|
||||
|
||||
@@ -85,80 +85,5 @@ class ReviewTask(Base, TimestampMixin):
|
||||
|
||||
# 关联
|
||||
tenant: Mapped["Tenant"] = relationship("Tenant", back_populates="review_tasks")
|
||||
manual_task: Mapped[Optional["ManualTask"]] = relationship(
|
||||
"ManualTask",
|
||||
back_populates="review_task",
|
||||
uselist=False,
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<ReviewTask(id={self.id}, status={self.status})>"
|
||||
|
||||
|
||||
class ManualTask(Base, TimestampMixin):
|
||||
"""人工审核任务表"""
|
||||
__tablename__ = "manual_tasks"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||||
tenant_id: Mapped[str] = mapped_column(
|
||||
String(64),
|
||||
ForeignKey("tenants.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
review_task_id: Mapped[Optional[str]] = mapped_column(
|
||||
String(64),
|
||||
ForeignKey("review_tasks.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
|
||||
# 视频信息 (冗余存储,即使关联的 review_task 被删除也能查看)
|
||||
video_url: Mapped[Optional[str]] = mapped_column(String(2048), nullable=True)
|
||||
video_uploaded_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
)
|
||||
platform: Mapped[Platform] = mapped_column(
|
||||
SQLEnum(Platform, name="platform_enum", create_type=False),
|
||||
nullable=False,
|
||||
)
|
||||
creator_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
||||
|
||||
# 脚本信息
|
||||
script_content: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
script_file_url: Mapped[Optional[str]] = mapped_column(String(2048), nullable=True)
|
||||
script_uploaded_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
# 任务状态
|
||||
status: Mapped[TaskStatus] = mapped_column(
|
||||
SQLEnum(TaskStatus, name="task_status_enum", create_type=False),
|
||||
default=TaskStatus.PENDING,
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
||||
# 审批结果
|
||||
approve_comment: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
reject_reason: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
reject_violations: Mapped[Optional[list]] = mapped_column(JSONType, nullable=True)
|
||||
|
||||
# 审批人
|
||||
reviewer_id: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||||
reviewed_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
# 关联
|
||||
tenant: Mapped["Tenant"] = relationship("Tenant", back_populates="manual_tasks")
|
||||
review_task: Mapped[Optional["ReviewTask"]] = relationship(
|
||||
"ReviewTask",
|
||||
back_populates="manual_task",
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<ManualTask(id={self.id}, status={self.status})>"
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
"""
|
||||
特例审批模型
|
||||
"""
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from datetime import datetime
|
||||
from sqlalchemy import String, Text, Boolean, ForeignKey, DateTime, Enum as SQLEnum
|
||||
from app.models.types import JSONType
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
import enum
|
||||
|
||||
from app.models.base import Base, TimestampMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.tenant import Tenant
|
||||
|
||||
|
||||
class RiskTargetType(str, enum.Enum):
|
||||
"""特例目标类型"""
|
||||
INFLUENCER = "influencer"
|
||||
ORDER = "order"
|
||||
CONTENT = "content"
|
||||
|
||||
|
||||
class RiskExceptionStatus(str, enum.Enum):
|
||||
"""特例审批状态"""
|
||||
PENDING = "pending"
|
||||
APPROVED = "approved"
|
||||
REJECTED = "rejected"
|
||||
EXPIRED = "expired"
|
||||
REVOKED = "revoked"
|
||||
|
||||
|
||||
class RiskException(Base, TimestampMixin):
|
||||
"""特例审批表"""
|
||||
__tablename__ = "risk_exceptions"
|
||||
|
||||
id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||||
tenant_id: Mapped[str] = mapped_column(
|
||||
String(64),
|
||||
ForeignKey("tenants.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
||||
# 申请信息
|
||||
applicant_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
||||
apply_time: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
# 目标信息
|
||||
target_type: Mapped[RiskTargetType] = mapped_column(
|
||||
SQLEnum(RiskTargetType, name="risk_target_type_enum"),
|
||||
nullable=False,
|
||||
)
|
||||
target_id: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
||||
risk_rule_id: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
|
||||
# 状态
|
||||
status: Mapped[RiskExceptionStatus] = mapped_column(
|
||||
SQLEnum(RiskExceptionStatus, name="risk_exception_status_enum"),
|
||||
default=RiskExceptionStatus.PENDING,
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
||||
# 有效期
|
||||
valid_start_time: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
)
|
||||
valid_end_time: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
# 申请原因
|
||||
reason_category: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||
justification: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
attachment_url: Mapped[Optional[str]] = mapped_column(String(2048), nullable=True)
|
||||
|
||||
# 审批信息
|
||||
current_approver_id: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
|
||||
|
||||
# 审批流转日志 (JSON 数组)
|
||||
# [{"approver_id": "...", "action": "approve/reject", "comment": "...", "timestamp": "..."}]
|
||||
approval_chain_log: Mapped[list] = mapped_column(JSONType, default=list, nullable=False)
|
||||
|
||||
# 驳回信息
|
||||
auto_rejected: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
||||
rejection_reason: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
||||
|
||||
# 最近状态变更时间
|
||||
last_status_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
# 关联
|
||||
tenant: Mapped["Tenant"] = relationship("Tenant", back_populates="risk_exceptions")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<RiskException(id={self.id}, status={self.status})>"
|
||||
@@ -9,9 +9,8 @@ from app.models.base import Base, TimestampMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.models.ai_config import AIConfig
|
||||
from app.models.review import ReviewTask, ManualTask
|
||||
from app.models.review import ReviewTask
|
||||
from app.models.rule import ForbiddenWord, WhitelistItem, Competitor
|
||||
from app.models.risk_exception import RiskException
|
||||
|
||||
|
||||
class Tenant(Base, TimestampMixin):
|
||||
@@ -34,11 +33,6 @@ class Tenant(Base, TimestampMixin):
|
||||
back_populates="tenant",
|
||||
lazy="selectin",
|
||||
)
|
||||
manual_tasks: Mapped[list["ManualTask"]] = relationship(
|
||||
"ManualTask",
|
||||
back_populates="tenant",
|
||||
lazy="selectin",
|
||||
)
|
||||
forbidden_words: Mapped[list["ForbiddenWord"]] = relationship(
|
||||
"ForbiddenWord",
|
||||
back_populates="tenant",
|
||||
@@ -54,11 +48,5 @@ class Tenant(Base, TimestampMixin):
|
||||
back_populates="tenant",
|
||||
lazy="selectin",
|
||||
)
|
||||
risk_exceptions: Mapped[list["RiskException"]] = relationship(
|
||||
"RiskException",
|
||||
back_populates="tenant",
|
||||
lazy="selectin",
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Tenant(id={self.id}, name={self.name})>"
|
||||
|
||||
Reference in New Issue
Block a user