inspection plan execute

This commit is contained in:
Julian Krauser 2025-05-16 10:27:08 +02:00
parent b359044cb5
commit 70e9b47483
17 changed files with 429 additions and 134 deletions

View file

@ -0,0 +1,63 @@
<template>
<div class="flex flex-col h-fit w-full border border-primary rounded-md">
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
<p>{{ inspectionPoint.title }}</p>
</div>
<div class="p-2">
<p v-if="inspectionPoint.description" class="pb-2">Beschreibung: {{ inspectionPoint.description }}</p>
<hr v-if="inspectionPoint.description" />
<RadioGroup v-model="value" :name="inspectionPoint.id" class="flex flex-row gap-2">
<RadioGroupOption
v-for="option in options"
:key="option.key"
button
:primary="value == option.key"
:primary-outline="value != option.key"
:value="option.key"
>
{{ option.title }}
</RadioGroupOption>
</RadioGroup>
</div>
</div>
</template>
<script setup lang="ts">
import { defineComponent, type PropType } from "vue";
import { RadioGroup, RadioGroupLabel, RadioGroupOption } from "@headlessui/vue";
import type { InspectionPointViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models";
</script>
<script lang="ts">
export default defineComponent({
props: {
inspectionPoint: {
type: Object as PropType<InspectionPointViewModel>,
required: true,
},
modelValue: {
type: String as PropType<"true" | "false">,
default: "false",
},
},
emits: ["update:model-value"],
data() {
return {
options: [
{ key: "true", title: "OK" },
{ key: "false", title: "nicht OK" },
],
};
},
computed: {
value: {
get() {
return this.modelValue;
},
set(val: string) {
this.$emit("update:model-value", val);
},
},
},
});
</script>

View file

@ -0,0 +1,52 @@
<template>
<div class="flex flex-col h-fit w-full border border-primary rounded-md">
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
<p>{{ inspectionPoint.title }}</p>
</div>
<div class="p-2">
<p v-if="inspectionPoint.description" class="pb-2">Beschreibung: {{ inspectionPoint.description }}</p>
<hr v-if="inspectionPoint.description" />
<label :for="inspectionPoint.id">{{ inspectionPoint.type == "number" ? "Zahl" : "Freitext" }}</label>
<input
v-if="inspectionPoint.type == 'number'"
:id="inspectionPoint.id"
:name="inspectionPoint.id"
type="number"
required
v-model="value"
/>
<textarea v-else :id="inspectionPoint.id" :name="inspectionPoint.id" required class="h-18" v-model="value" />
</div>
</div>
</template>
<script setup lang="ts">
import { defineComponent, type PropType } from "vue";
import type { InspectionPointViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models";
</script>
<script lang="ts">
export default defineComponent({
props: {
inspectionPoint: {
type: Object as PropType<InspectionPointViewModel>,
required: true,
},
modelValue: {
type: String,
default: "",
},
},
emits: ["update:model-value"],
computed: {
value: {
get() {
return this.modelValue;
},
set(val: string | number) {
this.$emit("update:model-value", val.toString());
},
},
},
});
</script>

View file

@ -1,10 +1,9 @@
import type { InspectionPlanViewModel } from "@/viewmodels/admin/unit/inspectionPlan/inspectionPlan.models";
import type { import type {
InspectionPlanViewModel,
InspectionPointResultViewModel,
InspectionPointViewModel, InspectionPointViewModel,
InspectionPointResultViewModel,
InspectionViewModel, InspectionViewModel,
} from "@/viewmodels/admin/unit/inspectionPlan/inspectionPlan.models"; } from "@/viewmodels/admin/unit/inspection/inspection.models";
import { equipmentTypeDemoData } from "./equipmentType";
export const inspectionPointDemoData: Array<InspectionPointViewModel> = [ export const inspectionPointDemoData: Array<InspectionPointViewModel> = [
{ {
@ -72,25 +71,19 @@ export const inspectionPointResultDemoData: Array<InspectionPointResultViewModel
{ {
inspectionId: "jkvshdfg", inspectionId: "jkvshdfg",
inspectionVersionedPlanId: inspectionPlanDemoData[0].id, inspectionVersionedPlanId: inspectionPlanDemoData[0].id,
inspectionVersionedPlan: inspectionPlanDemoData[0],
inspectionPointId: inspectionPointDemoData[0].id, inspectionPointId: inspectionPointDemoData[0].id,
inspectionPoint: inspectionPointDemoData[0], value: "5",
},
{
inspectionId: "jkvshdfg",
inspectionVersionedPlanId: inspectionPlanDemoData[0].id,
inspectionPointId: inspectionPointDemoData[1].id,
value: "", value: "",
}, },
{ {
inspectionId: "jkvshdfg", inspectionId: "jkvshdfg",
inspectionVersionedPlanId: inspectionPlanDemoData[0].id, inspectionVersionedPlanId: inspectionPlanDemoData[0].id,
inspectionVersionedPlan: inspectionPlanDemoData[0],
inspectionPointId: inspectionPointDemoData[1].id, inspectionPointId: inspectionPointDemoData[1].id,
inspectionPoint: inspectionPointDemoData[1],
value: "",
},
{
inspectionId: "jkvshdfg",
inspectionVersionedPlanId: inspectionPlanDemoData[0].id,
inspectionVersionedPlan: inspectionPlanDemoData[0],
inspectionPointId: inspectionPointDemoData[1].id,
inspectionPoint: inspectionPointDemoData[1],
value: "", value: "",
}, },
]; ];

View file

@ -68,23 +68,23 @@ body {
/*:not([headlessui]):not([id*="headlessui"]):not([class*="headlessui"])*/ /*:not([headlessui]):not([id*="headlessui"]):not([class*="headlessui"])*/
button:not([class*="ql"] *):not([class*="fc"]):not([id*="headlessui-combobox"]), button:not([class*="ql"] *):not([class*="fc"]):not([id*="headlessui-combobox"]),
a[button] { [button] {
@apply cursor-pointer relative box-border h-10 w-full flex justify-center py-2 px-4 text-sm font-medium rounded-md focus:outline-hidden focus:ring-0; @apply cursor-pointer relative box-border h-10 w-full flex justify-center py-2 px-4 text-sm font-medium rounded-md focus:outline-hidden focus:ring-0;
} }
button[primary]:not([primary="false"]), button[primary]:not([primary="false"]),
a[button][primary]:not([primary="false"]) { [button][primary]:not([primary="false"]) {
@apply border-2 border-transparent text-white bg-primary hover:bg-primary; @apply border-2 border-transparent text-white bg-primary hover:bg-primary;
} }
button[primary-outline]:not([primary-outline="false"]), button[primary-outline]:not([primary-outline="false"]),
a[button][primary-outline]:not([primary-outline="false"]) { [button][primary-outline]:not([primary-outline="false"]) {
@apply border-2 border-primary text-black hover:bg-primary; @apply border-2 border-primary text-black hover:bg-primary;
} }
button:disabled, button:disabled,
a[button]:disabled, [button]:disabled,
a[button].disabled { [button].disabled {
@apply opacity-75 pointer-events-none; @apply opacity-75 pointer-events-none;
} }

View file

@ -18,6 +18,7 @@ import { resetRespiratoryMissionStores, setRespiratoryMissionId } from "./unit/r
import { resetWearableStores, setWearableId } from "./unit/wearable"; import { resetWearableStores, setWearableId } from "./unit/wearable";
import { resetInspectionPlanStores, setInspectionPlanId } from "./unit/inspectionPlan"; import { resetInspectionPlanStores, setInspectionPlanId } from "./unit/inspectionPlan";
import { setVehicleTypeId } from "./unit/vehicleType"; import { setVehicleTypeId } from "./unit/vehicleType";
import { resetInspectionStores, setInspectionId } from "./unit/inspection";
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
@ -860,7 +861,7 @@ const router = createRouter({
name: "admin-unit-inspection-route", name: "admin-unit-inspection-route",
component: () => import("@/views/RouterView.vue"), component: () => import("@/views/RouterView.vue"),
meta: { type: "create", section: "unit", module: "inspection" }, meta: { type: "create", section: "unit", module: "inspection" },
beforeEnter: [abilityAndNavUpdate], beforeEnter: [abilityAndNavUpdate, resetInspectionStores],
children: [ children: [
{ {
path: "", path: "",
@ -875,10 +876,10 @@ const router = createRouter({
props: true, props: true,
}, },
{ {
path: "execute/:inspection", path: "execute/:inspectionId",
name: "admin-unit-inspection-execute", name: "admin-unit-inspection-execute",
component: () => import("@/views/admin/unit/inspection/InspectionExecute.vue"), component: () => import("@/views/admin/unit/inspection/InspectionExecute.vue"),
beforeEnter: [], beforeEnter: [setInspectionId],
props: true, props: true,
}, },
], ],

View file

@ -0,0 +1,20 @@
import { useInspectionStore } from "@/stores/admin/unit/inspection/inspection";
export async function setInspectionId(to: any, from: any, next: any) {
const InspectionStore = useInspectionStore();
InspectionStore.activeInspection = to.params?.inspectionId ?? null;
//useXYStore().$reset();
next();
}
export async function resetInspectionStores(to: any, from: any, next: any) {
const InspectionStore = useInspectionStore();
InspectionStore.activeInspection = null;
InspectionStore.activeInspectionObj = null;
//useXYStore().$reset();
next();
}

View file

@ -1,6 +1,6 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { http } from "@/serverCom"; import { http } from "@/serverCom";
import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspectionPlan/inspectionPlan.models"; import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models";
import { inspectionDemoData } from "@/demodata/inspectionPlan"; import { inspectionDemoData } from "@/demodata/inspectionPlan";
import { useEquipmentStore } from "./equipment"; import { useEquipmentStore } from "./equipment";

View file

@ -0,0 +1,55 @@
import { defineStore } from "pinia";
import { http } from "@/serverCom";
import type { AxiosResponse } from "axios";
import { inspectionDemoData } from "@/demodata/inspectionPlan";
import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models";
export const useInspectionStore = defineStore("inspection", {
state: () => {
return {
activeInspection: null as string | null,
activeInspectionObj: null as InspectionViewModel | null,
loadingActive: "loading" as "loading" | "fetched" | "failed",
};
},
actions: {
fetchInspectionByActiveId() {
this.loadingActive = "loading";
this.activeInspectionObj = inspectionDemoData.find((e) => e.id == this.activeInspection) as InspectionViewModel;
this.loadingActive = "fetched";
return;
this.loadingActive = "loading";
http
.get(`/admin/inspection/${this.activeInspection}`)
.then((res) => {
this.activeInspectionObj = res.data;
this.loadingActive = "fetched";
})
.catch((err) => {
this.loadingActive = "failed";
});
},
fetchInspectionById(id: string) {
return http.get(`/admin/inspection/${id}`);
},
async createInspection(inspection: any): Promise<AxiosResponse<any, any>> {
const result = await http.post(`/admin/inspection`, {
// TODO: data
});
this.fetchInspectionByActiveId();
return result;
},
async updateActiveInspection(inspection: any): Promise<AxiosResponse<any, any>> {
const result = await http.patch(`/admin/inspection/${inspection.id}`, {
// TODO: data
});
this.fetchInspectionByActiveId();
return result;
},
async deleteInspection(inspection: number): Promise<AxiosResponse<any, any>> {
const result = await http.delete(`/admin/inspection/${inspection}`);
this.fetchInspectionByActiveId();
return result;
},
},
});

View file

@ -1,6 +1,6 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { http } from "@/serverCom"; import { http } from "@/serverCom";
import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspectionPlan/inspectionPlan.models"; import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models";
import { inspectionDemoData } from "@/demodata/inspectionPlan"; import { inspectionDemoData } from "@/demodata/inspectionPlan";
import { useVehicleStore } from "./vehicle"; import { useVehicleStore } from "./vehicle";

View file

@ -1,5 +1,5 @@
import type { EquipmentTypeViewModel } from "../equipmentType/equipmentType.models"; import type { EquipmentTypeViewModel } from "../equipmentType/equipmentType.models";
import type { InspectionViewModel } from "../inspectionPlan/inspectionPlan.models"; import type { InspectionViewModel } from "../inspection/inspection.models";
export interface EquipmentViewModel { export interface EquipmentViewModel {
id: string; id: string;

View file

@ -0,0 +1,36 @@
import type { EquipmentViewModel } from "../equipment/equipment.models";
import type {
InspectionPlanViewModel,
InspectionVersionedPlanViewModel,
} from "../inspectionPlan/inspectionPlan.models";
import type { VehicleViewModel } from "../vehicle/vehicle.models";
export interface InspectionViewModel {
id: string;
inspectionPlanId: string;
inspectionPlan: InspectionPlanViewModel;
inspectionVersionedPlanId: string;
inspectionVersionedPlan: InspectionVersionedPlanViewModel;
context: string;
created: Date;
finished?: Date;
isOpen: boolean;
nextInspection?: Date;
checks: Array<InspectionPointResultViewModel>;
relatedId: string;
related: EquipmentViewModel | VehicleViewModel;
}
export interface InspectionPointViewModel {
id: string;
title: string;
description: string;
type: "iO-niO" | "text" | "number";
}
export interface InspectionPointResultViewModel {
inspectionId: string;
inspectionVersionedPlanId: string;
inspectionPointId: string;
value: string;
}

View file

@ -1,5 +1,6 @@
import type { EquipmentViewModel } from "../equipment/equipment.models"; import type { EquipmentViewModel } from "../equipment/equipment.models";
import type { EquipmentTypeViewModel } from "../equipmentType/equipmentType.models"; import type { EquipmentTypeViewModel } from "../equipmentType/equipmentType.models";
import type { InspectionPointViewModel } from "../inspection/inspection.models";
import type { VehicleViewModel } from "../vehicle/vehicle.models"; import type { VehicleViewModel } from "../vehicle/vehicle.models";
import type { VehicleTypeViewModel } from "../vehicleType/vehicleType.models"; import type { VehicleTypeViewModel } from "../vehicleType/vehicleType.models";
@ -38,35 +39,3 @@ export interface UpdateInspectionPlanViewModel {
inspectionInterval: PlanTimeDefinition; inspectionInterval: PlanTimeDefinition;
remindTime?: PlanTimeDefinition; remindTime?: PlanTimeDefinition;
} }
export interface InspectionPointViewModel {
id: string;
title: string;
description: string;
type: "iO-niO" | "text" | "number";
}
export interface InspectionViewModel {
id: string;
inspectionPlanId: string;
inspectionPlan: InspectionPlanViewModel;
inspectionVersionedPlanId: string;
inspectionVersionedPlan: InspectionVersionedPlanViewModel;
context: string;
created: Date;
finished?: Date;
isOpen: boolean;
nextInspection?: Date;
checks: Array<InspectionPointResultViewModel>;
relatedId: string;
related: EquipmentViewModel | VehicleViewModel;
}
export interface InspectionPointResultViewModel {
inspectionId: string;
inspectionVersionedPlanId: string;
inspectionVersionedPlan: InspectionVersionedPlanViewModel;
inspectionPointId: string;
inspectionPoint: InspectionPointViewModel;
value: string;
}

View file

@ -1,4 +1,4 @@
import type { InspectionViewModel } from "../inspectionPlan/inspectionPlan.models"; import type { InspectionViewModel } from "../inspection/inspection.models";
import type { VehicleTypeViewModel } from "../vehicleType/vehicleType.models"; import type { VehicleTypeViewModel } from "../vehicleType/vehicleType.models";
export interface VehicleViewModel { export interface VehicleViewModel {

View file

@ -9,7 +9,7 @@
> >
<template #pageRow="{ row }: { row: InspectionViewModel }"> <template #pageRow="{ row }: { row: InspectionViewModel }">
<RouterLink <RouterLink
:to="{ name: 'admin-unit-inspection-execute', params: { inspection: row.id } }" :to="{ name: 'admin-unit-inspection-execute', params: { inspectionId: row.id } }"
class="flex flex-col h-fit w-full border border-primary rounded-md" class="flex flex-col h-fit w-full border border-primary rounded-md"
> >
<div class="bg-primary p-2 text-white flex flex-row gap-2 items-center"> <div class="bg-primary p-2 text-white flex flex-row gap-2 items-center">
@ -44,7 +44,7 @@ import { useAbilityStore } from "@/stores/ability";
import { useEquipmentInspectionStore } from "@/stores/admin/unit/equipment/inspection"; import { useEquipmentInspectionStore } from "@/stores/admin/unit/equipment/inspection";
import { PencilSquareIcon } from "@heroicons/vue/24/outline"; import { PencilSquareIcon } from "@heroicons/vue/24/outline";
import Pagination from "@/components/Pagination.vue"; import Pagination from "@/components/Pagination.vue";
import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspectionPlan/inspectionPlan.models"; import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models";
</script> </script>
<script lang="ts"> <script lang="ts">

View file

@ -2,29 +2,45 @@
<MainTemplate> <MainTemplate>
<template #topBar> <template #topBar>
<div class="flex flex-row items-center justify-between pt-5 pb-3 px-7"> <div class="flex flex-row items-center justify-between pt-5 pb-3 px-7">
<h1 class="font-bold text-xl h-8">Prüfung durchführen</h1> <h1 class="font-bold text-xl min-h-8">
Prüfung durchführen: {{ activeInspectionObj?.related.name }} - {{ activeInspectionObj?.inspectionPlan.title }}
</h1>
</div> </div>
</template> </template>
<template #diffMain> <template #main>
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto"> <Spinner v-if="loading == 'loading'" class="mx-auto" />
<form class="flex flex-col gap-4 py-2 w-full max-w-xl mx-auto" @submit.prevent=""> <p v-else-if="loading == 'failed'">laden fehlgeschlagen</p>
<div class="flex flex-row justify-end gap-2"> <form
<RouterLink v-else-if="activeInspectionObj != null"
:to="{ name: 'admin-unit-inspection_plan' }" class="flex flex-col gap-4 py-2 w-full max-w-xl mx-auto"
primary-outline @submit.prevent="triggerUpdate"
button >
class="w-fit!" <div v-for="point in points" :key="point.title">
:disabled="status == 'loading' || status?.status == 'success'" <OkNotOk
> v-if="point.type == 'iO-niO'"
abbrechen :inspectionPoint="point"
</RouterLink> :modelValue="boolPointResult(point.id)"
<button primary type="submit" class="w-fit!" :disabled="status == 'loading'">speichern</button> @update:model-value="(val) => updateCheckResult(point.id, val)"
<Spinner v-if="status == 'loading'" class="my-auto" /> />
<SuccessCheckmark v-else-if="status?.status == 'success'" /> <ResultInput
<FailureXMark v-else-if="status?.status == 'failed'" /> v-else
</div> :inspectionPoint="point"
</form> :modelValue="pointResult(point.id)"
</div> @update:model-value="(val) => updateCheckResult(point.id, val)"
/>
</div>
<div class="flex flex-row justify-end gap-2">
<button primary-outline type="reset" class="w-fit!" :disabled="canSaveOrReset" @click="resetForm">
verwerfen
</button>
<button primary type="submit" class="w-fit!" :disabled="status == 'loading' || canSaveOrReset">
speichern
</button>
<Spinner v-if="status == 'loading'" class="my-auto" />
<SuccessCheckmark v-else-if="status?.status == 'success'" />
<FailureXMark v-else-if="status?.status == 'failed'" />
</div>
</form>
</template> </template>
</MainTemplate> </MainTemplate>
</template> </template>
@ -36,22 +52,109 @@ import MainTemplate from "@/templates/Main.vue";
import Spinner from "@/components/Spinner.vue"; import Spinner from "@/components/Spinner.vue";
import SuccessCheckmark from "@/components/SuccessCheckmark.vue"; import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
import FailureXMark from "@/components/FailureXMark.vue"; import FailureXMark from "@/components/FailureXMark.vue";
import ScanInput from "@/components/ScanInput.vue"; import { useInspectionStore } from "@/stores/admin/unit/inspection/inspection";
import InspectionPlanSearchSelect from "@/components/search/InspectionPlanSearchSelect.vue"; import OkNotOk from "@/components/admin/unit/inspection/OkNotOk.vue";
import EquipmentSearchSelect from "@/components/search/EquipmentSearchSelect.vue"; import ResultInput from "@/components/admin/unit/inspection/ResultInput.vue";
import VehicleSearchSelect from "@/components/search/VehicleSearchSelect.vue"; import type { InspectionPointResultViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models";
import cloneDeep from "lodash.clonedeep";
import isEqual from "lodash.isequal";
</script> </script>
<script lang="ts"> <script lang="ts">
export default defineComponent({ export default defineComponent({
props: { props: {
inspection: String, inspectionId: String,
},
watch: {
loadingActive() {
if (this.loading == "loading") {
this.loading = this.loadingActive;
}
if (this.loadingActive == "fetched") {
this.checks = cloneDeep(this.activeInspectionObj?.checks ?? []);
}
},
}, },
data() { data() {
return { return {
loading: "loading" as "loading" | "fetched" | "failed",
status: null as null | "loading" | { status: "success" | "failed"; reason?: string }, status: null as null | "loading" | { status: "success" | "failed"; reason?: string },
timeout: null as any, timeout: null as any,
checks: [] as Array<InspectionPointResultViewModel>,
}; };
}, },
computed: {
canSaveOrReset(): boolean {
return isEqual(
(this.activeInspectionObj?.checks || []).sort((a, b) => a.inspectionPointId.localeCompare(b.inspectionPointId)),
this.checks.sort((a, b) => a.inspectionPointId.localeCompare(b.inspectionPointId))
);
},
...mapState(useInspectionStore, ["activeInspectionObj", "loadingActive"]),
points() {
return this.activeInspectionObj?.inspectionVersionedPlan.inspectionPoints ?? [];
},
pointResult() {
return (pointId: string) => {
return this.checks.find((c) => c.inspectionPointId == pointId)?.value ?? "";
};
},
boolPointResult() {
return (pointId: string): "true" | "false" => {
return this.pointResult(pointId) == "true" ? "true" : "false";
};
},
},
mounted() {
this.fetchItem();
},
beforeUnmount() {
try {
clearTimeout(this.timeout);
} catch (error) {}
},
methods: {
...mapActions(useInspectionStore, ["fetchInspectionByActiveId"]),
resetForm() {
this.checks = cloneDeep(this.activeInspectionObj?.checks ?? []);
},
fetchItem() {
this.fetchInspectionByActiveId();
},
updateCheckResult(id: string, value: string) {
if (this.activeInspectionObj == null) return;
let index = this.checks.findIndex((c) => c.inspectionPointId == id);
if (index == -1) {
this.checks.push({
inspectionId: this.activeInspectionObj.id,
inspectionVersionedPlanId: this.activeInspectionObj.inspectionVersionedPlanId,
inspectionPointId: id,
value: value,
});
} else {
this.checks[index].value = value;
}
},
triggerUpdate(e: any) {
if (this.activeInspectionObj == null) return;
this.status = "loading";
new Promise<void>((resolve, reject) => {
resolve();
})
.then(() => {
this.fetchItem();
this.status = { status: "success" };
})
.catch((err) => {
this.status = { status: "failed" };
})
.finally(() => {
this.timeout = setTimeout(() => {
this.status = null;
}, 2000);
});
},
},
}); });
</script> </script>

View file

@ -5,55 +5,58 @@
<h1 class="font-bold text-xl h-8">Prüfung erstellen</h1> <h1 class="font-bold text-xl h-8">Prüfung erstellen</h1>
</div> </div>
</template> </template>
<template #diffMain> <template #main>
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto"> <form class="flex flex-col gap-4 py-2 w-full max-w-xl mx-auto" @submit.prevent="">
<form class="flex flex-col gap-4 py-2 w-full max-w-xl mx-auto" @submit.prevent=""> <div class="flex flex-row">
<div class="flex flex-row"> <div
<div v-for="tab in tabs"
v-for="tab in tabs" :key="tab.key"
:key="tab.key" class="w-1/2 p-0.5 first:pl-0 last:pr-0 cursor-pointer"
class="w-1/2 p-0.5 first:pl-0 last:pr-0 cursor-pointer" @click="
@click=" active = tab.key;
active = tab.key; related = '';
related = ''; inspectionPlan = '';
inspectionPlan = ''; "
" >
<p
:class="[
'w-full rounded-lg py-2.5 text-sm text-center font-medium leading-5 focus:ring-0 outline-hidden',
tab.key == active
? 'bg-red-200 shadow-sm border-b-2 border-primary rounded-b-none'
: ' hover:bg-red-200',
]"
> >
<p {{ tab.title }}
:class="[ </p>
'w-full rounded-lg py-2.5 text-sm text-center font-medium leading-5 focus:ring-0 outline-hidden',
tab.key == active
? 'bg-red-200 shadow-sm border-b-2 border-primary rounded-b-none'
: ' hover:bg-red-200',
]"
>
{{ tab.title }}
</p>
</div>
</div> </div>
</div>
<EquipmentSearchSelect v-if="active == 'equipment'" title="Gerät" useScanner v-model="related" /> <EquipmentSearchSelect v-if="active == 'equipment'" title="Gerät" useScanner v-model="related" />
<VehicleSearchSelect v-else title="Fahrzeug" useScanner v-model="related" /> <VehicleSearchSelect v-else title="Fahrzeug" useScanner v-model="related" />
<InspectionPlanSearchSelect title="Prüfplan" :type="active" v-model="inspectionPlan" /> <InspectionPlanSearchSelect title="Prüfplan" :type="active" v-model="inspectionPlan" />
<div class="flex flex-row justify-end gap-2"> <div>
<RouterLink <label for="nextInspection">Nächste Prüfung (optional) {{ " - Intervall: xx-x" }}</label>
:to="{ name: 'admin-unit-inspection_plan' }" <input id="nextInspection" type="date" />
primary-outline </div>
button
class="w-fit!" <div class="flex flex-row justify-end gap-2">
:disabled="status == 'loading' || status?.status == 'success'" <RouterLink
> :to="{ name: 'admin-unit-inspection_plan' }"
abbrechen primary-outline
</RouterLink> button
<button primary type="submit" class="w-fit!" :disabled="status == 'loading'">speichern</button> class="w-fit!"
<Spinner v-if="status == 'loading'" class="my-auto" /> :disabled="status == 'loading' || status?.status == 'success'"
<SuccessCheckmark v-else-if="status?.status == 'success'" /> >
<FailureXMark v-else-if="status?.status == 'failed'" /> abbrechen
</div> </RouterLink>
</form> <button primary type="submit" class="w-fit!" :disabled="status == 'loading'">speichern</button>
</div> <Spinner v-if="status == 'loading'" class="my-auto" />
<SuccessCheckmark v-else-if="status?.status == 'success'" />
<FailureXMark v-else-if="status?.status == 'failed'" />
</div>
</form>
</template> </template>
</MainTemplate> </MainTemplate>
</template> </template>

View file

@ -9,7 +9,7 @@
> >
<template #pageRow="{ row }: { row: InspectionViewModel }"> <template #pageRow="{ row }: { row: InspectionViewModel }">
<RouterLink <RouterLink
:to="{ name: 'admin-unit-inspection-execute', params: { inspection: row.id } }" :to="{ name: 'admin-unit-inspection-execute', params: { inspectionId: row.id } }"
class="flex flex-col h-fit w-full border border-primary rounded-md" class="flex flex-col h-fit w-full border border-primary rounded-md"
> >
<div class="bg-primary p-2 text-white flex flex-row gap-2 items-center"> <div class="bg-primary p-2 text-white flex flex-row gap-2 items-center">
@ -44,7 +44,7 @@ import { useAbilityStore } from "@/stores/ability";
import { useVehicleInspectionStore } from "@/stores/admin/unit/vehicle/inspection"; import { useVehicleInspectionStore } from "@/stores/admin/unit/vehicle/inspection";
import { PencilSquareIcon } from "@heroicons/vue/24/outline"; import { PencilSquareIcon } from "@heroicons/vue/24/outline";
import Pagination from "@/components/Pagination.vue"; import Pagination from "@/components/Pagination.vue";
import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspectionPlan/inspectionPlan.models"; import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models";
</script> </script>
<script lang="ts"> <script lang="ts">