feat(inspection): кнопка «Продолжить осмотр» на автозакрытом

Бэкенд раз в час закрывает осмотры, которые несколько часов никто не трогает,
— иначе снятые фото не попадают в отчёты. Редактирование в приложении завязано
на статус, поэтому механик, вернувшийся с перерыва, упирался бы в
заблокированную карточку и заводил осмотр заново.

На автозакрытом (meta.auto_completed) показываем плашку с объяснением и кнопку:
статус возвращается в in_progress, редактор открывается снова.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-01 12:51:35 +10:00
co-authored by Claude Opus 5
parent bbaef9bc7d
commit b7302c23d6
@@ -14,6 +14,7 @@ import { AuthImg } from "@/components/AuthImg";
import { ttImageUrl } from "@/api/vehicles"; import { ttImageUrl } from "@/api/vehicles";
import { VendorVehicleScheme } from "@/components/vehicle-scheme/VendorVehicleScheme"; import { VendorVehicleScheme } from "@/components/vehicle-scheme/VendorVehicleScheme";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { loadZoneLabels } from "@/data/zoneLabels"; import { loadZoneLabels } from "@/data/zoneLabels";
const STATUS_LABELS: Record<string, string> = { const STATUS_LABELS: Record<string, string> = {
@@ -138,6 +139,19 @@ export default function InspectionReview() {
onError: () => toast.error("Не удалось сохранить заметку"), onError: () => toast.error("Не удалось сохранить заметку"),
}); });
// Осмотр закрыт не механиком, а автоматикой — вернуть в работу и дать
// доснять. Без этой кнопки механик, вернувшийся через три часа, упирается в
// заблокированную карточку и вынужден заводить осмотр заново.
const reopenMutation = useMutation({
mutationFn: () => patchInspection(insId, { status: "in_progress" }),
onSuccess: (updated) => {
queryClient.setQueryData(["inspection", insId], updated);
queryClient.invalidateQueries({ queryKey: ["vehicle"] });
navigate(`/inspections/${insId}/edit`);
},
onError: () => toast.error("Не удалось вернуть осмотр в работу"),
});
if (isLoading) return <div className="p-8 text-muted-foreground">Загружаю</div>; if (isLoading) return <div className="p-8 text-muted-foreground">Загружаю</div>;
if (isError || !ins) if (isError || !ins)
return <div className="p-8 text-destructive">Осмотр не найден.</div>; return <div className="p-8 text-destructive">Осмотр не найден.</div>;
@@ -233,6 +247,27 @@ export default function InspectionReview() {
)} )}
</Card> </Card>
{ins.meta?.auto_completed === true && (
<Card className="p-4 space-y-3 border-amber-500/40 bg-amber-500/10">
<div className="text-sm">
<div className="font-semibold">Закрыт автоматически</div>
<p className="mt-1 text-muted-foreground leading-relaxed">
Осмотр несколько часов никто не открывал, поэтому система завершила
его сама чтобы фотографии не пропали из отчётов. Если работа не
доделана, верните осмотр в работу и продолжите.
</p>
</div>
<Button
variant="outline"
className="w-full"
onClick={() => reopenMutation.mutate()}
disabled={reopenMutation.isPending}
>
{reopenMutation.isPending ? "Открываю…" : "Продолжить осмотр"}
</Button>
</Card>
)}
<Card className="p-4 space-y-2"> <Card className="p-4 space-y-2">
<h2 className="text-sm font-semibold text-muted-foreground"> <h2 className="text-sm font-semibold text-muted-foreground">
Заметки механика Заметки механика