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

@ -9,7 +9,7 @@
>
<template #pageRow="{ row }: { row: InspectionViewModel }">
<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"
>
<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 { PencilSquareIcon } from "@heroicons/vue/24/outline";
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 lang="ts">

View file

@ -2,29 +2,45 @@
<MainTemplate>
<template #topBar>
<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>
</template>
<template #diffMain>
<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="">
<div class="flex flex-row justify-end gap-2">
<RouterLink
:to="{ name: 'admin-unit-inspection_plan' }"
primary-outline
button
class="w-fit!"
:disabled="status == 'loading' || status?.status == 'success'"
>
abbrechen
</RouterLink>
<button primary type="submit" class="w-fit!" :disabled="status == 'loading'">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>
</div>
<template #main>
<Spinner v-if="loading == 'loading'" class="mx-auto" />
<p v-else-if="loading == 'failed'">laden fehlgeschlagen</p>
<form
v-else-if="activeInspectionObj != null"
class="flex flex-col gap-4 py-2 w-full max-w-xl mx-auto"
@submit.prevent="triggerUpdate"
>
<div v-for="point in points" :key="point.title">
<OkNotOk
v-if="point.type == 'iO-niO'"
:inspectionPoint="point"
:modelValue="boolPointResult(point.id)"
@update:model-value="(val) => updateCheckResult(point.id, val)"
/>
<ResultInput
v-else
:inspectionPoint="point"
:modelValue="pointResult(point.id)"
@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>
</MainTemplate>
</template>
@ -36,22 +52,109 @@ import MainTemplate from "@/templates/Main.vue";
import Spinner from "@/components/Spinner.vue";
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
import FailureXMark from "@/components/FailureXMark.vue";
import ScanInput from "@/components/ScanInput.vue";
import InspectionPlanSearchSelect from "@/components/search/InspectionPlanSearchSelect.vue";
import EquipmentSearchSelect from "@/components/search/EquipmentSearchSelect.vue";
import VehicleSearchSelect from "@/components/search/VehicleSearchSelect.vue";
import { useInspectionStore } from "@/stores/admin/unit/inspection/inspection";
import OkNotOk from "@/components/admin/unit/inspection/OkNotOk.vue";
import ResultInput from "@/components/admin/unit/inspection/ResultInput.vue";
import type { InspectionPointResultViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models";
import cloneDeep from "lodash.clonedeep";
import isEqual from "lodash.isequal";
</script>
<script lang="ts">
export default defineComponent({
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() {
return {
loading: "loading" as "loading" | "fetched" | "failed",
status: null as null | "loading" | { status: "success" | "failed"; reason?: string },
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>

View file

@ -5,55 +5,58 @@
<h1 class="font-bold text-xl h-8">Prüfung erstellen</h1>
</div>
</template>
<template #diffMain>
<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="">
<div class="flex flex-row">
<div
v-for="tab in tabs"
:key="tab.key"
class="w-1/2 p-0.5 first:pl-0 last:pr-0 cursor-pointer"
@click="
active = tab.key;
related = '';
inspectionPlan = '';
"
<template #main>
<form class="flex flex-col gap-4 py-2 w-full max-w-xl mx-auto" @submit.prevent="">
<div class="flex flex-row">
<div
v-for="tab in tabs"
:key="tab.key"
class="w-1/2 p-0.5 first:pl-0 last:pr-0 cursor-pointer"
@click="
active = tab.key;
related = '';
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
: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',
]"
>
{{ tab.title }}
</p>
</div>
{{ tab.title }}
</p>
</div>
</div>
<EquipmentSearchSelect v-if="active == 'equipment'" title="Gerät" useScanner v-model="related" />
<VehicleSearchSelect v-else title="Fahrzeug" 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" />
<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">
<RouterLink
:to="{ name: 'admin-unit-inspection_plan' }"
primary-outline
button
class="w-fit!"
:disabled="status == 'loading' || status?.status == 'success'"
>
abbrechen
</RouterLink>
<button primary type="submit" class="w-fit!" :disabled="status == 'loading'">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>
</div>
<div>
<label for="nextInspection">Nächste Prüfung (optional) {{ " - Intervall: xx-x" }}</label>
<input id="nextInspection" type="date" />
</div>
<div class="flex flex-row justify-end gap-2">
<RouterLink
:to="{ name: 'admin-unit-inspection_plan' }"
primary-outline
button
class="w-fit!"
:disabled="status == 'loading' || status?.status == 'success'"
>
abbrechen
</RouterLink>
<button primary type="submit" class="w-fit!" :disabled="status == 'loading'">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>
</MainTemplate>
</template>

View file

@ -9,7 +9,7 @@
>
<template #pageRow="{ row }: { row: InspectionViewModel }">
<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"
>
<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 { PencilSquareIcon } from "@heroicons/vue/24/outline";
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 lang="ts">