unit/#103-base-management #110
19 changed files with 457 additions and 25 deletions
|
@ -14,6 +14,8 @@
|
||||||
type="number"
|
type="number"
|
||||||
required
|
required
|
||||||
v-model="value"
|
v-model="value"
|
||||||
|
:min="inspectionPoint.min"
|
||||||
|
:max="inspectionPoint.max"
|
||||||
/>
|
/>
|
||||||
<textarea v-else :id="inspectionPoint.id" :name="inspectionPoint.id" required class="h-18" v-model="value" />
|
<textarea v-else :id="inspectionPoint.id" :name="inspectionPoint.id" required class="h-18" v-model="value" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
<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 gap-2">
|
||||||
|
<ClipboardDocumentCheckIcon v-if="modelValue.type == InspectionPointEnum.oknok" class="w-6 h-6" />
|
||||||
|
<CalculatorIcon v-else-if="modelValue.type == InspectionPointEnum.number" class="w-6 h-6" />
|
||||||
|
<BoldIcon v-else-if="modelValue.type == InspectionPointEnum.text" class="w-6 h-6" />
|
||||||
|
<DocumentIcon v-else-if="modelValue.type == InspectionPointEnum.file" class="w-6 h-6" />
|
||||||
|
|
||||||
|
<input type="text" placeholder="Titel" v-model="title" />
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<ChevronUpIcon v-if="index != 0" class="text-white w-4 h-4 stroke-2 cursor-pointer" @click="$emit('up')" />
|
||||||
|
<ChevronDownIcon
|
||||||
|
v-if="index != totalCount - 1"
|
||||||
|
class="text-white w-4 h-4 stroke-2 cursor-pointer"
|
||||||
|
@click="$emit('down')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<TrashIcon class="h-5 w-5 cursor-pointer" @click="$emit('remove')" />
|
||||||
|
</div>
|
||||||
|
<div class="p-2">
|
||||||
|
<textarea name="description" placeholder="Beschreibung" v-model="description"></textarea>
|
||||||
|
<div v-if="modelValue.type == InspectionPointEnum.number">
|
||||||
|
<label for="min">Mindestens</label>
|
||||||
|
<input type="number" v-model="min" min="0" />
|
||||||
|
</div>
|
||||||
|
<div v-if="modelValue.type == InspectionPointEnum.number">
|
||||||
|
<label for="max">Maximal</label>
|
||||||
|
<input type="number" v-model="max" min="0" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineComponent, type PropType } from "vue";
|
||||||
|
import type { InspectionPointViewModel } from "@/viewmodels/admin/unit/inspection/inspectionPlan.models";
|
||||||
|
import { InspectionPointEnum } from "@/enums/inspectionEnum";
|
||||||
|
import {
|
||||||
|
BoldIcon,
|
||||||
|
CalculatorIcon,
|
||||||
|
ClipboardDocumentCheckIcon,
|
||||||
|
TrashIcon,
|
||||||
|
ChevronUpIcon,
|
||||||
|
ChevronDownIcon,
|
||||||
|
DocumentIcon,
|
||||||
|
} from "@heroicons/vue/24/outline";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
index: { type: Number, default: 0 },
|
||||||
|
totalCount: { type: Number, default: 0 },
|
||||||
|
modelValue: {
|
||||||
|
type: Object as PropType<InspectionPointViewModel>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ["up", "down", "remove", "update:model-value"],
|
||||||
|
computed: {
|
||||||
|
title: {
|
||||||
|
get() {
|
||||||
|
return this.modelValue.title;
|
||||||
|
},
|
||||||
|
set(val: InspectionPointViewModel) {
|
||||||
|
this.$emit("update:model-value", { ...this.modelValue, title: val });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
get() {
|
||||||
|
return this.modelValue.description;
|
||||||
|
},
|
||||||
|
set(val: InspectionPointViewModel) {
|
||||||
|
this.$emit("update:model-value", { ...this.modelValue, description: val });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
min: {
|
||||||
|
get() {
|
||||||
|
return this.modelValue.min;
|
||||||
|
},
|
||||||
|
set(val: InspectionPointViewModel) {
|
||||||
|
this.$emit("update:model-value", { ...this.modelValue, min: val });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
get() {
|
||||||
|
return this.modelValue.max;
|
||||||
|
},
|
||||||
|
set(val: InspectionPointViewModel) {
|
||||||
|
this.$emit("update:model-value", { ...this.modelValue, max: val });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -6,6 +6,9 @@
|
||||||
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
|
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
|
||||||
<p>{{ vehicle.name }}</p>
|
<p>{{ vehicle.name }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="p-2">
|
||||||
|
<p v-if="vehicle.code">Code: {{ vehicle.code }}</p>
|
||||||
|
</div>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -2,4 +2,5 @@ export enum InspectionPointEnum {
|
||||||
oknok = "oknok",
|
oknok = "oknok",
|
||||||
text = "text",
|
text = "text",
|
||||||
number = "number",
|
number = "number",
|
||||||
|
file = "file",
|
||||||
}
|
}
|
||||||
|
|
|
@ -898,7 +898,15 @@ const router = createRouter({
|
||||||
{
|
{
|
||||||
path: "edit",
|
path: "edit",
|
||||||
name: "admin-unit-inspection_plan-edit",
|
name: "admin-unit-inspection_plan-edit",
|
||||||
component: () => import("@/views/admin/ViewSelect.vue"),
|
component: () => import("@/views/admin/unit/inspectionPlan/UpdateInspectionPlan.vue"),
|
||||||
|
meta: { type: "update", section: "unit", module: "inspection_plan" },
|
||||||
|
beforeEnter: [abilityAndNavUpdate],
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "pointedit",
|
||||||
|
name: "admin-unit-inspection_plan-pointedit",
|
||||||
|
component: () => import("@/views/admin/unit/inspectionPlan/UpdateInspectionPlanPoints.vue"),
|
||||||
meta: { type: "update", section: "unit", module: "inspection_plan" },
|
meta: { type: "update", section: "unit", module: "inspection_plan" },
|
||||||
beforeEnter: [abilityAndNavUpdate],
|
beforeEnter: [abilityAndNavUpdate],
|
||||||
props: true,
|
props: true,
|
||||||
|
@ -916,13 +924,25 @@ const router = createRouter({
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "",
|
path: "",
|
||||||
|
name: "admin-unit-inspection-routing",
|
||||||
|
component: () => import("@/views/admin/unit/inspection/InspectionRouting.vue"),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "next",
|
||||||
name: "admin-unit-inspection",
|
name: "admin-unit-inspection",
|
||||||
redirect: { name: "admin-unit-inspection-plan" },
|
component: () => import("@/views/admin/unit/inspection/NextInspection.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "plan/:type?/:relatedId?/:inspectionPlanId?",
|
path: "running",
|
||||||
name: "admin-unit-inspection-plan",
|
name: "admin-unit-inspection-running",
|
||||||
component: () => import("@/views/admin/unit/inspection/InspectionPlan.vue"),
|
component: () => import("@/views/admin/unit/inspection/NextInspection.vue"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "start/:type?/:relatedId?/:inspectionPlanId?",
|
||||||
|
name: "admin-unit-inspection-start",
|
||||||
|
component: () => import("@/views/admin/unit/inspection/InspectionStart.vue"),
|
||||||
beforeEnter: [],
|
beforeEnter: [],
|
||||||
props: true,
|
props: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -110,13 +110,13 @@ export const useNavigationStore = defineStore("navigation", {
|
||||||
...(abilityStore.can("read", "unit", "equipment") ? [{ key: "equipment", title: "Gerätschaften" }] : []),
|
...(abilityStore.can("read", "unit", "equipment") ? [{ key: "equipment", title: "Gerätschaften" }] : []),
|
||||||
...(abilityStore.can("read", "unit", "vehicle") ? [{ key: "vehicle", title: "Fahrzeuge" }] : []),
|
...(abilityStore.can("read", "unit", "vehicle") ? [{ key: "vehicle", title: "Fahrzeuge" }] : []),
|
||||||
...(abilityStore.can("read", "unit", "wearable") ? [{ key: "wearable", title: "Kleidung" }] : []),
|
...(abilityStore.can("read", "unit", "wearable") ? [{ key: "wearable", title: "Kleidung" }] : []),
|
||||||
...(abilityStore.can("read", "unit", "respiratory_gear")
|
...(false && abilityStore.can("read", "unit", "respiratory_gear")
|
||||||
? [{ key: "respiratory_gear", title: "Atemschutz-Geräte" }]
|
? [{ key: "respiratory_gear", title: "Atemschutz-Geräte" }]
|
||||||
: []),
|
: []),
|
||||||
...(abilityStore.can("read", "unit", "respiratory_wearer")
|
...(false && abilityStore.can("read", "unit", "respiratory_wearer")
|
||||||
? [{ key: "respiratory_wearer", title: "Atemschutz-Träger" }]
|
? [{ key: "respiratory_wearer", title: "Atemschutz-Träger" }]
|
||||||
: []),
|
: []),
|
||||||
...(abilityStore.can("read", "unit", "respiratory_mission")
|
...(false && abilityStore.can("read", "unit", "respiratory_mission")
|
||||||
? [{ key: "respiratory_mission", title: "Atemschutz-Einsätze" }]
|
? [{ key: "respiratory_mission", title: "Atemschutz-Einsätze" }]
|
||||||
: []),
|
: []),
|
||||||
...(abilityStore.can("create", "unit", "inspection") ? [{ key: "inspection", title: "Prüfungen" }] : []),
|
...(abilityStore.can("create", "unit", "inspection") ? [{ key: "inspection", title: "Prüfungen" }] : []),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col w-full h-full gap-2 justify-center px-7">
|
<div class="flex flex-col w-full h-full gap-2 justify-center">
|
||||||
<Pagination
|
<Pagination
|
||||||
:items="damageReports"
|
:items="damageReports"
|
||||||
:totalCount="totalCount"
|
:totalCount="totalCount"
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<div class="flex flex-row gap-4">
|
<div class="flex flex-row gap-4">
|
||||||
<RouterLink
|
<RouterLink
|
||||||
v-if="can('create', 'unit', 'equipment')"
|
v-if="can('create', 'unit', 'equipment')"
|
||||||
:to="{ name: 'admin-unit-inspection-plan', params: { type: 'equipment', relatedId: equipmentId } }"
|
:to="{ name: 'admin-unit-inspection-start', params: { type: 'equipment', relatedId: equipmentId } }"
|
||||||
button
|
button
|
||||||
primary
|
primary
|
||||||
class="w-fit!"
|
class="w-fit!"
|
||||||
|
|
54
src/views/admin/unit/inspection/InspectionRouting.vue
Normal file
54
src/views/admin/unit/inspection/InspectionRouting.vue
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<template>
|
||||||
|
<MainTemplate title="Prüfungen">
|
||||||
|
<template #diffMain>
|
||||||
|
<div class="flex flex-col gap-2 grow px-7 overflow-hidden">
|
||||||
|
<div class="flex flex-col grow gap-2 overflow-hidden">
|
||||||
|
<div class="w-full flex flex-row max-lg:flex-wrap justify-center">
|
||||||
|
<RouterLink
|
||||||
|
v-for="tab in tabs"
|
||||||
|
:key="tab.route"
|
||||||
|
v-slot="{ isExactActive }"
|
||||||
|
:to="{ name: tab.route }"
|
||||||
|
class="w-1/2 md:w-1/3 lg:w-full p-0.5 first:pl-0 last:pr-0"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
:class="[
|
||||||
|
'w-full rounded-lg py-2.5 text-sm text-center font-medium leading-5 focus:ring-0 outline-hidden',
|
||||||
|
isExactActive ? 'bg-red-200 shadow-sm border-b-2 border-primary rounded-b-none' : ' hover:bg-red-200',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
{{ tab.title }}
|
||||||
|
</p>
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
<RouterView />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MainTemplate>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import { mapActions, mapState } from "pinia";
|
||||||
|
import MainTemplate from "@/templates/Main.vue";
|
||||||
|
import { RouterLink, RouterView } from "vue-router";
|
||||||
|
import { useAbilityStore } from "@/stores/ability";
|
||||||
|
import { useEquipmentStore } from "@/stores/admin/unit/equipment/equipment";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tabs: [
|
||||||
|
{ route: "admin-unit-inspection", title: "anstehend" },
|
||||||
|
{ route: "admin-unit-inspection-running", title: "in Arbeit" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useAbilityStore, ["can"]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<MainTemplate title="Prüfung erstellen">
|
<MainTemplate title="Prüfung starten">
|
||||||
<template #main>
|
<template #main>
|
||||||
<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">
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
>
|
>
|
||||||
abbrechen
|
abbrechen
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
<button primary type="submit" class="w-fit!" :disabled="status == 'loading'">speichern</button>
|
<button primary type="submit" class="w-fit!" :disabled="status == 'loading'">starten</button>
|
||||||
<Spinner v-if="status == 'loading'" class="my-auto" />
|
<Spinner v-if="status == 'loading'" class="my-auto" />
|
||||||
<SuccessCheckmark v-else-if="status?.status == 'success'" />
|
<SuccessCheckmark v-else-if="status?.status == 'success'" />
|
||||||
<FailureXMark v-else-if="status?.status == 'failed'" />
|
<FailureXMark v-else-if="status?.status == 'failed'" />
|
||||||
|
@ -64,11 +64,10 @@ 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 InspectionPlanSearchSelect from "@/components/search/InspectionPlanSearchSelect.vue";
|
import InspectionPlanSearchSelect from "@/components/search/InspectionPlanSearchSelect.vue";
|
||||||
import EquipmentSearchSelect from "@/components/search/EquipmentSearchSelect.vue";
|
import EquipmentSearchSelect from "@/components/search/EquipmentSearchSelect.vue";
|
||||||
import VehicleSearchSelect from "@/components/search/VehicleSearchSelect.vue";
|
import VehicleSearchSelect from "@/components/search/VehicleSearchSelect.vue";
|
||||||
import WearableSearchSelect from "../../../../components/search/wearableSearchSelect.vue";
|
import WearableSearchSelect from "@/components/search/WearableSearchSelect.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
45
src/views/admin/unit/inspection/NextInspection.vue
Normal file
45
src/views/admin/unit/inspection/NextInspection.vue
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col w-full h-full gap-2 justify-center">
|
||||||
|
<Pagination
|
||||||
|
:items="[]"
|
||||||
|
:totalCount="0"
|
||||||
|
:indicateLoading="false"
|
||||||
|
@load-data="(offset, count, search) => {}"
|
||||||
|
@search="(search) => {}"
|
||||||
|
>
|
||||||
|
<template #pageRow="{ row }: { row: any }">
|
||||||
|
{{ row }}
|
||||||
|
</template>
|
||||||
|
</Pagination>
|
||||||
|
|
||||||
|
<div class="flex flex-row gap-4">
|
||||||
|
<RouterLink
|
||||||
|
v-if="can('create', 'unit', 'inspection')"
|
||||||
|
:to="{ name: 'admin-unit-inspection-start' }"
|
||||||
|
primary
|
||||||
|
button
|
||||||
|
class="w-fit!"
|
||||||
|
>
|
||||||
|
Prüfung starten
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import { mapActions, mapState } from "pinia";
|
||||||
|
import Pagination from "@/components/Pagination.vue";
|
||||||
|
import { useAbilityStore } from "@/stores/ability";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useAbilityStore, ["can"]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -159,7 +159,7 @@ export default defineComponent({
|
||||||
|
|
||||||
this.timeout = setTimeout(() => {
|
this.timeout = setTimeout(() => {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: "admin-unit-inspectionPlan-overview",
|
name: "admin-unit-inspection_plan-overview",
|
||||||
params: {
|
params: {
|
||||||
inspectionPlanId: res.data,
|
inspectionPlanId: res.data,
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,9 +4,17 @@
|
||||||
<RouterLink to="./" class="text-primary">zurück zur Liste</RouterLink>
|
<RouterLink to="./" class="text-primary">zurück zur Liste</RouterLink>
|
||||||
</template>
|
</template>
|
||||||
<template #topBar>
|
<template #topBar>
|
||||||
|
<div class="flex flex-row gap-2">
|
||||||
<RouterLink v-if="can('update', 'unit', 'inspection_plan')" :to="{ name: 'admin-unit-inspection_plan-edit' }">
|
<RouterLink v-if="can('update', 'unit', 'inspection_plan')" :to="{ name: 'admin-unit-inspection_plan-edit' }">
|
||||||
<PencilIcon class="w-5 h-5" />
|
<PencilIcon class="w-5 h-5" />
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
<RouterLink
|
||||||
|
v-if="can('update', 'unit', 'inspection_plan')"
|
||||||
|
:to="{ name: 'admin-unit-inspection_plan-pointedit' }"
|
||||||
|
>
|
||||||
|
<RectangleStackIcon class="w-5 h-5" />
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #diffMain>
|
<template #diffMain>
|
||||||
<div class="flex flex-col gap-2 grow px-7 overflow-hidden">
|
<div class="flex flex-col gap-2 grow px-7 overflow-hidden">
|
||||||
|
@ -21,7 +29,7 @@ import { defineComponent } from "vue";
|
||||||
import { mapActions, mapState } from "pinia";
|
import { mapActions, mapState } from "pinia";
|
||||||
import MainTemplate from "@/templates/Main.vue";
|
import MainTemplate from "@/templates/Main.vue";
|
||||||
import { RouterLink, RouterView } from "vue-router";
|
import { RouterLink, RouterView } from "vue-router";
|
||||||
import { PencilIcon, TrashIcon } from "@heroicons/vue/24/outline";
|
import { PencilIcon, RectangleStackIcon, TrashIcon } from "@heroicons/vue/24/outline";
|
||||||
import { useAbilityStore } from "@/stores/ability";
|
import { useAbilityStore } from "@/stores/ability";
|
||||||
import { useInspectionPlanStore } from "@/stores/admin/unit/inspectionPlan/inspectionPlan";
|
import { useInspectionPlanStore } from "@/stores/admin/unit/inspectionPlan/inspectionPlan";
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="interval">Intervall</label>
|
<label for="interval">Intervall</label>
|
||||||
<input type="text" id="interval" :value="activeInspectionPlanObj.inspectionInterval" reaonly />
|
<input type="text" id="interval" :value="activeInspectionPlanObj.inspectionInterval" readonly />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="remind">Erinnerung vor Fälligkeit</label>
|
||||||
|
<input type="text" id="remind" :value="activeInspectionPlanObj.remindTime" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>Prüfungspunkte:</p>
|
<p>Prüfungspunkte:</p>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
|
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
|
||||||
|
<RouterLink to="./" class="text-primary">zurück zur Übersicht</RouterLink>
|
||||||
<Spinner v-if="loading == 'loading'" class="mx-auto" />
|
<Spinner v-if="loading == 'loading'" class="mx-auto" />
|
||||||
<p v-else-if="loading == 'failed'">laden fehlgeschlagen</p>
|
<p v-else-if="loading == 'failed'">laden fehlgeschlagen</p>
|
||||||
<form
|
<form
|
||||||
|
@ -7,7 +8,7 @@
|
||||||
class="flex flex-col gap-4 py-2 w-full max-w-xl mx-auto"
|
class="flex flex-col gap-4 py-2 w-full max-w-xl mx-auto"
|
||||||
@submit.prevent="triggerUpdate"
|
@submit.prevent="triggerUpdate"
|
||||||
>
|
>
|
||||||
<p class="mx-auto">Ausrüstung bearbeiten</p>
|
<p class="mx-auto">Prüfplan bearbeiten</p>
|
||||||
<div>
|
<div>
|
||||||
<label for="name">Bezeichnung</label>
|
<label for="name">Bezeichnung</label>
|
||||||
<input type="text" id="name" required v-model="inspectionPlan.title" />
|
<input type="text" id="name" required v-model="inspectionPlan.title" />
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
|
||||||
|
<RouterLink to="./" class="text-primary">zurück zur Übersicht</RouterLink>
|
||||||
|
<Spinner v-if="loading == 'loading'" class="mx-auto" />
|
||||||
|
<p v-else-if="loading == 'failed'">laden fehlgeschlagen</p>
|
||||||
|
<div
|
||||||
|
v-else-if="inspectionPlan != null"
|
||||||
|
class="flex flex-col grow gap-4 py-2 w-full max-w-xl mx-auto overflow-hidden"
|
||||||
|
>
|
||||||
|
<p class="mx-auto">Prüfplan-Punkte bearbeiten</p>
|
||||||
|
|
||||||
|
<div class="flex flex-row justify-center gap-4">
|
||||||
|
<div
|
||||||
|
class="p-3 border border-gray-300 rounded-md shadow cursor-pointer"
|
||||||
|
@click="addItemToArray(InspectionPointEnum.oknok)"
|
||||||
|
>
|
||||||
|
<ClipboardDocumentCheckIcon class="w-7 h-7" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="p-3 border border-gray-300 rounded-md shadow cursor-pointer pointer-events-none opacity-50"
|
||||||
|
@click="addItemToArray(InspectionPointEnum.file)"
|
||||||
|
>
|
||||||
|
<DocumentIcon class="w-7 h-7" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="p-3 border border-gray-300 rounded-md shadow cursor-pointer"
|
||||||
|
@click="addItemToArray(InspectionPointEnum.number)"
|
||||||
|
>
|
||||||
|
<CalculatorIcon class="w-7 h-7" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="p-3 border border-gray-300 rounded-md shadow cursor-pointer"
|
||||||
|
@click="addItemToArray(InspectionPointEnum.text)"
|
||||||
|
>
|
||||||
|
<BoldIcon class="w-7 h-7" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grow flex flex-col gap-2 overflow-y-scroll">
|
||||||
|
<InspectionPointListItem
|
||||||
|
v-for="(point, index) in sortedPoints"
|
||||||
|
:key="index"
|
||||||
|
:model-value="point"
|
||||||
|
:index="index"
|
||||||
|
:total-count="inspectionPoints.length"
|
||||||
|
@update:model-value="updateItemFromArray"
|
||||||
|
@up="changeSort('up', point.id, index)"
|
||||||
|
@down="changeSort('down', point.id, index)"
|
||||||
|
@remove="removeItemFromArray(point.id)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-row justify-end gap-2">
|
||||||
|
<button primary-outline type="reset" class="w-fit!" :disabled="canSaveOrReset" @click="resetForm">
|
||||||
|
abbrechen
|
||||||
|
</button>
|
||||||
|
<button primary type="submit" class="w-fit!" :disabled="status == 'loading'" @click="triggerUpdate">
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import { mapActions, mapState } from "pinia";
|
||||||
|
import { useInspectionPlanStore } from "@/stores/admin/unit/inspectionPlan/inspectionPlan";
|
||||||
|
import type {
|
||||||
|
CreateInspectionPlanViewModel,
|
||||||
|
InspectionPlanViewModel,
|
||||||
|
InspectionPointViewModel,
|
||||||
|
UpdateInspectionPlanViewModel,
|
||||||
|
} from "@/viewmodels/admin/unit/inspection/inspectionPlan.models";
|
||||||
|
import Spinner from "@/components/Spinner.vue";
|
||||||
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
|
import isEqual from "lodash.isequal";
|
||||||
|
import cloneDeep from "lodash.clonedeep";
|
||||||
|
import { BoldIcon, CalculatorIcon, ClipboardDocumentCheckIcon, DocumentIcon } from "@heroicons/vue/24/outline";
|
||||||
|
import { InspectionPointEnum } from "@/enums/inspectionEnum";
|
||||||
|
import { v4 as uuid } from "uuid";
|
||||||
|
import InspectionPointListItem from "@/components/admin/unit/inspectionPlan/InspectionPointListItem.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
inspectionPlanId: String,
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
loadingActive() {
|
||||||
|
if (this.loading == "loading") {
|
||||||
|
this.loading = this.loadingActive;
|
||||||
|
}
|
||||||
|
if (this.loadingActive == "fetched") this.inspectionPlan = cloneDeep(this.activeInspectionPlanObj);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: "loading" as "loading" | "fetched" | "failed",
|
||||||
|
status: null as null | "loading" | { status: "success" | "failed"; reason?: string },
|
||||||
|
inspectionPlan: null as null | InspectionPlanViewModel,
|
||||||
|
timeout: null as any,
|
||||||
|
inspectionPoints: [] as Array<InspectionPointViewModel>,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
canSaveOrReset(): boolean {
|
||||||
|
return isEqual(this.activeInspectionPlanObj, this.inspectionPlan);
|
||||||
|
},
|
||||||
|
...mapState(useInspectionPlanStore, ["activeInspectionPlanObj", "loadingActive"]),
|
||||||
|
sortedPoints() {
|
||||||
|
return this.inspectionPoints.slice().sort((a, b) => a.sort - b.sort);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.fetchItem();
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
try {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
} catch (error) {}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useInspectionPlanStore, ["updateActiveInspectionPlan", "fetchInspectionPlanByActiveId"]),
|
||||||
|
resetForm() {
|
||||||
|
this.inspectionPlan = cloneDeep(this.activeInspectionPlanObj);
|
||||||
|
},
|
||||||
|
fetchItem() {
|
||||||
|
this.fetchInspectionPlanByActiveId();
|
||||||
|
},
|
||||||
|
addItemToArray(type: InspectionPointEnum) {
|
||||||
|
this.inspectionPoints.push({
|
||||||
|
id: uuid(),
|
||||||
|
title: "",
|
||||||
|
description: "",
|
||||||
|
type,
|
||||||
|
sort: this.inspectionPoints.length,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateItemFromArray(pkg: InspectionPointViewModel) {
|
||||||
|
let index = this.inspectionPoints.findIndex((ip) => ip.id == pkg.id);
|
||||||
|
this.inspectionPoints[index] = pkg;
|
||||||
|
},
|
||||||
|
removeItemFromArray(id: string) {
|
||||||
|
let index = this.inspectionPoints.findIndex((ip) => ip.id == id);
|
||||||
|
if (index !== -1) {
|
||||||
|
this.inspectionPoints.splice(index, 1);
|
||||||
|
this.normalizeSort();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeSort(dir: "up" | "down", thisId: string, index: number) {
|
||||||
|
let affected = this.sortedPoints[dir == "up" ? index - 1 : index + 1];
|
||||||
|
if (affected) {
|
||||||
|
this.inspectionPoints.find((a) => a.id == thisId)!.sort = dir == "up" ? index - 1 : index + 1;
|
||||||
|
this.inspectionPoints.find((a) => a.id == affected.id)!.sort =
|
||||||
|
dir == "up" ? affected.sort + 1 : affected.sort - 1;
|
||||||
|
}
|
||||||
|
this.normalizeSort();
|
||||||
|
},
|
||||||
|
normalizeSort() {
|
||||||
|
let rightSort = this.sortedPoints.every((val, index) => val.sort == index);
|
||||||
|
if (!rightSort) {
|
||||||
|
this.inspectionPoints.forEach((e, index) => {
|
||||||
|
e.sort = this.sortedPoints.findIndex((sp) => sp.id == e.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
triggerUpdate(e: any) {
|
||||||
|
if (this.inspectionPlan == null) return;
|
||||||
|
let formData = e.target.elements;
|
||||||
|
let updateInspectionPlan: UpdateInspectionPlanViewModel = {
|
||||||
|
id: this.inspectionPlan.id,
|
||||||
|
title: formData.name.value,
|
||||||
|
inspectionInterval: formData.interval.value,
|
||||||
|
remindTime: formData.remind.value,
|
||||||
|
};
|
||||||
|
this.status = "loading";
|
||||||
|
this.updateActiveInspectionPlan(updateInspectionPlan)
|
||||||
|
.then((res) => {
|
||||||
|
this.fetchItem();
|
||||||
|
this.status = { status: "success" };
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.status = { status: "failed" };
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.status = null;
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col w-full h-full gap-2 justify-center px-7">
|
<div class="flex flex-col w-full h-full gap-2 justify-center">
|
||||||
<Pagination
|
<Pagination
|
||||||
:items="maintenances"
|
:items="maintenances"
|
||||||
:totalCount="totalCount"
|
:totalCount="totalCount"
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<div class="flex flex-row gap-4">
|
<div class="flex flex-row gap-4">
|
||||||
<RouterLink
|
<RouterLink
|
||||||
v-if="can('create', 'unit', 'vehicle')"
|
v-if="can('create', 'unit', 'vehicle')"
|
||||||
:to="{ name: 'admin-unit-inspection-plan', params: { type: 'vehicle', relatedId: vehicleId } }"
|
:to="{ name: 'admin-unit-inspection-start', params: { type: 'vehicle', relatedId: vehicleId } }"
|
||||||
button
|
button
|
||||||
primary
|
primary
|
||||||
class="w-fit!"
|
class="w-fit!"
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<div class="flex flex-row gap-4">
|
<div class="flex flex-row gap-4">
|
||||||
<RouterLink
|
<RouterLink
|
||||||
v-if="can('create', 'unit', 'wearable')"
|
v-if="can('create', 'unit', 'wearable')"
|
||||||
:to="{ name: 'admin-unit-inspection-plan', params: { type: 'wearable', relatedId: wearableId } }"
|
:to="{ name: 'admin-unit-inspection-start', params: { type: 'wearable', relatedId: wearableId } }"
|
||||||
button
|
button
|
||||||
primary
|
primary
|
||||||
class="w-fit!"
|
class="w-fit!"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue