from __future__ import annotations from typing import Any from pydantic import BaseModel, Field class ProjectIn(BaseModel): name: str category_id: int | None = None owner: str | None = None # 主负责人;传了 owners 时以 owners[0] 为准 owners: list[str] | None = None # 多负责人(第一位是主负责人),整体替换 members: list[str] | None = None # 团队成员,整体替换 status: str = "in_progress" priority: str = "p2" is_key: bool = False progress: float = 0 description: str | None = None archived: bool = False tags: list[str] = Field(default_factory=list) # 标签名,自动创建 class ProjectPatch(BaseModel): name: str | None = None category_id: int | None = None owner: str | None = None owners: list[str] | None = None # 不传即不改;传空数组即清空 members: list[str] | None = None status: str | None = None priority: str | None = None is_key: bool | None = None progress: float | None = None description: str | None = None archived: bool | None = None tags: list[str] | None = None class CategoryIn(BaseModel): name: str color: str = "#2563eb" class TagIn(BaseModel): name: str color: str = "#6b7280" class PeriodIn(BaseModel): label: str kind: str = "week" year: int month: int week: int = 0 start_date: str | None = None end_date: str | None = None class TaskIn(BaseModel): project_id: int name: str class UpdateIn(BaseModel): project_id: int task_id: int | None = None period_id: int content: str | None = None summary: str | None = None progress: float | None = None status: str = "in_progress" risk: str | None = None next_step: str | None = None owner: str | None = None source: str = "manual" raw_text: str | None = None model: str | None = None # AI 写入时可直接传子任务名(自动创建/复用) task_name: str | None = None class UpdatePatch(BaseModel): """修改单条执行记录:只提交需要改的字段(未提交的字段保持原值)。""" task_id: int | None = None task_name: str | None = None period_id: int | None = None content: str | None = None summary: str | None = None progress: float | None = None status: str | None = None risk: str | None = None next_step: str | None = None owner: str | None = None class AIParseIn(BaseModel): project_id: int | None = None project_name: str | None = None period_id: int | None = None raw_text: str use_ai: bool = True class AICommitIn(BaseModel): project_id: int | None = None project_name: str | None = None period_id: int raw_text: str parsed: dict[str, Any] mode: str = "ai" model: str | None = None class SettingsIn(BaseModel): values: dict[str, str] class FocusIn(BaseModel): """每周重点工作(单条录入)。 预计完成时间是日历日期(due_date: YYYY-MM-DD),只作目标日期,不决定条目归属的周; period_id 是录入周(前端传顶栏当前周,脚本可不传,后端按今天所在周补)。 """ content: str detail: str | None = None due_date: str | None = None result: str | None = None delayed: bool | None = None period_id: int | None = None status: str = "not_started" class FocusPatch(BaseModel): content: str | None = None detail: str | None = None due_date: str | None = None result: str | None = None delayed: bool | None = None period_id: int | None = None status: str | None = None archived: bool | None = None # ---------------------------------------------------------------------- 权限 class LoginIn(BaseModel): username: str password: str class ProfileIn(BaseModel): name: str class PasswordIn(BaseModel): old_password: str new_password: str class RoleIn(BaseModel): name: str description: str | None = None menus: dict[str, str] = Field(default_factory=dict) class RolePatch(BaseModel): name: str | None = None description: str | None = None menus: dict[str, str] | None = None class UserIn(BaseModel): name: str username: str password: str role_id: int | None = None active: bool = True class UserPatch(BaseModel): name: str | None = None role_id: int | None = None active: bool | None = None password: str | None = None # 管理员重置密码,不需要旧密码