From 65759488410439cdefd563f4c69179b2dd855a07 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Fri, 13 Jun 2025 12:45:43 +0200 Subject: [PATCH] maintainance view and wearable inspection integration --- .../unit/maintenance/MaintenanceListItem.vue | 31 +++ .../wearableType/WearableTypeListItem.vue | 18 +- .../search/WearableSearchSelect.vue | 196 ++++++++++++++++++ src/router/index.ts | 57 ++++- src/router/unit/wearableType.ts | 21 ++ src/stores/admin/navigation.ts | 3 + .../admin/unit/maintenance/maintenance.ts | 74 +++++++ src/stores/admin/unit/wearable/inspection.ts | 43 ++++ .../admin/unit/wearableType/inspectionPlan.ts | 29 +++ .../admin/unit/wearableType/wearableType.ts | 15 ++ src/types/permissionTypes.ts | 3 + .../unit/inspection/inspection.models.ts | 5 + .../unit/inspection/inspectionPlan.models.ts | 7 +- .../club/newsletter/NewsletterRecipients.vue | 2 - .../unit/damageReport/DamageReportRouting.vue | 3 - .../equipmentType/EquipmentTypeRouting.vue | 2 +- .../admin/unit/inspection/InspectionPlan.vue | 16 +- .../admin/unit/maintenance/Maintenance.vue | 46 ++++ .../unit/maintenance/MaintenanceRouting.vue | 54 +++++ .../unit/vehicleType/VehicleTypeRouting.vue | 2 +- src/views/admin/unit/wearable/Inspection.vue | 69 ++++++ .../admin/unit/wearable/WearableRouting.vue | 3 +- .../unit/wearableType/InspectionPlans.vue | 51 +++++ .../admin/unit/wearableType/Overview.vue | 43 ++++ .../unit/wearableType/UpdateWearableType.vue | 62 +++--- .../unit/wearableType/WearableTypeRouting.vue | 88 ++++++++ 26 files changed, 877 insertions(+), 66 deletions(-) create mode 100644 src/components/admin/unit/maintenance/MaintenanceListItem.vue create mode 100644 src/components/search/WearableSearchSelect.vue create mode 100644 src/router/unit/wearableType.ts create mode 100644 src/stores/admin/unit/maintenance/maintenance.ts create mode 100644 src/stores/admin/unit/wearable/inspection.ts create mode 100644 src/stores/admin/unit/wearableType/inspectionPlan.ts create mode 100644 src/views/admin/unit/maintenance/Maintenance.vue create mode 100644 src/views/admin/unit/maintenance/MaintenanceRouting.vue create mode 100644 src/views/admin/unit/wearable/Inspection.vue create mode 100644 src/views/admin/unit/wearableType/InspectionPlans.vue create mode 100644 src/views/admin/unit/wearableType/Overview.vue create mode 100644 src/views/admin/unit/wearableType/WearableTypeRouting.vue diff --git a/src/components/admin/unit/maintenance/MaintenanceListItem.vue b/src/components/admin/unit/maintenance/MaintenanceListItem.vue new file mode 100644 index 0000000..a838973 --- /dev/null +++ b/src/components/admin/unit/maintenance/MaintenanceListItem.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/src/components/admin/unit/wearableType/WearableTypeListItem.vue b/src/components/admin/unit/wearableType/WearableTypeListItem.vue index a6cb6b9..09bdf96 100644 --- a/src/components/admin/unit/wearableType/WearableTypeListItem.vue +++ b/src/components/admin/unit/wearableType/WearableTypeListItem.vue @@ -1,20 +1,12 @@ + + diff --git a/src/router/index.ts b/src/router/index.ts index 40c5159..5f58c0a 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -19,6 +19,7 @@ import { resetWearableStores, setWearableId } from "./unit/wearable"; import { resetInspectionPlanStores, setInspectionPlanId } from "./unit/inspectionPlan"; import { setVehicleTypeId } from "./unit/vehicleType"; import { resetInspectionStores, setInspectionId } from "./unit/inspection"; +import { setWearableTypeId } from "./unit/wearableType"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -498,6 +499,12 @@ const router = createRouter({ component: () => import("@/views/admin/ViewSelect.vue"), props: true, }, + { + path: "inspection", + name: "admin-unit-wearable-inspection", + component: () => import("@/views/admin/unit/wearable/Inspection.vue"), + props: true, + }, { path: "report", name: "admin-unit-wearable-damage_report", @@ -706,6 +713,25 @@ const router = createRouter({ }, ], }, + { + path: "maintenance", + name: "admin-unit-maintenance-route", + component: () => import("@/views/admin/unit/maintenance/MaintenanceRouting.vue"), + meta: { type: "read", section: "unit", module: "maintenance" }, + beforeEnter: [abilityAndNavUpdate], + children: [ + { + path: "", + name: "admin-unit-maintenance", + component: () => import("@/views/admin/unit/maintenance/Maintenance.vue"), + }, + { + path: "done", + name: "admin-unit-maintenance-done", + component: () => import("@/views/admin/unit/maintenance/Maintenance.vue"), + }, + ], + }, { path: "equipment-type", name: "admin-unit-equipment_type-route", @@ -806,12 +832,33 @@ const router = createRouter({ component: () => import("@/views/admin/unit/wearableType/WearableType.vue"), }, { - path: ":wearableTypeId/edit", - name: "admin-unit-wearable_type-edit", - component: () => import("@/views/admin/unit/wearableType/UpdateWearableType.vue"), - meta: { type: "update", section: "unit", module: "wearable_type" }, - beforeEnter: [abilityAndNavUpdate], + path: ":wearableTypeId", + name: "admin-unit-wearable_type-routing", + component: () => import("@/views/admin/unit/wearableType/WearableTypeRouting.vue"), + beforeEnter: [setWearableTypeId], props: true, + children: [ + { + path: "overview", + name: "admin-unit-wearable_type-overview", + component: () => import("@/views/admin/unit/wearableType/Overview.vue"), + props: true, + }, + { + path: "inspection-plan", + name: "admin-unit-wearable_type-inspection_plan", + component: () => import("@/views/admin/unit/wearableType/InspectionPlans.vue"), + props: true, + }, + { + path: "edit", + name: "admin-unit-wearable_type-edit", + component: () => import("@/views/admin/unit/wearableType/UpdateWearableType.vue"), + meta: { type: "update", section: "unit", module: "wearable_type" }, + beforeEnter: [abilityAndNavUpdate], + props: true, + }, + ], }, ], }, diff --git a/src/router/unit/wearableType.ts b/src/router/unit/wearableType.ts new file mode 100644 index 0000000..3b439ff --- /dev/null +++ b/src/router/unit/wearableType.ts @@ -0,0 +1,21 @@ +import { useWearableTypeStore } from "@/stores/admin/unit/wearableType/wearableType"; +import { useWearableTypeInspectionPlanStore } from "@/stores/admin/unit/wearableType/inspectionPlan"; + +export async function setWearableTypeId(to: any, from: any, next: any) { + const wearableTypeStore = useWearableTypeStore(); + wearableTypeStore.activeWearableType = to.params?.wearableTypeId ?? null; + + useWearableTypeInspectionPlanStore().$reset(); + + next(); +} + +export async function resetWearableTypeStores(to: any, from: any, next: any) { + const wearableTypeStore = useWearableTypeStore(); + wearableTypeStore.activeWearableType = null; + wearableTypeStore.activeWearableTypeObj = null; + + useWearableTypeInspectionPlanStore().$reset(); + + next(); +} diff --git a/src/stores/admin/navigation.ts b/src/stores/admin/navigation.ts index 59991b3..b5d1301 100644 --- a/src/stores/admin/navigation.ts +++ b/src/stores/admin/navigation.ts @@ -123,6 +123,9 @@ export const useNavigationStore = defineStore("navigation", { ...(abilityStore.can("read", "unit", "damage_report") ? [{ key: "damage_report", title: "Schadensmeldungen" }] : []), + ...(abilityStore.can("read", "unit", "maintenance") + ? [{ key: "maintenance", title: "Wartungen / Reparaturen" }] + : []), { key: "divider1", title: "Basisdaten" }, ...(abilityStore.can("read", "unit", "equipment_type") ? [{ key: "equipment_type", title: "Geräte-Typen" }] diff --git a/src/stores/admin/unit/maintenance/maintenance.ts b/src/stores/admin/unit/maintenance/maintenance.ts new file mode 100644 index 0000000..fd9fb79 --- /dev/null +++ b/src/stores/admin/unit/maintenance/maintenance.ts @@ -0,0 +1,74 @@ +import { defineStore } from "pinia"; +import type { + MaintenanceViewModel, + CreateMaintenanceViewModel, + UpdateMaintenanceViewModel, +} from "@/viewmodels/admin/unit/maintenance.models"; +import { http } from "@/serverCom"; +import type { AxiosResponse } from "axios"; + +export const useMaintenanceStore = defineStore("maintenance", { + state: () => { + return { + maintenances: [] as Array, + totalCount: 0 as number, + loading: "loading" as "loading" | "fetched" | "failed", + }; + }, + actions: { + fetchMaintenances(offset = 0, count = 25, search = "", clear = false) { + if (clear) this.maintenances = []; + this.loading = "loading"; + //TODO enable fetch of done reports + http + .get(`/admin/maintenance?offset=${offset}&count=${count}${search != "" ? "&search=" + search : ""}`) + .then((result) => { + this.totalCount = result.data.total; + result.data.maintenances + .filter((elem: MaintenanceViewModel) => this.maintenances.findIndex((m) => m.id == elem.id) == -1) + .map((elem: MaintenanceViewModel, index: number): MaintenanceViewModel & { tab_pos: number } => { + return { + ...elem, + tab_pos: index + offset, + }; + }) + .forEach((elem: MaintenanceViewModel & { tab_pos: number }) => { + this.maintenances.push(elem); + }); + this.loading = "fetched"; + }) + .catch((err) => { + this.loading = "failed"; + }); + }, + async getAllMaintenances(): Promise> { + return await http.get(`/admin/maintenance?noLimit=true`).then((res) => { + return { ...res, data: res.data.maintenances }; + }); + }, + async getMaintenancesByIds(ids: Array): Promise> { + return await http + .post(`/admin/maintenance/ids`, { + ids, + }) + .then((res) => { + return { ...res, data: res.data.maintenances }; + }); + }, + async searchMaintenances(search: string): Promise> { + return await http.get(`/admin/maintenance?search=${search}&noLimit=true`).then((res) => { + return { ...res, data: res.data.maintenances }; + }); + }, + fetchMaintenanceById(id: string) { + return http.get(`/admin/maintenance/${id}`); + }, + async updateMaintenance(maintenance: UpdateMaintenanceViewModel): Promise> { + const result = await http.patch(`/admin/maintenance/${maintenance.id}`, { + // TODO: data + }); + this.fetchMaintenances(); + return result; + }, + }, +}); diff --git a/src/stores/admin/unit/wearable/inspection.ts b/src/stores/admin/unit/wearable/inspection.ts new file mode 100644 index 0000000..1596da6 --- /dev/null +++ b/src/stores/admin/unit/wearable/inspection.ts @@ -0,0 +1,43 @@ +import { defineStore } from "pinia"; +import { http } from "@/serverCom"; +import type { InspectionViewModel } from "@/viewmodels/admin/unit/inspection/inspection.models"; +import { useWearableStore } from "./wearable"; + +export const useWearableInspectionStore = defineStore("wearableInspection", { + state: () => { + return { + inspections: [] as Array, + totalCount: 0 as number, + loading: "loading" as "loading" | "fetched" | "failed", + }; + }, + actions: { + fetchInspectionForWearable(offset = 0, count = 25, search = "", clear = false) { + const wearableId = useWearableStore().activeWearable; + if (clear) this.inspections = []; + this.loading = "loading"; + http + .get( + `/admin/inspection/wearable/${wearableId}?offset=${offset}&count=${count}${search != "" ? "&search=" + search : ""}` + ) + .then((result) => { + this.totalCount = result.data.total; + result.data.inspections + .filter((elem: InspectionViewModel) => this.inspections.findIndex((m) => m.id == elem.id) == -1) + .map((elem: InspectionViewModel, index: number): InspectionViewModel & { tab_pos: number } => { + return { + ...elem, + tab_pos: index + offset, + }; + }) + .forEach((elem: InspectionViewModel & { tab_pos: number }) => { + this.inspections.push(elem); + }); + this.loading = "fetched"; + }) + .catch((err) => { + this.loading = "failed"; + }); + }, + }, +}); diff --git a/src/stores/admin/unit/wearableType/inspectionPlan.ts b/src/stores/admin/unit/wearableType/inspectionPlan.ts new file mode 100644 index 0000000..dbe2254 --- /dev/null +++ b/src/stores/admin/unit/wearableType/inspectionPlan.ts @@ -0,0 +1,29 @@ +import { defineStore } from "pinia"; +import { http } from "@/serverCom"; +import type { InspectionPlanViewModel } from "@/viewmodels/admin/unit/inspection/inspectionPlan.models"; +import { useWearableTypeStore } from "./wearableType"; + +export const useWearableTypeInspectionPlanStore = defineStore("wearableTypeInspectionPlan", { + state: () => { + return { + inspectionPlans: [] as Array, + totalCount: 0 as number, + loading: "loading" as "loading" | "fetched" | "failed", + }; + }, + actions: { + fetchInspectionPlanForWearableType() { + const wearableTypeId = useWearableTypeStore().activeWearableType; + this.loading = "loading"; + http + .get(`/admin/inspectionPlan/wearableType/${wearableTypeId}`) + .then((result) => { + this.inspectionPlans = result.data; + this.loading = "fetched"; + }) + .catch((err) => { + this.loading = "failed"; + }); + }, + }, +}); diff --git a/src/stores/admin/unit/wearableType/wearableType.ts b/src/stores/admin/unit/wearableType/wearableType.ts index 06b73a1..bba5113 100644 --- a/src/stores/admin/unit/wearableType/wearableType.ts +++ b/src/stores/admin/unit/wearableType/wearableType.ts @@ -13,6 +13,9 @@ export const useWearableTypeStore = defineStore("wearableType", { wearableTypes: [] as Array, totalCount: 0 as number, loading: "loading" as "loading" | "fetched" | "failed", + activeWearableType: null as string | null, + activeWearableTypeObj: null as WearableTypeViewModel | null, + loadingActive: "loading" as "loading" | "fetched" | "failed", }; }, actions: { @@ -50,6 +53,18 @@ export const useWearableTypeStore = defineStore("wearableType", { return { ...res, data: res.data.wearableTypes }; }); }, + fetchWearableTypeByActiveId() { + this.loadingActive = "loading"; + http + .get(`/admin/wearableType/${this.activeWearableType}`) + .then((res) => { + this.activeWearableTypeObj = res.data; + this.loadingActive = "fetched"; + }) + .catch((err) => { + this.loadingActive = "failed"; + }); + }, fetchWearableTypeById(id: string) { return http.get(`/admin/wearableType/${id}`); }, diff --git a/src/types/permissionTypes.ts b/src/types/permissionTypes.ts index f85a54f..2442d9f 100644 --- a/src/types/permissionTypes.ts +++ b/src/types/permissionTypes.ts @@ -21,6 +21,7 @@ export type PermissionModule = | "respiratory_wearer" | "respiratory_mission" | "damage_report" + | "maintenance" // configuration | "qualification" | "award" @@ -95,6 +96,7 @@ export const permissionModules: Array = [ "respiratory_wearer", "respiratory_mission", "damage_report", + "maintenance", // configuration "qualification", "award", @@ -131,6 +133,7 @@ export const sectionsAndModules: SectionsAndModulesObject = { "respiratory_wearer", "respiratory_mission", "damage_report", + "maintenance", ], configuration: [ "qualification", diff --git a/src/viewmodels/admin/unit/inspection/inspection.models.ts b/src/viewmodels/admin/unit/inspection/inspection.models.ts index 3f65cad..4f72a13 100644 --- a/src/viewmodels/admin/unit/inspection/inspection.models.ts +++ b/src/viewmodels/admin/unit/inspection/inspection.models.ts @@ -5,6 +5,7 @@ import type { InspectionVersionedPlanViewModel, } from "./inspectionPlan.models"; import type { VehicleViewModel } from "../vehicle/vehicle.models"; +import type { WearableViewModel } from "../wearable/wearable.models"; export type InspectionViewModel = { id: string; @@ -28,6 +29,10 @@ export type InspectionViewModel = { assigned: "vehicle"; related: VehicleViewModel; } + | { + assigned: "wearable"; + related: WearableViewModel; + } ); export interface InspectionPointResultViewModel { diff --git a/src/viewmodels/admin/unit/inspection/inspectionPlan.models.ts b/src/viewmodels/admin/unit/inspection/inspectionPlan.models.ts index 4d7b9a9..262f25e 100644 --- a/src/viewmodels/admin/unit/inspection/inspectionPlan.models.ts +++ b/src/viewmodels/admin/unit/inspection/inspectionPlan.models.ts @@ -3,6 +3,7 @@ import type { EquipmentViewModel } from "../equipment/equipment.models"; import type { VehicleViewModel } from "../vehicle/vehicle.models"; import type { EquipmentTypeViewModel } from "../equipment/equipmentType.models"; import type { VehicleTypeViewModel } from "../vehicle/vehicleType.models"; +import type { WearableTypeViewModel } from "../wearable/wearableType.models"; export type PlanTimeDefinition = `${number}-${"d" | "m" | "y"}` | `${number}/${number | "*"}`; @@ -24,6 +25,10 @@ export type InspectionPlanViewModel = { assigned: "vehicle"; related: VehicleTypeViewModel; } + | { + assigned: "wearable"; + related: WearableTypeViewModel; + } ); export interface InspectionVersionedPlanViewModel { @@ -48,7 +53,7 @@ export interface CreateInspectionPlanViewModel { inspectionInterval: PlanTimeDefinition; remindTime: PlanTimeDefinition; relatedId: string; - assigned: "vehicle" | "equipment"; + assigned: "vehicle" | "equipment" | "wearable"; } export interface UpdateInspectionPlanViewModel { diff --git a/src/views/admin/club/newsletter/NewsletterRecipients.vue b/src/views/admin/club/newsletter/NewsletterRecipients.vue index cad08c2..6fcdec5 100644 --- a/src/views/admin/club/newsletter/NewsletterRecipients.vue +++ b/src/views/admin/club/newsletter/NewsletterRecipients.vue @@ -74,9 +74,7 @@ import { useNewsletterRecipientsStore } from "@/stores/admin/club/newsletter/new import { useAbilityStore } from "@/stores/ability"; import { useQueryStoreStore } from "@/stores/admin/configuration/queryStore"; import { useQueryBuilderStore } from "@/stores/admin/club/queryBuilder"; -import cloneDeep from "lodash.clonedeep"; import MemberSearchSelectMultiple from "@/components/search/MemberSearchSelectMultiple.vue"; -import MemberSearchSelect from "@/components/search/MemberSearchSelect.vue"; import type { FieldType } from "@/types/dynamicQueries"; import DoubleConfirmClick from "@/components/DoubleConfirmClick.vue"; diff --git a/src/views/admin/unit/damageReport/DamageReportRouting.vue b/src/views/admin/unit/damageReport/DamageReportRouting.vue index fdb9a49..48d8b0f 100644 --- a/src/views/admin/unit/damageReport/DamageReportRouting.vue +++ b/src/views/admin/unit/damageReport/DamageReportRouting.vue @@ -39,9 +39,6 @@ import { useEquipmentStore } from "@/stores/admin/unit/equipment/equipment"; + + diff --git a/src/views/admin/unit/maintenance/MaintenanceRouting.vue b/src/views/admin/unit/maintenance/MaintenanceRouting.vue new file mode 100644 index 0000000..679740c --- /dev/null +++ b/src/views/admin/unit/maintenance/MaintenanceRouting.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/src/views/admin/unit/vehicleType/VehicleTypeRouting.vue b/src/views/admin/unit/vehicleType/VehicleTypeRouting.vue index 46c3338..3c9a3d4 100644 --- a/src/views/admin/unit/vehicleType/VehicleTypeRouting.vue +++ b/src/views/admin/unit/vehicleType/VehicleTypeRouting.vue @@ -79,7 +79,7 @@ export default defineComponent({ ...mapActions(useModalStore, ["openModal"]), openDeleteModal() { this.openModal( - markRaw(defineAsyncComponent(() => import("@/components/admin/unit/vehicleType/CreateVehicleTypeModal.vue"))), + markRaw(defineAsyncComponent(() => import("@/components/admin/unit/vehicleType/DeleteVehicleTypeModal.vue"))), this.vehicleTypeId ?? "" ); }, diff --git a/src/views/admin/unit/wearable/Inspection.vue b/src/views/admin/unit/wearable/Inspection.vue new file mode 100644 index 0000000..bf71eff --- /dev/null +++ b/src/views/admin/unit/wearable/Inspection.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/src/views/admin/unit/wearable/WearableRouting.vue b/src/views/admin/unit/wearable/WearableRouting.vue index 1b35c5f..e1f9f88 100644 --- a/src/views/admin/unit/wearable/WearableRouting.vue +++ b/src/views/admin/unit/wearable/WearableRouting.vue @@ -55,7 +55,8 @@ export default defineComponent({ return { tabs: [ { route: "admin-unit-wearable-overview", title: "Übersicht" }, - { route: "admin-unit-wearable-maintenance", title: "Reparaturen" }, + { route: "admin-unit-wearable-maintenance", title: "Wartungen/Reparaturen" }, + { route: "admin-unit-wearable-inspection", title: "Prüfungen" }, { route: "admin-unit-wearable-damage_report", title: "Schadensmeldungen" }, ], }; diff --git a/src/views/admin/unit/wearableType/InspectionPlans.vue b/src/views/admin/unit/wearableType/InspectionPlans.vue new file mode 100644 index 0000000..5cc5c46 --- /dev/null +++ b/src/views/admin/unit/wearableType/InspectionPlans.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/src/views/admin/unit/wearableType/Overview.vue b/src/views/admin/unit/wearableType/Overview.vue new file mode 100644 index 0000000..5e0444e --- /dev/null +++ b/src/views/admin/unit/wearableType/Overview.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/src/views/admin/unit/wearableType/UpdateWearableType.vue b/src/views/admin/unit/wearableType/UpdateWearableType.vue index 242301a..cf85991 100644 --- a/src/views/admin/unit/wearableType/UpdateWearableType.vue +++ b/src/views/admin/unit/wearableType/UpdateWearableType.vue @@ -1,43 +1,37 @@ + +