PMFlow/backend/app/schemas/feedback_center.py

210 lines
5.5 KiB
Python

"""统一反馈中心 Pydantic 模型。"""
from __future__ import annotations
from datetime import date, datetime
from typing import Any, Literal, Optional
from pydantic import BaseModel, ConfigDict, Field
class FeedbackReasonCandidate(BaseModel):
model_config = ConfigDict(extra="ignore")
code: str
label: str
confidence: float = 0.0
description: Optional[str] = None
source_type: Optional[str] = None
field_name: Optional[str] = None
class FeedbackCenterRecordRevisionRead(BaseModel):
model_config = ConfigDict(from_attributes=True, extra="ignore")
id: int
record_id: int
before_snapshot: Any
after_snapshot: Any
reviewed_by: Optional[int] = None
reviewed_at: Optional[datetime] = None
created_at: Optional[datetime] = None
class FeedbackCenterRecordRead(BaseModel):
model_config = ConfigDict(from_attributes=True, extra="ignore")
id: int
tenant_id: int
project_id: Optional[int] = None
source_type: str
source_id: int
object_type: str
object_id: int
field_name: str
source_title: Optional[str] = None
object_title: Optional[str] = None
before_value: Any = None
after_value: Any = None
ai_snapshot: Any = None
ai_confidence: Optional[float] = None
reason_candidates: list[FeedbackReasonCandidate] = Field(default_factory=list)
reason_code: Optional[str] = None
reason_text: Optional[str] = None
review_status: str
reviewed_by: Optional[int] = None
reviewed_at: Optional[datetime] = None
auto_assigned: bool = False
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
revisions: list[FeedbackCenterRecordRevisionRead] = Field(default_factory=list)
class FeedbackCenterSummaryReasonRead(BaseModel):
code: str
label: str
count: int
class FeedbackCenterSummaryMetricsRead(BaseModel):
accepted_rate_reviewed: float
manual_override_rate: float
rework_rate: float
auto_assigned_rate: float
avg_review_latency_minutes: float
total_task_breakdown_count: int
total_task_override_count: int
total_qa_feedback_count: int
total_signal_feedback_count: int
total_revision_count: int
class FeedbackCenterTrendDailyRead(BaseModel):
model_config = ConfigDict(extra="ignore")
date: date
total_records: int
accepted_count: int
rejected_count: int
reviewed_count: int
pending_count: int
task_breakdown_count: int
task_override_count: int
qa_feedback_count: int
signal_feedback_count: int
auto_assigned_count: int
override_count: int
rework_count: int
accepted_rate_reviewed: float
manual_override_rate: float
rework_rate: float
auto_assigned_rate: float
avg_review_latency_minutes: float
revision_count: int
class FeedbackCenterTrendWindowRead(BaseModel):
model_config = ConfigDict(extra="ignore")
total_records: int
accepted_count: int
rejected_count: int
reviewed_count: int
pending_count: int
task_breakdown_count: int
task_override_count: int
qa_feedback_count: int
signal_feedback_count: int
auto_assigned_count: int
override_count: int
rework_count: int
accepted_rate_reviewed: float
manual_override_rate: float
rework_rate: float
auto_assigned_rate: float
avg_review_latency_minutes: float
revision_count: int
class FeedbackCenterTrendDeltaRead(BaseModel):
model_config = ConfigDict(extra="ignore")
total_records_delta: int
accepted_rate_reviewed_delta: float
manual_override_rate_delta: float
rework_rate_delta: float
auto_assigned_rate_delta: float
avg_review_latency_minutes_delta: float
class FeedbackCenterTrendRead(BaseModel):
model_config = ConfigDict(extra="ignore")
window_days: int
current_window_start: date
previous_window_start: date
daily: list[FeedbackCenterTrendDailyRead]
current: FeedbackCenterTrendWindowRead
previous: FeedbackCenterTrendWindowRead
deltas: FeedbackCenterTrendDeltaRead
class FeedbackCenterSummaryRead(BaseModel):
model_config = ConfigDict(extra="ignore")
tenant_id: int
project_id: Optional[int] = None
source_group: str = "all"
total: int
backlog_count: int
pending_count: int
reviewed_count: int
accepted_count: int
rejected_count: int
accepted_rate: float
avg_confidence: float
by_status: dict[str, int]
by_source_type: dict[str, int]
top_reasons: list[FeedbackCenterSummaryReasonRead]
metrics: FeedbackCenterSummaryMetricsRead
trend: FeedbackCenterTrendRead
class FeedbackCenterListRead(BaseModel):
model_config = ConfigDict(extra="ignore")
items: list[FeedbackCenterRecordRead]
total: int
limit: int
offset: int
has_more: bool
class FeedbackCenterReviewRequest(BaseModel):
model_config = ConfigDict(extra="ignore")
review_status: Literal["reviewed", "accepted", "rejected"] = "accepted"
reason_code: Optional[str] = None
reason_text: Optional[str] = None
class FeedbackCenterReasonCatalogRead(BaseModel):
items: list[FeedbackReasonCandidate]
__all__ = [
"FeedbackReasonCandidate",
"FeedbackCenterRecordRevisionRead",
"FeedbackCenterRecordRead",
"FeedbackCenterSummaryReasonRead",
"FeedbackCenterSummaryMetricsRead",
"FeedbackCenterTrendDailyRead",
"FeedbackCenterTrendWindowRead",
"FeedbackCenterTrendDeltaRead",
"FeedbackCenterTrendRead",
"FeedbackCenterSummaryRead",
"FeedbackCenterListRead",
"FeedbackCenterReviewRequest",
"FeedbackCenterReasonCatalogRead",
]