From ce4b50109a5dbdb64199f77f40d61a580d7f47f7 Mon Sep 17 00:00:00 2001 From: vladtechno Date: Wed, 29 Jul 2026 13:37:38 +1000 Subject: [PATCH] =?UTF-8?q?repairs:=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BA=D0=BE=20=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD=20=D0=BC?= =?UTF-8?q?=D0=B0=D1=81=D0=BB=D0=B0=20=D0=B7=D0=B0=20=D0=B7=D0=B0=D0=B5?= =?UTF-8?q?=D0=B7=D0=B4=20(=D0=B4=D0=B2=D0=B8=D0=B3=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=20+=20=D0=BA=D0=BE=D1=80=D0=BE=D0=B1=D0=BA=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Блок «Замена масла» теперь мульти: чекбоксы Двигатель / Коробка (можно оба), общий одометр (одна замена — один пробег). Отправляем список oil_changes (1:N), стикер прикрепляем к первой выбранной. Тип 'transmission' объединяет АКПП/вариатор/робот — интервал по модели в отчёте СТО. Co-Authored-By: Claude Opus 4.8 --- .../frontend/src/api/repairsCreate.ts | 3 +- .../src/pages/repairs/CreateRepairPage.tsx | 103 ++++++++++-------- 2 files changed, 60 insertions(+), 46 deletions(-) diff --git a/mechanic-pwa/frontend/src/api/repairsCreate.ts b/mechanic-pwa/frontend/src/api/repairsCreate.ts index 4524ab6..2d56f3c 100644 --- a/mechanic-pwa/frontend/src/api/repairsCreate.ts +++ b/mechanic-pwa/frontend/src/api/repairsCreate.ts @@ -72,7 +72,8 @@ export interface CreateRepairPayload { works: CreateWorkPayload[]; parts: CreatePartPayload[]; photos: CreatePhotoPayload[]; - oil_change: CreateOilChangePayload | null; + // 1:N — за один заезд бывает несколько замен (двигатель + коробка). + oil_changes: CreateOilChangePayload[]; } export interface CreateRepairResponse { diff --git a/mechanic-pwa/frontend/src/pages/repairs/CreateRepairPage.tsx b/mechanic-pwa/frontend/src/pages/repairs/CreateRepairPage.tsx index ca129b6..54130d4 100644 --- a/mechanic-pwa/frontend/src/pages/repairs/CreateRepairPage.tsx +++ b/mechanic-pwa/frontend/src/pages/repairs/CreateRepairPage.tsx @@ -61,14 +61,13 @@ interface PartRow { qty: number; } -type OilKind = "engine" | "cvt" | "akpp"; - interface OilChangeState { enabled: boolean; - mileage_at_change: number | null; + mileage_at_change: number | null; // общий одометр — один на все замены заезда mileage_is_dirty: boolean; // У24: мягкая подписка с шапочным - next_in_km: number; - oil_type: OilKind; + next_in_km: number; // интервал двигателя + // Какие масла меняли за заезд (можно оба сразу): + types: { engine: boolean; transmission: boolean }; sticker: PhotoState | null; } @@ -101,7 +100,7 @@ export default function CreateRepairPage() { mileage_at_change: null, mileage_is_dirty: false, next_in_km: 10000, - oil_type: "engine", + types: { engine: true, transmission: false }, sticker: null, }); @@ -272,6 +271,8 @@ export default function CreateRepairPage() { if (works.length === 0) return "Добавьте хотя бы одну работу"; const unlockedNoComment = works.find((w) => w.unlocked && !w.override_comment.trim()); if (unlockedNoComment) return "Укажите комментарий к ручной правке цены"; + if (oilChange.enabled && !oilChange.types.engine && !oilChange.types.transmission) + return "Выберите тип масла (двигатель и/или коробка) или снимите «Была замена масла»"; return ""; }; @@ -301,22 +302,25 @@ export default function CreateRepairPage() { })), parts: parts.map((p) => ({ name: p.name, qty: p.qty })), photos: photoPayload, - oil_change: oilChange.enabled - ? { - enabled: true, - mileage_at_change: oilChange.mileage_at_change, - next_in_km: oilChange.next_in_km, - oil_type: oilChange.oil_type, - sticker_photo_uuid: - oilChange.sticker?.status === "uploaded" - ? oilChange.sticker.presign.photo_uuid - : null, - sticker_extension: - oilChange.sticker?.status === "uploaded" - ? oilChange.sticker.presign.extension - : null, - } - : null, + oil_changes: oilChange.enabled + ? (["engine", "transmission"] as const) + .filter((t) => oilChange.types[t]) + .map((t, idx) => ({ + enabled: true, + mileage_at_change: oilChange.mileage_at_change, + next_in_km: t === "engine" ? oilChange.next_in_km : 0, + oil_type: t, + // Стикер прикрепляем к первой выбранной замене (обычно двигатель). + sticker_photo_uuid: + idx === 0 && oilChange.sticker?.status === "uploaded" + ? oilChange.sticker.presign.photo_uuid + : null, + sticker_extension: + idx === 0 && oilChange.sticker?.status === "uploaded" + ? oilChange.sticker.presign.extension + : null, + })) + : [], }, idemKey.current, ); @@ -585,25 +589,34 @@ export default function CreateRepairPage() { {oilChange.enabled && (
- -
- {([["engine", "Двигатель"], ["cvt", "Вариатор"], ["akpp", "АКПП"]] as [OilKind, string][]).map( - ([v, l]) => ( - - ), - )} + +
+ {( + [ + ["engine", "Двигатель"], + ["transmission", "Коробка"], + ] as ["engine" | "transmission", string][] + ).map(([v, l]) => ( + + ))}
+ {!oilChange.types.engine && !oilChange.types.transmission && ( +

Выберите хотя бы один тип масла.

+ )}
@@ -620,9 +633,9 @@ export default function CreateRepairPage() { } />
- {oilChange.oil_type === "engine" ? ( + {oilChange.types.engine && (
- +
- ) : ( + )} + {oilChange.types.transmission && (

- Интервал {oilChange.oil_type === "cvt" ? "вариатора" : "АКПП"} задаётся по модели авто в - отчёте СТО. + Интервал коробки задаётся по модели авто в отчёте СТО.

)}