feat: документация из Nextcloud, график у сотрудника, автоочистка фото, мониторинг, итог мастера, фильтр по местам; доп. сервисы в docker-compose

- docker-compose.yml: профили docs (Nextcloud), office (ONLYOFFICE Document Server), ai (Ollama + скачивание модели)
- автонастройка: адреса Nextcloud, ONLYOFFICE, портала и модели подставляются из .env или по именам сервисов
  во внутренней сети Docker; значения из интерфейса важнее
- локальная модель в своей сети (имя сервиса, частный IP) подключается без ключа API
- .env.example, docs/DEPLOY.md (раздел 7а), README
This commit is contained in:
darkorion
2026-10-13 13:27:20 +03:00
parent 6b8fca4f5a
commit e67c175f80
44 changed files with 2131 additions and 94 deletions
+12 -1
View File
@@ -85,6 +85,7 @@ class UserIn(BaseModel):
portal_admin: bool = False
is_active: bool = True
position_id: Optional[int] = None
schedule_id: Optional[int] = None # график работы сотрудника (пусто — всегда на смене)
department_id: Optional[int] = None
skills: str = Field(default="", max_length=4000)
phone: str = Field(default="", max_length=40)
@@ -100,6 +101,7 @@ class UserPatch(BaseModel):
portal_admin: Optional[bool] = None
is_active: Optional[bool] = None
position_id: Optional[int] = None
schedule_id: Optional[int] = None
department_id: Optional[int] = None
skills: Optional[str] = Field(default=None, max_length=4000)
phone: Optional[str] = Field(default=None, max_length=40)
@@ -138,6 +140,7 @@ class UserOut(ORM):
is_active: bool
position_id: Optional[int]
position: Optional[PositionBrief] = None
schedule_id: Optional[int] = None
department_id: Optional[int] = None
department: Optional["DepartmentBrief"] = None
has_photo: bool = False
@@ -147,6 +150,7 @@ class UserOut(ORM):
demo_mode: bool = False
crane_map: bool = False # включена отдельная карта кранов
reliability: bool = False # доступен раздел «Анализ надёжности» (включён и у пользователя есть права)
docs: bool = False # подключена документация из Nextcloud
portal_admin: bool = False # администратор портала: настройки сервера и обратная связь
is_root: bool = False # администратор по умолчанию (admin): выдаёт права администратора портала
@@ -222,7 +226,7 @@ class PreviewDay(BaseModel):
class PositionIn(BaseModel):
name: str
kind: Literal["technician", "engineer"] = "technician"
schedule_id: Optional[int] = None
schedule_id: Optional[int] = None # устарело и не используется: график задаётся сотруднику
class PositionOut(ORM):
@@ -265,6 +269,7 @@ class EquipmentOut(EquipmentIn, ORM):
meter_updated_at: Optional[datetime] = None
map_x: Optional[float] = None
map_y: Optional[float] = None
docs_path: str = "" # папка документации в Nextcloud (привязывается через PUT /equipment/{id}/docs)
# ----- регламентное обслуживание: узлы машины -----
@@ -373,6 +378,7 @@ class ChecklistItemIn(BaseModel):
max_value: Optional[float] = None
required: bool = True
photo: Literal["none", "optional", "required"] = "none"
photo_keep: bool = False # фото хранить более года (не удаляются автоочисткой)
class ChecklistItemOut(ChecklistItemIn, ORM):
@@ -460,6 +466,7 @@ class OrderItemOut(ORM):
answered_at: Optional[datetime]
out_of_range: bool
photo: str
photo_keep: bool = False
service_unit_id: Optional[int] = None
is_meter: bool = False
photos: list[PhotoOut] = []
@@ -532,6 +539,7 @@ class SettingsIn(BaseModel):
setup_done: Optional[str] = Field(default=None, max_length=1000)
crane_map: Optional[bool] = None # отдельная карта кранов
reliability: Optional[bool] = None # раздел «Анализ надёжности»
photo_keep_days: Optional[int] = Field(default=None, ge=0, le=36500) # удалять фото старше N дней (0 — не удалять)
class PushSubIn(BaseModel):
@@ -841,6 +849,7 @@ class TaskIn(BaseModel):
equipment_id: Optional[int] = None
unit_id: Optional[int] = None
labor_hours: Optional[float] = Field(default=None, ge=0, le=1000)
photo_keep: bool = False # фото к заданию хранить более года
class TaskPatch(BaseModel):
@@ -851,6 +860,7 @@ class TaskPatch(BaseModel):
equipment_id: Optional[int] = None
unit_id: Optional[int] = None
labor_hours: Optional[float] = Field(default=None, ge=0, le=1000)
photo_keep: Optional[bool] = None
class TaskStatusIn(BaseModel):
@@ -892,6 +902,7 @@ class TaskOut(BaseModel):
updated_at: datetime
finished_at: Optional[datetime]
labor_hours: Optional[float] = None
photo_keep: bool = False
last_comment: str = ""
photos: list[int] = []
can_change: bool = False