补充监查访视问题模块内容、翻页功能UI统一

This commit is contained in:
Cheng Zhou
2026-02-28 09:51:13 +08:00
parent db2d38edbc
commit af0c1b4b7d
16 changed files with 2372 additions and 84 deletions
@@ -0,0 +1,182 @@
import uuid
from datetime import date, datetime, timezone
from pydantic import BaseModel, ConfigDict, field_validator
class MonitoringVisitIssueCreate(BaseModel):
issue_no: str | None = None
category: str
subject_code: str | None = None
monitor_item: str | None = None
monitor_type: str | None = None
status: str = "OPEN"
source: str | None = None
creator_name: str | None = None
recommendation: str | None = None
subject_name: str | None = None
description: str | None = None
action_taken: str | None = None
follow_up_progress: str | None = None
found_date: date | None = None
due_at: datetime | None = None
actual_resolve_date: date | None = None
closed_at: datetime | None = None
responsible_name: str | None = None
@field_validator("category", mode="before")
@classmethod
def _strip_required(cls, value: str) -> str:
text = (value or "").strip()
if not text:
raise ValueError("不能为空")
return text
@field_validator("issue_no", mode="before")
@classmethod
def _strip_issue_no(cls, value: str | None) -> str | None:
if value is None:
return None
text = value.strip()
return text or None
@field_validator(
"subject_code",
"monitor_item",
"monitor_type",
"source",
"creator_name",
"recommendation",
"subject_name",
"description",
"action_taken",
"follow_up_progress",
"responsible_name",
mode="before",
)
@classmethod
def _strip_optional(cls, value: str | None) -> str | None:
if value is None:
return None
text = value.strip()
return text or None
@field_validator("status", mode="before")
@classmethod
def _normalize_status(cls, value: str | None) -> str:
normalized = (value or "OPEN").strip().upper()
if normalized not in {"OPEN", "CLOSED"}:
raise ValueError("状态必须为 OPEN 或 CLOSED")
return normalized
@field_validator("due_at", "closed_at")
@classmethod
def _normalize_due_at(cls, value: datetime | None) -> datetime | None:
if value is None:
return None
return value if value.tzinfo else value.replace(tzinfo=timezone.utc)
class MonitoringVisitIssueRead(BaseModel):
id: uuid.UUID
study_id: uuid.UUID
issue_no: str
open_duration: str
category: str
subject_code: str | None
monitor_item: str | None
monitor_type: str | None
progress: str
status: str
source: str | None
creator_name: str | None
recommendation: str | None
subject_name: str | None
created_at: datetime
description: str | None
action_taken: str | None
follow_up_progress: str | None
found_date: date | None
overdue: bool
due_at: datetime | None
actual_resolve_date: date | None
closed_at: datetime | None
responsible_name: str | None
model_config = ConfigDict(from_attributes=True)
class MonitoringVisitIssueImportSummary(BaseModel):
created_count: int
updated_count: int
skipped_count: int
skipped_rows: list[str]
class MonitoringVisitIssueUpdate(BaseModel):
issue_no: str | None = None
category: str | None = None
subject_code: str | None = None
monitor_item: str | None = None
monitor_type: str | None = None
status: str | None = None
source: str | None = None
creator_name: str | None = None
recommendation: str | None = None
subject_name: str | None = None
description: str | None = None
action_taken: str | None = None
follow_up_progress: str | None = None
found_date: date | None = None
due_at: datetime | None = None
actual_resolve_date: date | None = None
closed_at: datetime | None = None
responsible_name: str | None = None
@field_validator("issue_no", "category", mode="before")
@classmethod
def _strip_required(cls, value: str | None) -> str | None:
if value is None:
return None
text = value.strip()
if not text:
raise ValueError("不能为空")
return text
@field_validator(
"subject_code",
"monitor_item",
"monitor_type",
"source",
"creator_name",
"recommendation",
"subject_name",
"description",
"action_taken",
"follow_up_progress",
"responsible_name",
mode="before",
)
@classmethod
def _strip_optional(cls, value: str | None) -> str | None:
if value is None:
return None
text = value.strip()
return text or None
@field_validator("status", mode="before")
@classmethod
def _normalize_status(cls, value: str | None) -> str | None:
if value is None:
return None
normalized = value.strip().upper()
if normalized not in {"OPEN", "CLOSED"}:
raise ValueError("状态必须为 OPEN 或 CLOSED")
return normalized
@field_validator("due_at", "closed_at")
@classmethod
def _normalize_due_at(cls, value: datetime | None) -> datetime | None:
if value is None:
return None
return value if value.tzinfo else value.replace(tzinfo=timezone.utc)