161 lines
3.8 KiB
Python
161 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
Role = Literal["student", "admin"]
|
|
OrderStatus = Literal["已提交", "待处理", "处理中", "待上门", "已完成", "已确认", "返工申请中", "已取消"]
|
|
Urgency = Literal["低", "中", "高", "紧急"]
|
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
username: str = Field(min_length=1, max_length=50)
|
|
password: str = Field(min_length=1, max_length=100)
|
|
|
|
|
|
class UserProfile(BaseModel):
|
|
id: int
|
|
username: str
|
|
display_name: str
|
|
role: Role
|
|
|
|
|
|
class LoginResponse(BaseModel):
|
|
token: str
|
|
user: UserProfile
|
|
|
|
|
|
class DiagnosisStartRequest(BaseModel):
|
|
message: str = Field(min_length=2, max_length=300)
|
|
|
|
|
|
class DiagnosisQuestionAnswer(BaseModel):
|
|
question_id: str
|
|
answer: str = Field(min_length=1, max_length=200)
|
|
|
|
|
|
class DiagnosisAnswerRequest(BaseModel):
|
|
session_id: str
|
|
answers: list[DiagnosisQuestionAnswer]
|
|
|
|
|
|
class DiagnosisQuestion(BaseModel):
|
|
id: str
|
|
prompt: str
|
|
|
|
|
|
class DiagnosisDraft(BaseModel):
|
|
category: str
|
|
urgency: Urgency
|
|
summary: str
|
|
safety_risk: bool
|
|
suggested_worker: str
|
|
notes: list[str]
|
|
|
|
|
|
class DiagnosisResponse(BaseModel):
|
|
session_id: str
|
|
stage: Literal["questions", "draft"]
|
|
initial_message: str
|
|
suggested_categories: list[str]
|
|
questions: list[DiagnosisQuestion]
|
|
draft: DiagnosisDraft | None = None
|
|
|
|
|
|
class SavedAddressOut(BaseModel):
|
|
id: int
|
|
campus: str
|
|
building: str
|
|
room: str
|
|
last_used_at: str
|
|
|
|
|
|
class OrderCreateRequest(BaseModel):
|
|
campus: str = Field(min_length=1, max_length=50)
|
|
building: str = Field(min_length=1, max_length=50)
|
|
room: str = Field(min_length=1, max_length=50)
|
|
category: str = Field(min_length=1, max_length=50)
|
|
raw_description: str = Field(min_length=2, max_length=300)
|
|
structured_summary: str = Field(min_length=2, max_length=400)
|
|
urgency: Urgency
|
|
expected_date: str | None = Field(default=None, max_length=20)
|
|
expected_time_segment: str | None = Field(default=None, max_length=50)
|
|
diagnosis_session_id: str | None = Field(default=None, max_length=80)
|
|
allow_room_entry: bool = False
|
|
|
|
|
|
class FeedbackRequest(BaseModel):
|
|
rating: int = Field(ge=1, le=5)
|
|
comment: str = Field(min_length=1, max_length=300)
|
|
|
|
|
|
class ReworkRequest(BaseModel):
|
|
reason: str = Field(min_length=2, max_length=300)
|
|
|
|
|
|
class AdminOrderUpdateRequest(BaseModel):
|
|
status: OrderStatus | None = None
|
|
assignee_name: str | None = Field(default=None, max_length=50)
|
|
expected_arrival_at: str | None = Field(default=None, max_length=50)
|
|
admin_note: str | None = Field(default=None, max_length=300)
|
|
|
|
|
|
class OrderEventOut(BaseModel):
|
|
id: int
|
|
actor_role: str
|
|
actor_name: str
|
|
event_type: str
|
|
title: str
|
|
detail: str | None
|
|
from_status: str | None
|
|
to_status: str | None
|
|
created_at: str
|
|
|
|
|
|
class AttachmentOut(BaseModel):
|
|
id: int
|
|
file_name: str
|
|
file_path: str
|
|
mime_type: str
|
|
created_at: str
|
|
|
|
|
|
class OrderSummaryOut(BaseModel):
|
|
id: int
|
|
order_no: str
|
|
campus: str
|
|
building: str
|
|
room: str
|
|
category: str
|
|
status: str
|
|
urgency: str
|
|
submission_time: str
|
|
expected_repair_time: str | None
|
|
assignee_name: str | None
|
|
|
|
|
|
class OrderDetailOut(BaseModel):
|
|
id: int
|
|
order_no: str
|
|
campus: str
|
|
building: str
|
|
room: str
|
|
category: str
|
|
status: str
|
|
urgency: str
|
|
raw_description: str
|
|
structured_summary: str
|
|
allow_room_entry: bool
|
|
expected_date: str | None
|
|
expected_time_segment: str | None
|
|
assignee_name: str | None
|
|
expected_arrival_at: str | None
|
|
admin_note: str | None
|
|
rework_reason: str | None
|
|
created_at: str
|
|
updated_at: str
|
|
attachments: list[AttachmentOut]
|
|
events: list[OrderEventOut]
|
|
feedback: dict[str, Any] | None
|