From 2a58c5ca94709f64550ff734de7f996ac6eb15d9 Mon Sep 17 00:00:00 2001 From: vladtechno Date: Thu, 13 Aug 2026 20:10:39 +1000 Subject: [PATCH] =?UTF-8?q?feat(tyres):=20=D0=BF=D0=BE=20=D1=83=D0=BC?= =?UTF-8?q?=D0=BE=D0=BB=D1=87=D0=B0=D0=BD=D0=B8=D1=8E=20=D1=82=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BA=D0=BE=20=D0=BF=D0=BE=D0=B4=D1=85=D0=BE=D0=B4=D1=8F?= =?UTF-8?q?=D1=89=D0=B0=D1=8F=20=D1=80=D0=B5=D0=B7=D0=B8=D0=BD=D0=B0,=20?= =?UTF-8?q?=C2=AB=D0=9F=D0=BE=D0=BA=D0=B0=D0=B7=D0=B0=D1=82=D1=8C=20=D0=B2?= =?UTF-8?q?=D1=81=D0=B5=C2=BB=20=D1=80=D0=B0=D0=B7=D0=B2=D0=BE=D1=80=D0=B0?= =?UTF-8?q?=D1=87=D0=B8=D0=B2=D0=B0=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Кладовщик у подъёмника выбирал размер из девятнадцати позиций глазами. Теперь экран показывает только подходящее выбранной машине (по подтверждённой применимости), с счётчиком и кнопкой-переключателем на полный список. Если по модели применимость не отмечена, фильтровать нечем — показываются все размеры и объясняется, почему: прятать правильную резину по незнанию хуже, чем показать лишнюю. Плашка на строке различает «подходит» (применимость) и «штатный» (справочник размеров), и предвыбор позиции теперь учитывает оба признака. --- mechanic-pwa/frontend/src/api/warehouse.ts | 4 ++ .../src/pages/warehouse/TyresPage.tsx | 51 ++++++++++++++----- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/mechanic-pwa/frontend/src/api/warehouse.ts b/mechanic-pwa/frontend/src/api/warehouse.ts index 74a51a2..0575716 100644 --- a/mechanic-pwa/frontend/src/api/warehouse.ts +++ b/mechanic-pwa/frontend/src/api/warehouse.ts @@ -375,6 +375,8 @@ export interface TyreStockRow { by_grade: Partial>; places: string[]; suggested: boolean; + /** Подтверждённая применимость к выбранной машине. */ + fits: boolean; } export interface TyreSet { @@ -410,6 +412,8 @@ export interface TyreContext { suggested_size: string | null; open_set: TyreSet | null; stock: TyreStockRow[]; + /** Известно ли, что подходит машине. false — фильтровать нечем, показываем всё. */ + fit_known: boolean; } export interface TyreClose { diff --git a/mechanic-pwa/frontend/src/pages/warehouse/TyresPage.tsx b/mechanic-pwa/frontend/src/pages/warehouse/TyresPage.tsx index 194cbca..ee8ce58 100644 --- a/mechanic-pwa/frontend/src/pages/warehouse/TyresPage.tsx +++ b/mechanic-pwa/frontend/src/pages/warehouse/TyresPage.tsx @@ -179,14 +179,19 @@ function IssueForm({ carId, onDone }: { carId: number; onDone: () => void }) { // Подставляем подсказанный размер, как только пришёл контекст. useEffect(() => { if (!ctx || partId !== null) return; - const suggested = ctx.stock.find((s) => s.suggested && s.qty > 0); - if (suggested) setPartId(suggested.part_id); + const best = ctx.stock.find((s) => (s.fits || s.suggested) && s.qty > 0); + if (best) setPartId(best.part_id); }, [ctx, partId]); - const visibleStock = useMemo(() => { - if (!ctx) return []; - return showAll ? ctx.stock : ctx.stock.slice(0, 6); - }, [ctx, showAll]); + // По умолчанию показываем ТОЛЬКО подходящее этой машине — иначе кладовщик + // выбирает размер из девятнадцати позиций глазами. Если применимость по + // машине не заполнена, фильтровать нечем: прятать правильную резину по + // незнанию хуже, чем показать лишнюю (то же правило, что у подбора запчастей). + const fitting = useMemo( + () => (ctx ? ctx.stock.filter((s) => s.fits || s.suggested) : []), + [ctx], + ); + const visibleStock = showAll || !ctx?.fit_known ? (ctx?.stock ?? []) : fitting; if (ctxQuery.isLoading) { return
Загрузка…
; @@ -290,7 +295,20 @@ function IssueForm({ carId, onDone }: { carId: number; onDone: () => void }) { {/* Что выдаём */}
-

Что выдаём

+
+

Что выдаём

+ {ctx.fit_known && ( + + {showAll ? `все размеры (${ctx.stock.length})` : `подходит: ${fitting.length}`} + + )} +
+ {!ctx.fit_known && ( +

+ Для этой модели не отмечено, какая резина подходит, — показаны все размеры. + Отметить можно в карточке позиции на складе. +

+ )}
{visibleStock.length === 0 && (

На складе нет резины.

@@ -304,9 +322,16 @@ function IssueForm({ carId, onDone }: { carId: number; onDone: () => void }) { /> ))}
- {!showAll && ctx.stock.length > 6 && ( - )} {chosen && chosen.qty < qty && ( @@ -400,8 +425,10 @@ function StockRow({ {row.size ?? row.name} - {row.suggested && ( - штатный + {(row.fits || row.suggested) && ( + + {row.fits ? "подходит" : "штатный"} + )} 0 ? "text-muted-foreground" : "text-destructive"}`}> {row.qty} шт