From 2b3231e26cebaeee26fa339b262bc71930422ae6 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Mon, 24 Mar 2025 15:12:03 +0100 Subject: [PATCH 01/32] vehicle and equipment base --- .../unit/equipment/CreateEquipmentModal.vue | 157 ++++++++++++++++++ .../unit/equipment/EquipmentListItem.vue | 33 ++++ .../admin/unit/vehicle/CreateVehicleModal.vue | 157 ++++++++++++++++++ .../admin/unit/vehicle/VehicleListItem.vue | 31 ++++ src/router/index.ts | 37 +++++ src/stores/admin/navigation.ts | 9 +- src/stores/admin/unit/equipment/equipment.ts | 128 ++++++++++++++ src/stores/admin/unit/vehicle/vehicle.ts | 128 ++++++++++++++ src/types/permissionTypes.ts | 22 ++- .../admin/unit/equipment/equipment.models.ts | 39 +++++ .../admin/unit/vehicle/vehicle.models.ts | 39 +++++ src/views/admin/unit/equipment/Equipment.vue | 70 ++++++++ src/views/admin/unit/vehicle/Vehicle.vue | 70 ++++++++ 13 files changed, 912 insertions(+), 8 deletions(-) create mode 100644 src/components/admin/unit/equipment/CreateEquipmentModal.vue create mode 100644 src/components/admin/unit/equipment/EquipmentListItem.vue create mode 100644 src/components/admin/unit/vehicle/CreateVehicleModal.vue create mode 100644 src/components/admin/unit/vehicle/VehicleListItem.vue create mode 100644 src/stores/admin/unit/equipment/equipment.ts create mode 100644 src/stores/admin/unit/vehicle/vehicle.ts create mode 100644 src/viewmodels/admin/unit/equipment/equipment.models.ts create mode 100644 src/viewmodels/admin/unit/vehicle/vehicle.models.ts create mode 100644 src/views/admin/unit/equipment/Equipment.vue create mode 100644 src/views/admin/unit/vehicle/Vehicle.vue diff --git a/src/components/admin/unit/equipment/CreateEquipmentModal.vue b/src/components/admin/unit/equipment/CreateEquipmentModal.vue new file mode 100644 index 0000000..4f934d7 --- /dev/null +++ b/src/components/admin/unit/equipment/CreateEquipmentModal.vue @@ -0,0 +1,157 @@ + + + + + diff --git a/src/components/admin/unit/equipment/EquipmentListItem.vue b/src/components/admin/unit/equipment/EquipmentListItem.vue new file mode 100644 index 0000000..8eed147 --- /dev/null +++ b/src/components/admin/unit/equipment/EquipmentListItem.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/src/components/admin/unit/vehicle/CreateVehicleModal.vue b/src/components/admin/unit/vehicle/CreateVehicleModal.vue new file mode 100644 index 0000000..19fe092 --- /dev/null +++ b/src/components/admin/unit/vehicle/CreateVehicleModal.vue @@ -0,0 +1,157 @@ + + + + + diff --git a/src/components/admin/unit/vehicle/VehicleListItem.vue b/src/components/admin/unit/vehicle/VehicleListItem.vue new file mode 100644 index 0000000..5ac56f5 --- /dev/null +++ b/src/components/admin/unit/vehicle/VehicleListItem.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/src/router/index.ts b/src/router/index.ts index 503ce7f..65d07b0 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -310,6 +310,43 @@ const router = createRouter({ component: () => import("@/views/RouterView.vue"), meta: { type: "read", section: "unit" }, beforeEnter: [abilityAndNavUpdate], + children: [ + { + path: "", + name: "admin-unit-default", + component: () => import("@/views/admin/ViewSelect.vue"), + meta: { type: "read", section: "unit" }, + beforeEnter: [abilityAndNavUpdate], + }, + { + path: "equipment", + name: "admin-unit-equipment-route", + component: () => import("@/views/RouterView.vue"), + meta: { type: "read", section: "unit", module: "equipment" }, + beforeEnter: [abilityAndNavUpdate], + children: [ + { + path: "", + name: "admin-unit-equipment", + component: () => import("@/views/admin/unit/equipment/Equipment.vue"), + }, + ], + }, + { + path: "vehicle", + name: "admin-unit-vehicle-route", + component: () => import("@/views/RouterView.vue"), + meta: { type: "read", section: "unit", module: "vehicle" }, + beforeEnter: [abilityAndNavUpdate], + children: [ + { + path: "", + name: "admin-unit-vehicle", + component: () => import("@/views/admin/unit/vehicle/Vehicle.vue"), + }, + ], + }, + ], }, { path: "configuration", diff --git a/src/stores/admin/navigation.ts b/src/stores/admin/navigation.ts index a17bba9..f11acbf 100644 --- a/src/stores/admin/navigation.ts +++ b/src/stores/admin/navigation.ts @@ -62,7 +62,7 @@ export const useNavigationStore = defineStore("navigation", { { key: "unit", title: "Wehr", - levelDefault: "", + levelDefault: "equipment", } as topLevelNavigationModel, ] : []), @@ -104,6 +104,13 @@ export const useNavigationStore = defineStore("navigation", { ...(abilityStore.can("read", "club", "listprint") ? [{ key: "listprint", title: "Liste Drucken" }] : []), ], }, + unit: { + mainTitle: "Wehr", + main: [ + ...(abilityStore.can("read", "unit", "equipment") ? [{ key: "equipment", title: "Gerätschaften" }] : []), + ...(abilityStore.can("read", "unit", "vehicle") ? [{ key: "vehicle", title: "Fahrzeuge" }] : []), + ], + }, configuration: { mainTitle: "Einstellungen", main: [ diff --git a/src/stores/admin/unit/equipment/equipment.ts b/src/stores/admin/unit/equipment/equipment.ts new file mode 100644 index 0000000..b0611ae --- /dev/null +++ b/src/stores/admin/unit/equipment/equipment.ts @@ -0,0 +1,128 @@ +import { defineStore } from "pinia"; +import type { + EquipmentViewModel, + CreateEquipmentViewModel, + EquipmentStatisticsViewModel, + UpdateEquipmentViewModel, +} from "@/viewmodels/admin/unit/equipment/equipment.models"; +import { http } from "@/serverCom"; +import type { AxiosResponse } from "axios"; + +export const useEquipmentStore = defineStore("equipment", { + state: () => { + return { + equipments: [] as Array, + totalCount: 0 as number, + loading: "loading" as "loading" | "fetched" | "failed", + activeEquipment: null as string | null, + activeEquipmentObj: null as EquipmentViewModel | null, + activeEquipmentStatistics: null as EquipmentStatisticsViewModel | null, + loadingActive: "loading" as "loading" | "fetched" | "failed", + }; + }, + actions: { + fetchEquipments(offset = 0, count = 25, search = "", clear = false) { + if (clear) this.equipments = []; + this.loading = "loading"; + http + .get(`/admin/equipment?offset=${offset}&count=${count}${search != "" ? "&search=" + search : ""}`) + .then((result) => { + this.totalCount = result.data.total; + result.data.equipments + .filter((elem: EquipmentViewModel) => this.equipments.findIndex((m) => m.id == elem.id) == -1) + .map((elem: EquipmentViewModel, index: number): EquipmentViewModel & { tab_pos: number } => { + return { + ...elem, + tab_pos: index + offset, + }; + }) + .forEach((elem: EquipmentViewModel & { tab_pos: number }) => { + this.equipments.push(elem); + }); + this.loading = "fetched"; + }) + .catch((err) => { + this.loading = "failed"; + }); + }, + async getAllEquipments(): Promise> { + return await http.get(`/admin/equipment?noLimit=true`).then((res) => { + return { ...res, data: res.data.equipments }; + }); + }, + async getEquipmentsByIds(ids: Array): Promise> { + return await http + .post(`/admin/equipment/ids`, { + ids, + }) + .then((res) => { + return { ...res, data: res.data.equipments }; + }); + }, + async searchEquipments(search: string): Promise> { + return await http.get(`/admin/equipment?search=${search}&noLimit=true`).then((res) => { + return { ...res, data: res.data.equipments }; + }); + }, + fetchEquipmentByActiveId() { + this.loadingActive = "loading"; + http + .get(`/admin/equipment/${this.activeEquipment}`) + .then((res) => { + this.activeEquipmentObj = res.data; + this.loadingActive = "fetched"; + }) + .catch((err) => { + this.loadingActive = "failed"; + }); + }, + fetchEquipmentById(id: string) { + return http.get(`/admin/equipment/${id}`); + }, + fetchEquipmentStatisticsByActiveId() { + http + .get(`/admin/equipment/${this.activeEquipment}/statistics`) + .then((res) => { + this.activeEquipmentStatistics = res.data; + }) + .catch((err) => {}); + }, + async printEquipmentByActiveId() { + return http.get(`/admin/equipment/${this.activeEquipment}/print`, { + responseType: "blob", + }); + }, + fetchEquipmentStatisticsById(id: string) { + return http.get(`/admin/equipment/${id}/statistics`); + }, + async createEquipment(equipment: CreateEquipmentViewModel): Promise> { + const result = await http.post(`/admin/equipment`, { + salutationId: equipment.salutationId, + firstname: equipment.firstname, + lastname: equipment.lastname, + nameaffix: equipment.nameaffix, + birthdate: equipment.birthdate, + internalId: equipment.internalId, + }); + this.fetchEquipments(); + return result; + }, + async updateActiveEquipment(equipment: UpdateEquipmentViewModel): Promise> { + const result = await http.patch(`/admin/equipment/${equipment.id}`, { + salutationId: equipment.salutationId, + firstname: equipment.firstname, + lastname: equipment.lastname, + nameaffix: equipment.nameaffix, + birthdate: equipment.birthdate, + internalId: equipment.internalId, + }); + this.fetchEquipments(); + return result; + }, + async deleteEquipment(equipment: number): Promise> { + const result = await http.delete(`/admin/equipment/${equipment}`); + this.fetchEquipments(); + return result; + }, + }, +}); diff --git a/src/stores/admin/unit/vehicle/vehicle.ts b/src/stores/admin/unit/vehicle/vehicle.ts new file mode 100644 index 0000000..5b3e669 --- /dev/null +++ b/src/stores/admin/unit/vehicle/vehicle.ts @@ -0,0 +1,128 @@ +import { defineStore } from "pinia"; +import type { + VehicleViewModel, + CreateVehicleViewModel, + VehicleStatisticsViewModel, + UpdateVehicleViewModel, +} from "@/viewmodels/admin/unit/vehicle/vehicle.models"; +import { http } from "@/serverCom"; +import type { AxiosResponse } from "axios"; + +export const useVehicleStore = defineStore("vehicle", { + state: () => { + return { + vehicles: [] as Array, + totalCount: 0 as number, + loading: "loading" as "loading" | "fetched" | "failed", + activeVehicle: null as string | null, + activeVehicleObj: null as VehicleViewModel | null, + activeVehicleStatistics: null as VehicleStatisticsViewModel | null, + loadingActive: "loading" as "loading" | "fetched" | "failed", + }; + }, + actions: { + fetchVehicles(offset = 0, count = 25, search = "", clear = false) { + if (clear) this.vehicles = []; + this.loading = "loading"; + http + .get(`/admin/vehicle?offset=${offset}&count=${count}${search != "" ? "&search=" + search : ""}`) + .then((result) => { + this.totalCount = result.data.total; + result.data.vehicles + .filter((elem: VehicleViewModel) => this.vehicles.findIndex((m) => m.id == elem.id) == -1) + .map((elem: VehicleViewModel, index: number): VehicleViewModel & { tab_pos: number } => { + return { + ...elem, + tab_pos: index + offset, + }; + }) + .forEach((elem: VehicleViewModel & { tab_pos: number }) => { + this.vehicles.push(elem); + }); + this.loading = "fetched"; + }) + .catch((err) => { + this.loading = "failed"; + }); + }, + async getAllVehicles(): Promise> { + return await http.get(`/admin/vehicle?noLimit=true`).then((res) => { + return { ...res, data: res.data.vehicles }; + }); + }, + async getVehiclesByIds(ids: Array): Promise> { + return await http + .post(`/admin/vehicle/ids`, { + ids, + }) + .then((res) => { + return { ...res, data: res.data.vehicles }; + }); + }, + async searchVehicles(search: string): Promise> { + return await http.get(`/admin/vehicle?search=${search}&noLimit=true`).then((res) => { + return { ...res, data: res.data.vehicles }; + }); + }, + fetchVehicleByActiveId() { + this.loadingActive = "loading"; + http + .get(`/admin/vehicle/${this.activeVehicle}`) + .then((res) => { + this.activeVehicleObj = res.data; + this.loadingActive = "fetched"; + }) + .catch((err) => { + this.loadingActive = "failed"; + }); + }, + fetchVehicleById(id: string) { + return http.get(`/admin/vehicle/${id}`); + }, + fetchVehicleStatisticsByActiveId() { + http + .get(`/admin/vehicle/${this.activeVehicle}/statistics`) + .then((res) => { + this.activeVehicleStatistics = res.data; + }) + .catch((err) => {}); + }, + async printVehicleByActiveId() { + return http.get(`/admin/vehicle/${this.activeVehicle}/print`, { + responseType: "blob", + }); + }, + fetchVehicleStatisticsById(id: string) { + return http.get(`/admin/vehicle/${id}/statistics`); + }, + async createVehicle(vehicle: CreateVehicleViewModel): Promise> { + const result = await http.post(`/admin/vehicle`, { + salutationId: vehicle.salutationId, + firstname: vehicle.firstname, + lastname: vehicle.lastname, + nameaffix: vehicle.nameaffix, + birthdate: vehicle.birthdate, + internalId: vehicle.internalId, + }); + this.fetchVehicles(); + return result; + }, + async updateActiveVehicle(vehicle: UpdateVehicleViewModel): Promise> { + const result = await http.patch(`/admin/vehicle/${vehicle.id}`, { + salutationId: vehicle.salutationId, + firstname: vehicle.firstname, + lastname: vehicle.lastname, + nameaffix: vehicle.nameaffix, + birthdate: vehicle.birthdate, + internalId: vehicle.internalId, + }); + this.fetchVehicles(); + return result; + }, + async deleteVehicle(vehicle: number): Promise> { + const result = await http.delete(`/admin/vehicle/${vehicle}`); + this.fetchVehicles(); + return result; + }, + }, +}); diff --git a/src/types/permissionTypes.ts b/src/types/permissionTypes.ts index 8dae3d3..8a686a9 100644 --- a/src/types/permissionTypes.ts +++ b/src/types/permissionTypes.ts @@ -1,27 +1,33 @@ export type PermissionSection = "club" | "unit" | "configuration" | "management"; export type PermissionModule = + // club | "member" | "calendar" | "newsletter" - | "newsletter_config" | "protocol" + | "query" | "listprint" + // unit + | "equipment" + | "vehicle" + // configuration | "qualification" | "award" | "executive_position" | "communication_type" | "membership_status" + | "newsletter_config" | "salutation" | "calendar_type" - | "user" - | "role" - | "webapi" - | "query" | "query_store" | "template" | "template_usage" - | "backup"; + | "backup" + // management + | "user" + | "role" + | "webapi"; export type PermissionType = "read" | "create" | "update" | "delete"; @@ -52,6 +58,8 @@ export const permissionModules: Array = [ "newsletter_config", "protocol", "listprint", + "equipment", + "vehicle", "qualification", "award", "executive_position", @@ -71,7 +79,7 @@ export const permissionModules: Array = [ export const permissionTypes: Array = ["read", "create", "update", "delete"]; export const sectionsAndModules: SectionsAndModulesObject = { club: ["member", "calendar", "newsletter", "protocol", "query", "listprint"], - unit: [], + unit: ["equipment", "vehicle"], configuration: [ "qualification", "award", diff --git a/src/viewmodels/admin/unit/equipment/equipment.models.ts b/src/viewmodels/admin/unit/equipment/equipment.models.ts new file mode 100644 index 0000000..4ea40a5 --- /dev/null +++ b/src/viewmodels/admin/unit/equipment/equipment.models.ts @@ -0,0 +1,39 @@ +export interface EquipmentViewModel { + id: string; + firstname: string; + lastname: string; + nameaffix: string; + birthdate: Date; + internalId?: string; +} + +export interface EquipmentStatisticsViewModel { + id: string; + salutation: string; + firstname: string; + lastname: string; + nameaffix: string; + birthdate: Date; + todayAge: number; + ageThisYear: number; + exactAge: string; +} + +export interface CreateEquipmentViewModel { + salutationId: number; + firstname: string; + lastname: string; + nameaffix: string; + birthdate: Date; + internalId?: string; +} + +export interface UpdateEquipmentViewModel { + id: string; + salutationId: number; + firstname: string; + lastname: string; + nameaffix: string; + birthdate: Date; + internalId?: string; +} diff --git a/src/viewmodels/admin/unit/vehicle/vehicle.models.ts b/src/viewmodels/admin/unit/vehicle/vehicle.models.ts new file mode 100644 index 0000000..d35fe94 --- /dev/null +++ b/src/viewmodels/admin/unit/vehicle/vehicle.models.ts @@ -0,0 +1,39 @@ +export interface VehicleViewModel { + id: string; + firstname: string; + lastname: string; + nameaffix: string; + birthdate: Date; + internalId?: string; +} + +export interface VehicleStatisticsViewModel { + id: string; + salutation: string; + firstname: string; + lastname: string; + nameaffix: string; + birthdate: Date; + todayAge: number; + ageThisYear: number; + exactAge: string; +} + +export interface CreateVehicleViewModel { + salutationId: number; + firstname: string; + lastname: string; + nameaffix: string; + birthdate: Date; + internalId?: string; +} + +export interface UpdateVehicleViewModel { + id: string; + salutationId: number; + firstname: string; + lastname: string; + nameaffix: string; + birthdate: Date; + internalId?: string; +} diff --git a/src/views/admin/unit/equipment/Equipment.vue b/src/views/admin/unit/equipment/Equipment.vue new file mode 100644 index 0000000..4348010 --- /dev/null +++ b/src/views/admin/unit/equipment/Equipment.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/src/views/admin/unit/vehicle/Vehicle.vue b/src/views/admin/unit/vehicle/Vehicle.vue new file mode 100644 index 0000000..6b16546 --- /dev/null +++ b/src/views/admin/unit/vehicle/Vehicle.vue @@ -0,0 +1,70 @@ + + + + + From 2a77a950f5902ba6e20caad1e3ad617bedac95e5 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Mon, 24 Mar 2025 16:18:23 +0100 Subject: [PATCH 02/32] code scanner --- package-lock.json | 64 +++++++++ package.json | 1 + src/components/CodeDetector.vue | 73 ++++++++++ src/components/Modal.vue | 3 +- src/components/Pagination.vue | 96 ++----------- src/helpers/codeScanner.ts | 143 +++++++++++++++++++ src/stores/modal.ts | 13 +- src/views/admin/unit/equipment/Equipment.vue | 5 +- src/views/admin/unit/vehicle/Vehicle.vue | 5 +- 9 files changed, 312 insertions(+), 91 deletions(-) create mode 100644 src/components/CodeDetector.vue create mode 100644 src/helpers/codeScanner.ts diff --git a/package-lock.json b/package-lock.json index 58c2a95..4a87af7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "unplugin-vue-markdown": "^0.28.0", "uuid": "^9.0.0", "vue": "^3.4.29", + "vue-qrcode-reader": "^5.7.1", "vue-router": "^4.3.3" }, "devDependencies": { @@ -3080,6 +3081,18 @@ "@types/underscore": "*" } }, + "node_modules/@types/dom-webcodecs": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.14.tgz", + "integrity": "sha512-ba9aF0qARLLQpLihONIRbj8VvAdUxO+5jIxlscVcDAQTcJmq5qVr781+ino5qbQUJUmO21cLP2eLeXYWzao5Vg==", + "license": "MIT" + }, + "node_modules/@types/emscripten": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.40.0.tgz", + "integrity": "sha512-MD2JJ25S4tnjnhjWyalMS6K6p0h+zQV6+Ylm+aGbiS8tSn/aHLSGNzBgduj6FB4zH0ax2GRMGYi/8G1uOxhXWA==", + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", @@ -4109,6 +4122,16 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/barcode-detector": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.2.2.tgz", + "integrity": "sha512-JcSekql+EV93evfzF9zBr+Y6aRfkR+QFvgyzbwQ0dbymZXoAI9+WgT7H1E429f+3RKNncHz2CW98VQtaaKpmfQ==", + "license": "MIT", + "dependencies": { + "@types/dom-webcodecs": "^0.1.11", + "zxing-wasm": "1.1.3" + } + }, "node_modules/bare-events": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", @@ -8696,6 +8719,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sdp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz", + "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==", + "license": "MIT" + }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -10167,6 +10196,19 @@ "eslint": ">=6.0.0" } }, + "node_modules/vue-qrcode-reader": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/vue-qrcode-reader/-/vue-qrcode-reader-5.7.1.tgz", + "integrity": "sha512-7QBu3PqaPJHxobiDLqgcrp6wsjdTk9GJWhRCd4CgQYi93gBw/sIXNNWtbjeKz8d3QYj13n9dyPvcPMUcGOsBHw==", + "license": "MIT", + "dependencies": { + "barcode-detector": "2.2.2", + "webrtc-adapter": "8.2.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/vue-router": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.3.tgz", @@ -10210,6 +10252,19 @@ "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", "license": "MIT" }, + "node_modules/webrtc-adapter": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.2.3.tgz", + "integrity": "sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==", + "license": "BSD-3-Clause", + "dependencies": { + "sdp": "^3.2.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, "node_modules/whatwg-url": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", @@ -10841,6 +10896,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zxing-wasm": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-1.1.3.tgz", + "integrity": "sha512-MYm9k/5YVs4ZOTIFwlRjfFKD0crhefgbnt1+6TEpmKUDFp3E2uwqGSKwQOd2hOIsta/7Usq4hnpNRYTLoljnfA==", + "license": "MIT", + "dependencies": { + "@types/emscripten": "^1.39.10" + } } } } diff --git a/package.json b/package.json index bb37882..32aab8c 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "unplugin-vue-markdown": "^0.28.0", "uuid": "^9.0.0", "vue": "^3.4.29", + "vue-qrcode-reader": "^5.7.1", "vue-router": "^4.3.3" }, "devDependencies": { diff --git a/src/components/CodeDetector.vue b/src/components/CodeDetector.vue new file mode 100644 index 0000000..1832f1a --- /dev/null +++ b/src/components/CodeDetector.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/components/Modal.vue b/src/components/Modal.vue index fac5fcf..2b296bd 100644 --- a/src/components/Modal.vue +++ b/src/components/Modal.vue @@ -9,6 +9,7 @@ @@ -23,7 +24,7 @@ import { useModalStore } from "@/stores/modal"; - - diff --git a/src/helpers/codeScanner.ts b/src/helpers/codeScanner.ts new file mode 100644 index 0000000..bf3c026 --- /dev/null +++ b/src/helpers/codeScanner.ts @@ -0,0 +1,143 @@ +import type { BarcodeFormat, DetectedBarcode } from "barcode-detector/pure"; + +/*** select camera ***/ +export interface Camera { + label: string; + constraints: { + deviceId?: string; + facingMode: string; + }; +} +export const defaultConstraintOptions: Array = [ + { label: "rear camera", constraints: { facingMode: "environment" } }, + { label: "front camera", constraints: { facingMode: "user" } }, +]; + +export async function getAvailableCameras(): Promise> { + // NOTE: on iOS we can't invoke `enumerateDevices` before the user has given + // camera access permission. `QrcodeStream` internally takes care of + // requesting the permissions. The `camera-on` event should guarantee that this + // has happened. + const devices = await navigator.mediaDevices.enumerateDevices(); + const videoDevices = devices.filter(({ kind }) => kind === "videoinput"); + + return [ + ...defaultConstraintOptions, + ...videoDevices.map(({ deviceId, label }) => ({ + label: `${label} (ID: ${deviceId})`, + constraints: { deviceId, facingMode: "custom" }, + })), + ]; +} + +/*** track functons ***/ +export function paintOutline(detectedCodes: DetectedBarcode[], ctx: CanvasRenderingContext2D) { + for (const detectedCode of detectedCodes) { + const [firstPoint, ...otherPoints] = detectedCode.cornerPoints; + + ctx.strokeStyle = "red"; + + ctx.beginPath(); + ctx.moveTo(firstPoint.x, firstPoint.y); + for (const { x, y } of otherPoints) { + ctx.lineTo(x, y); + } + ctx.lineTo(firstPoint.x, firstPoint.y); + ctx.closePath(); + ctx.stroke(); + } +} +export function paintBoundingBox(detectedCodes: DetectedBarcode[], ctx: CanvasRenderingContext2D) { + for (const detectedCode of detectedCodes) { + const { + boundingBox: { x, y, width, height }, + } = detectedCode; + + ctx.lineWidth = 2; + ctx.strokeStyle = "#007bff"; + ctx.strokeRect(x, y, width, height); + } +} +export function paintCenterText(detectedCodes: DetectedBarcode[], ctx: CanvasRenderingContext2D) { + for (const detectedCode of detectedCodes) { + const { boundingBox, rawValue } = detectedCode; + + const centerX = boundingBox.x + boundingBox.width / 2; + const centerY = boundingBox.y + boundingBox.height / 2; + + const fontSize = Math.max(12, (50 * boundingBox.width) / ctx.canvas.width); + + ctx.font = `bold ${fontSize}px sans-serif`; + ctx.textAlign = "center"; + + ctx.lineWidth = 3; + ctx.strokeStyle = "#35495e"; + ctx.strokeText(detectedCode.rawValue, centerX, centerY); + + ctx.fillStyle = "#5cb984"; + ctx.fillText(rawValue, centerX, centerY); + } +} +export const trackFunctionOptions = [ + { text: "nothing (default)", value: undefined }, + { text: "outline", value: paintOutline }, + { text: "centered text", value: paintCenterText }, + { text: "bounding box", value: paintBoundingBox }, + { + text: "mixed", + value: (detectedCodes: DetectedBarcode[], ctx: CanvasRenderingContext2D) => { + paintOutline(detectedCodes, ctx); + paintCenterText(detectedCodes, ctx); + }, + }, +]; + +/*** barcode formats ***/ +export const barcodeFormats: Array = [ + "aztec", + "code_128", + "code_39", + "code_93", + "codabar", + "databar", + "databar_expanded", + "data_matrix", + "dx_film_edge", + "ean_13", + "ean_8", + "itf", + "maxi_code", + "micro_qr_code", + "pdf417", + "qr_code", + "rm_qr_code", + "upc_a", + "upc_e", + "linear_codes", + "matrix_codes", +]; + +/*** error handling ***/ +export function handleScannerError(err: Error) { + let error = `[${err.name}]: `; + + if (err.name === "NotAllowedError") { + error += "you need to grant camera access permission"; + } else if (err.name === "NotFoundError") { + error += "no camera on this device"; + } else if (err.name === "NotSupportedError") { + error += "secure context required (HTTPS, localhost)"; + } else if (err.name === "NotReadableError") { + error += "is the camera already in use?"; + } else if (err.name === "OverconstrainedError") { + error += "installed cameras are not suitable"; + } else if (err.name === "StreamApiNotSupportedError") { + error += "Stream API is not supported in this browser"; + } else if (err.name === "InsecureContextError") { + error += "Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP."; + } else { + error += err.message; + } + + return error; +} diff --git a/src/stores/modal.ts b/src/stores/modal.ts index cdc4c49..a537848 100644 --- a/src/stores/modal.ts +++ b/src/stores/modal.ts @@ -4,19 +4,22 @@ export const useModalStore = defineStore("modal", { state: () => { return { show: false, - component_ref: null as any, - data: null as any, + component_ref: undefined as any, + data: undefined as any, + callback: undefined as undefined | Function, }; }, actions: { - openModal(component_ref: any, data?: any) { + openModal(component_ref: any, data?: any, callback?: Function) { this.component_ref = component_ref; this.data = data; + this.callback = callback; this.show = true; }, closeModal() { - this.component_ref = null; - this.data = null; + this.component_ref = undefined; + this.data = undefined; + this.callback = undefined; this.show = false; }, }, diff --git a/src/views/admin/unit/equipment/Equipment.vue b/src/views/admin/unit/equipment/Equipment.vue index 4348010..a3e6cc8 100644 --- a/src/views/admin/unit/equipment/Equipment.vue +++ b/src/views/admin/unit/equipment/Equipment.vue @@ -8,10 +8,11 @@ @@ -15,12 +46,35 @@ import { defineComponent } from "vue"; import { mapActions, mapState } from "pinia"; import MainTemplate from "@/templates/Main.vue"; +import { useAbilityStore } from "@/stores/ability"; +import { useDamageReportStore } from "@/stores/admin/unit/damageReport/damageReport"; +import type { DamageReportViewModel } from "@/viewmodels/admin/unit/damageReport/damageReport.models"; +import Pagination from "@/components/Pagination.vue"; +import DamageReportListItem from "../../../../components/admin/unit/damageReport/DamageReportListItem.vue"; diff --git a/src/views/admin/unit/equipmentType/EquipmentType.vue b/src/views/admin/unit/equipmentType/EquipmentType.vue index 3c09340..921ee77 100644 --- a/src/views/admin/unit/equipmentType/EquipmentType.vue +++ b/src/views/admin/unit/equipmentType/EquipmentType.vue @@ -12,7 +12,6 @@ :totalCount="totalCount" :indicateLoading="loading == 'loading'" useSearch - useScanner @load-data="(offset, count, search) => fetchEquipmentTypes(offset, count, search)" @search="(search) => fetchEquipmentTypes(0, maxEntriesPerPage, search, true)" > diff --git a/src/views/admin/unit/respiratoryGear/RespiratoryGear.vue b/src/views/admin/unit/respiratoryGear/RespiratoryGear.vue index c1531cc..ebf2f4f 100644 --- a/src/views/admin/unit/respiratoryGear/RespiratoryGear.vue +++ b/src/views/admin/unit/respiratoryGear/RespiratoryGear.vue @@ -8,16 +8,15 @@ diff --git a/src/stores/admin/unit/damageReport/damageReport.ts b/src/stores/admin/unit/damageReport/damageReport.ts index aa761e7..903fc36 100644 --- a/src/stores/admin/unit/damageReport/damageReport.ts +++ b/src/stores/admin/unit/damageReport/damageReport.ts @@ -68,24 +68,14 @@ export const useDamageReportStore = defineStore("damageReport", { }, async createDamageReport(damageReport: CreateDamageReportViewModel): Promise> { const result = await http.post(`/admin/damageReport`, { - salutationId: damageReport.salutationId, - firstname: damageReport.firstname, - lastname: damageReport.lastname, - nameaffix: damageReport.nameaffix, - birthdate: damageReport.birthdate, - internalId: damageReport.internalId, + // TODO: data }); this.fetchDamageReports(); return result; }, async updateDamageReport(damageReport: UpdateDamageReportViewModel): Promise> { const result = await http.patch(`/admin/damageReport/${damageReport.id}`, { - salutationId: damageReport.salutationId, - firstname: damageReport.firstname, - lastname: damageReport.lastname, - nameaffix: damageReport.nameaffix, - birthdate: damageReport.birthdate, - internalId: damageReport.internalId, + // TODO: data }); this.fetchDamageReports(); return result; diff --git a/src/stores/admin/unit/equipment/equipment.ts b/src/stores/admin/unit/equipment/equipment.ts index 42b368b..13185a1 100644 --- a/src/stores/admin/unit/equipment/equipment.ts +++ b/src/stores/admin/unit/equipment/equipment.ts @@ -2,9 +2,8 @@ import { defineStore } from "pinia"; import type { EquipmentViewModel, CreateEquipmentViewModel, - EquipmentStatisticsViewModel, UpdateEquipmentViewModel, -} from "@/viewmodels/admin/unit/equipmentType/equipment.models"; +} from "@/viewmodels/admin/unit/equipment/equipment.models"; import { http } from "@/serverCom"; import type { AxiosResponse } from "axios"; @@ -16,7 +15,6 @@ export const useEquipmentStore = defineStore("equipment", { loading: "loading" as "loading" | "fetched" | "failed", activeEquipment: null as string | null, activeEquipmentObj: null as EquipmentViewModel | null, - activeEquipmentStatistics: null as EquipmentStatisticsViewModel | null, loadingActive: "loading" as "loading" | "fetched" | "failed", }; }, @@ -79,14 +77,6 @@ export const useEquipmentStore = defineStore("equipment", { fetchEquipmentById(id: string) { return http.get(`/admin/equipment/${id}`); }, - fetchEquipmentStatisticsByActiveId() { - http - .get(`/admin/equipment/${this.activeEquipment}/statistics`) - .then((res) => { - this.activeEquipmentStatistics = res.data; - }) - .catch((err) => {}); - }, async printEquipmentByActiveId() { return http.get(`/admin/equipment/${this.activeEquipment}/print`, { responseType: "blob", @@ -97,24 +87,14 @@ export const useEquipmentStore = defineStore("equipment", { }, async createEquipment(equipment: CreateEquipmentViewModel): Promise> { const result = await http.post(`/admin/equipment`, { - salutationId: equipment.salutationId, - firstname: equipment.firstname, - lastname: equipment.lastname, - nameaffix: equipment.nameaffix, - birthdate: equipment.birthdate, - internalId: equipment.internalId, + // TODO: data }); this.fetchEquipments(); return result; }, async updateActiveEquipment(equipment: UpdateEquipmentViewModel): Promise> { const result = await http.patch(`/admin/equipment/${equipment.id}`, { - salutationId: equipment.salutationId, - firstname: equipment.firstname, - lastname: equipment.lastname, - nameaffix: equipment.nameaffix, - birthdate: equipment.birthdate, - internalId: equipment.internalId, + // TODO: data }); this.fetchEquipments(); return result; diff --git a/src/stores/admin/unit/equipmentType/equipmentType.ts b/src/stores/admin/unit/equipmentType/equipmentType.ts index 40b377e..cbe9956 100644 --- a/src/stores/admin/unit/equipmentType/equipmentType.ts +++ b/src/stores/admin/unit/equipmentType/equipmentType.ts @@ -3,7 +3,7 @@ import type { EquipmentTypeViewModel, CreateEquipmentTypeViewModel, UpdateEquipmentTypeViewModel, -} from "@/viewmodels/admin/unit/equipmentType.models"; +} from "@/viewmodels/admin/unit/equipmentType/equipmentType.models"; import { http } from "@/serverCom"; import type { AxiosResponse } from "axios"; @@ -79,24 +79,14 @@ export const useEquipmentTypeStore = defineStore("equipmentType", { }, async createEquipmentType(equipmentType: CreateEquipmentTypeViewModel): Promise> { const result = await http.post(`/admin/equipmentType`, { - salutationId: equipmentType.salutationId, - firstname: equipmentType.firstname, - lastname: equipmentType.lastname, - nameaffix: equipmentType.nameaffix, - birthdate: equipmentType.birthdate, - internalId: equipmentType.internalId, + // TODO: data }); this.fetchEquipmentTypes(); return result; }, async updateActiveEquipmentType(equipmentType: UpdateEquipmentTypeViewModel): Promise> { const result = await http.patch(`/admin/equipmentType/${equipmentType.id}`, { - salutationId: equipmentType.salutationId, - firstname: equipmentType.firstname, - lastname: equipmentType.lastname, - nameaffix: equipmentType.nameaffix, - birthdate: equipmentType.birthdate, - internalId: equipmentType.internalId, + // TODO: data }); this.fetchEquipmentTypes(); return result; diff --git a/src/stores/admin/unit/respiratoryGear/respiratoryGear.ts b/src/stores/admin/unit/respiratoryGear/respiratoryGear.ts index 94bdc98..a153612 100644 --- a/src/stores/admin/unit/respiratoryGear/respiratoryGear.ts +++ b/src/stores/admin/unit/respiratoryGear/respiratoryGear.ts @@ -87,12 +87,7 @@ export const useRespiratoryGearStore = defineStore("respiratoryGear", { }, async createRespiratoryGear(respiratoryGear: CreateRespiratoryGearViewModel): Promise> { const result = await http.post(`/admin/respiratoryGear`, { - salutationId: respiratoryGear.salutationId, - firstname: respiratoryGear.firstname, - lastname: respiratoryGear.lastname, - nameaffix: respiratoryGear.nameaffix, - birthdate: respiratoryGear.birthdate, - internalId: respiratoryGear.internalId, + // TODO: data }); this.fetchRespiratoryGears(); return result; @@ -101,12 +96,7 @@ export const useRespiratoryGearStore = defineStore("respiratoryGear", { respiratoryGear: UpdateRespiratoryGearViewModel ): Promise> { const result = await http.patch(`/admin/respiratoryGear/${respiratoryGear.id}`, { - salutationId: respiratoryGear.salutationId, - firstname: respiratoryGear.firstname, - lastname: respiratoryGear.lastname, - nameaffix: respiratoryGear.nameaffix, - birthdate: respiratoryGear.birthdate, - internalId: respiratoryGear.internalId, + // TODO: data }); this.fetchRespiratoryGears(); return result; diff --git a/src/stores/admin/unit/respiratoryMission/respiratoryMission.ts b/src/stores/admin/unit/respiratoryMission/respiratoryMission.ts index 712a843..d5aa214 100644 --- a/src/stores/admin/unit/respiratoryMission/respiratoryMission.ts +++ b/src/stores/admin/unit/respiratoryMission/respiratoryMission.ts @@ -93,12 +93,7 @@ export const useRespiratoryMissionStore = defineStore("respiratoryMission", { respiratoryMission: CreateRespiratoryMissionViewModel ): Promise> { const result = await http.post(`/admin/respiratoryMission`, { - salutationId: respiratoryMission.salutationId, - firstname: respiratoryMission.firstname, - lastname: respiratoryMission.lastname, - nameaffix: respiratoryMission.nameaffix, - birthdate: respiratoryMission.birthdate, - internalId: respiratoryMission.internalId, + // TODO: data }); this.fetchRespiratoryMissions(); return result; @@ -107,12 +102,7 @@ export const useRespiratoryMissionStore = defineStore("respiratoryMission", { respiratoryMission: UpdateRespiratoryMissionViewModel ): Promise> { const result = await http.patch(`/admin/respiratoryMission/${respiratoryMission.id}`, { - salutationId: respiratoryMission.salutationId, - firstname: respiratoryMission.firstname, - lastname: respiratoryMission.lastname, - nameaffix: respiratoryMission.nameaffix, - birthdate: respiratoryMission.birthdate, - internalId: respiratoryMission.internalId, + // TODO: data }); this.fetchRespiratoryMissions(); return result; diff --git a/src/stores/admin/unit/respiratoryWearer/respiratoryWearer.ts b/src/stores/admin/unit/respiratoryWearer/respiratoryWearer.ts index 18bd220..67eba7b 100644 --- a/src/stores/admin/unit/respiratoryWearer/respiratoryWearer.ts +++ b/src/stores/admin/unit/respiratoryWearer/respiratoryWearer.ts @@ -93,12 +93,7 @@ export const useRespiratoryWearerStore = defineStore("respiratoryWearer", { respiratoryWearer: CreateRespiratoryWearerViewModel ): Promise> { const result = await http.post(`/admin/respiratoryWearer`, { - salutationId: respiratoryWearer.salutationId, - firstname: respiratoryWearer.firstname, - lastname: respiratoryWearer.lastname, - nameaffix: respiratoryWearer.nameaffix, - birthdate: respiratoryWearer.birthdate, - internalId: respiratoryWearer.internalId, + // TODO: data }); this.fetchRespiratoryWearers(); return result; @@ -107,12 +102,7 @@ export const useRespiratoryWearerStore = defineStore("respiratoryWearer", { respiratoryWearer: UpdateRespiratoryWearerViewModel ): Promise> { const result = await http.patch(`/admin/respiratoryWearer/${respiratoryWearer.id}`, { - salutationId: respiratoryWearer.salutationId, - firstname: respiratoryWearer.firstname, - lastname: respiratoryWearer.lastname, - nameaffix: respiratoryWearer.nameaffix, - birthdate: respiratoryWearer.birthdate, - internalId: respiratoryWearer.internalId, + // TODO: data }); this.fetchRespiratoryWearers(); return result; diff --git a/src/stores/admin/unit/vehicle/vehicle.ts b/src/stores/admin/unit/vehicle/vehicle.ts index 5b3e669..56fa419 100644 --- a/src/stores/admin/unit/vehicle/vehicle.ts +++ b/src/stores/admin/unit/vehicle/vehicle.ts @@ -2,7 +2,6 @@ import { defineStore } from "pinia"; import type { VehicleViewModel, CreateVehicleViewModel, - VehicleStatisticsViewModel, UpdateVehicleViewModel, } from "@/viewmodels/admin/unit/vehicle/vehicle.models"; import { http } from "@/serverCom"; @@ -16,7 +15,6 @@ export const useVehicleStore = defineStore("vehicle", { loading: "loading" as "loading" | "fetched" | "failed", activeVehicle: null as string | null, activeVehicleObj: null as VehicleViewModel | null, - activeVehicleStatistics: null as VehicleStatisticsViewModel | null, loadingActive: "loading" as "loading" | "fetched" | "failed", }; }, @@ -79,14 +77,6 @@ export const useVehicleStore = defineStore("vehicle", { fetchVehicleById(id: string) { return http.get(`/admin/vehicle/${id}`); }, - fetchVehicleStatisticsByActiveId() { - http - .get(`/admin/vehicle/${this.activeVehicle}/statistics`) - .then((res) => { - this.activeVehicleStatistics = res.data; - }) - .catch((err) => {}); - }, async printVehicleByActiveId() { return http.get(`/admin/vehicle/${this.activeVehicle}/print`, { responseType: "blob", @@ -97,24 +87,14 @@ export const useVehicleStore = defineStore("vehicle", { }, async createVehicle(vehicle: CreateVehicleViewModel): Promise> { const result = await http.post(`/admin/vehicle`, { - salutationId: vehicle.salutationId, - firstname: vehicle.firstname, - lastname: vehicle.lastname, - nameaffix: vehicle.nameaffix, - birthdate: vehicle.birthdate, - internalId: vehicle.internalId, + // TODO: data }); this.fetchVehicles(); return result; }, async updateActiveVehicle(vehicle: UpdateVehicleViewModel): Promise> { const result = await http.patch(`/admin/vehicle/${vehicle.id}`, { - salutationId: vehicle.salutationId, - firstname: vehicle.firstname, - lastname: vehicle.lastname, - nameaffix: vehicle.nameaffix, - birthdate: vehicle.birthdate, - internalId: vehicle.internalId, + // TODO: data }); this.fetchVehicles(); return result; diff --git a/src/viewmodels/admin/unit/damageReport/damageReport.models.ts b/src/viewmodels/admin/unit/damageReport/damageReport.models.ts index 7551f19..b21bff1 100644 --- a/src/viewmodels/admin/unit/damageReport/damageReport.models.ts +++ b/src/viewmodels/admin/unit/damageReport/damageReport.models.ts @@ -1,39 +1,20 @@ +import type { EquipmentViewModel } from "../equipment/equipment.models"; + export interface DamageReportViewModel { id: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} - -export interface DamageReportStatisticsViewModel { - id: string; - salutation: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - todayAge: number; - ageThisYear: number; - exactAge: string; + reported: Date; + status: string; + description: string; + affectedEquipmentId: string; + affectedEquipment: EquipmentViewModel; } export interface CreateDamageReportViewModel { - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + description: string; + affectedEquipmentId: string; } export interface UpdateDamageReportViewModel { id: string; - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + status: string; } diff --git a/src/viewmodels/admin/unit/equipment/equipment.models.ts b/src/viewmodels/admin/unit/equipment/equipment.models.ts new file mode 100644 index 0000000..191ffff --- /dev/null +++ b/src/viewmodels/admin/unit/equipment/equipment.models.ts @@ -0,0 +1,25 @@ +import type { EquipmentTypeViewModel } from "../equipmentType/equipmentType.models"; + +export interface EquipmentViewModel { + id: string; + code: string; + name: string; + location: string; + equipmentTypeId: string; + equipmentType: EquipmentTypeViewModel; +} + +export interface CreateEquipmentViewModel { + code: string; + name: string; + location: string; + equipmentTypeId: string; +} + +export interface UpdateEquipmentViewModel { + id: string; + code: string; + name: string; + location: string; + equipmentTypeId: string; +} diff --git a/src/viewmodels/admin/unit/equipmentType.models.ts b/src/viewmodels/admin/unit/equipmentType.models.ts deleted file mode 100644 index ee5dc54..0000000 --- a/src/viewmodels/admin/unit/equipmentType.models.ts +++ /dev/null @@ -1,39 +0,0 @@ -export interface EquipmentTypeViewModel { - id: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} - -export interface EquipmentTypeStatisticsViewModel { - id: string; - salutation: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - todayAge: number; - ageThisYear: number; - exactAge: string; -} - -export interface CreateEquipmentTypeViewModel { - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} - -export interface UpdateEquipmentTypeViewModel { - id: string; - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} diff --git a/src/viewmodels/admin/unit/equipmentType/equipment.models.ts b/src/viewmodels/admin/unit/equipmentType/equipment.models.ts deleted file mode 100644 index 4ea40a5..0000000 --- a/src/viewmodels/admin/unit/equipmentType/equipment.models.ts +++ /dev/null @@ -1,39 +0,0 @@ -export interface EquipmentViewModel { - id: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} - -export interface EquipmentStatisticsViewModel { - id: string; - salutation: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - todayAge: number; - ageThisYear: number; - exactAge: string; -} - -export interface CreateEquipmentViewModel { - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} - -export interface UpdateEquipmentViewModel { - id: string; - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} diff --git a/src/viewmodels/admin/unit/equipmentType/equipmentType.models.ts b/src/viewmodels/admin/unit/equipmentType/equipmentType.models.ts new file mode 100644 index 0000000..942dc60 --- /dev/null +++ b/src/viewmodels/admin/unit/equipmentType/equipmentType.models.ts @@ -0,0 +1,20 @@ +export interface EquipmentTypeViewModel { + id: string; + type: string; + description: string; + inspectionInterval: `${number}${"d" | "m" | "y"}`; + // attached inspection plans +} + +export interface CreateEquipmentTypeViewModel { + type: string; + description: string; + inspectionInterval: `${number}${"d" | "m" | "y"}`; +} + +export interface UpdateEquipmentTypeViewModel { + id: string; + type: string; + description: string; + inspectionInterval: `${number}${"d" | "m" | "y"}`; +} diff --git a/src/viewmodels/admin/unit/respiratoryGear/respiratoryGear.models.ts b/src/viewmodels/admin/unit/respiratoryGear/respiratoryGear.models.ts index b37c28b..07f4ec8 100644 --- a/src/viewmodels/admin/unit/respiratoryGear/respiratoryGear.models.ts +++ b/src/viewmodels/admin/unit/respiratoryGear/respiratoryGear.models.ts @@ -1,39 +1,16 @@ +import type { EquipmentViewModel } from "../equipment/equipment.models"; + export interface RespiratoryGearViewModel { id: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} - -export interface RespiratoryGearStatisticsViewModel { - id: string; - salutation: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - todayAge: number; - ageThisYear: number; - exactAge: string; + equipmentId: string; + equipment: EquipmentViewModel; } export interface CreateRespiratoryGearViewModel { - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + equipmentId: string; } export interface UpdateRespiratoryGearViewModel { id: string; - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + equipmentId: string; } diff --git a/src/viewmodels/admin/unit/respiratoryMission/respiratoryMission.models.ts b/src/viewmodels/admin/unit/respiratoryMission/respiratoryMission.models.ts index 2a19bae..49c6e7f 100644 --- a/src/viewmodels/admin/unit/respiratoryMission/respiratoryMission.models.ts +++ b/src/viewmodels/admin/unit/respiratoryMission/respiratoryMission.models.ts @@ -1,39 +1,20 @@ export interface RespiratoryMissionViewModel { id: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} - -export interface RespiratoryMissionStatisticsViewModel { - id: string; - salutation: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - todayAge: number; - ageThisYear: number; - exactAge: string; + date: Date; + title: string; + description: string; + // refs to used respiratory gear and wearers } export interface CreateRespiratoryMissionViewModel { - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + date: Date; + title: string; + description: string; } export interface UpdateRespiratoryMissionViewModel { id: string; - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + date: Date; + title: string; + description: string; } diff --git a/src/viewmodels/admin/unit/respiratoryWearer/respiratoryWearer.models.ts b/src/viewmodels/admin/unit/respiratoryWearer/respiratoryWearer.models.ts index 113ee71..027fa25 100644 --- a/src/viewmodels/admin/unit/respiratoryWearer/respiratoryWearer.models.ts +++ b/src/viewmodels/admin/unit/respiratoryWearer/respiratoryWearer.models.ts @@ -1,39 +1,16 @@ +import type { MemberViewModel } from "../../club/member/member.models"; + export interface RespiratoryWearerViewModel { id: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} - -export interface RespiratoryWearerStatisticsViewModel { - id: string; - salutation: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - todayAge: number; - ageThisYear: number; - exactAge: string; + memberId: string; + member: MemberViewModel; } export interface CreateRespiratoryWearerViewModel { - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + memberId: string; } export interface UpdateRespiratoryWearerViewModel { id: string; - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + memberId: string; } diff --git a/src/viewmodels/admin/unit/vehicle/vehicle.models.ts b/src/viewmodels/admin/unit/vehicle/vehicle.models.ts index d35fe94..27fcd98 100644 --- a/src/viewmodels/admin/unit/vehicle/vehicle.models.ts +++ b/src/viewmodels/admin/unit/vehicle/vehicle.models.ts @@ -1,39 +1,13 @@ export interface VehicleViewModel { id: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; -} - -export interface VehicleStatisticsViewModel { - id: string; - salutation: string; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - todayAge: number; - ageThisYear: number; - exactAge: string; + name: string; } export interface CreateVehicleViewModel { - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + name: string; } export interface UpdateVehicleViewModel { id: string; - salutationId: number; - firstname: string; - lastname: string; - nameaffix: string; - birthdate: Date; - internalId?: string; + name: string; } diff --git a/src/views/admin/unit/damageReport/DamageReport.vue b/src/views/admin/unit/damageReport/DamageReport.vue index 99aabac..1d7a863 100644 --- a/src/views/admin/unit/damageReport/DamageReport.vue +++ b/src/views/admin/unit/damageReport/DamageReport.vue @@ -7,12 +7,12 @@ @@ -71,11 +57,11 @@ export default defineComponent({ return { tabs: [ { route: "admin-unit-respiratory_wearer-overview", title: "Übersicht" }, - { route: "admin-unit-respiratory_wearer-xy", title: "Einsätze" }, - { route: "admin-unit-respiratory_wearer-xy", title: "Bildungen" }, - { route: "admin-unit-respiratory_wearer-xy", title: "Unterweisungen" }, - { route: "admin-unit-respiratory_wearer-xy", title: "Untersuchungen" }, - { route: "admin-unit-respiratory_wearer-xy", title: "Belastungen" }, + { route: "admin-unit-respiratory_wearer-mission", title: "Einsätze" }, + { route: "admin-unit-respiratory_wearer-education", title: "Bildungen" }, + { route: "admin-unit-respiratory_wearer-instruction", title: "Unterweisungen" }, + { route: "admin-unit-respiratory_wearer-screening", title: "Untersuchungen" }, + { route: "admin-unit-respiratory_wearer-strain", title: "Belastungen" }, ], }; }, @@ -88,13 +74,6 @@ export default defineComponent({ }, methods: { ...mapActions(useRespiratoryWearerStore, ["fetchRespiratoryWearerByActiveId"]), - ...mapActions(useModalStore, ["openModal"]), - openDeleteModal() { - this.openModal( - markRaw(defineAsyncComponent(() => import("@/components/admin/club/member/DeleteMemberModal.vue"))), - this.respiratoryWearerId ?? "" - ); - }, }, }); diff --git a/src/views/admin/unit/vehicle/Vehicle.vue b/src/views/admin/unit/vehicle/Vehicle.vue index 3998025..02fd8d4 100644 --- a/src/views/admin/unit/vehicle/Vehicle.vue +++ b/src/views/admin/unit/vehicle/Vehicle.vue @@ -21,9 +21,14 @@
- +
@@ -31,15 +36,14 @@ diff --git a/src/views/admin/unit/vehicle/VehicleRouting.vue b/src/views/admin/unit/vehicle/VehicleRouting.vue index 33bbc59..cb5accd 100644 --- a/src/views/admin/unit/vehicle/VehicleRouting.vue +++ b/src/views/admin/unit/vehicle/VehicleRouting.vue @@ -12,7 +12,6 @@ - @@ -63,9 +61,9 @@ export default defineComponent({ return { tabs: [ { route: "admin-unit-vehicle-overview", title: "Übersicht" }, - { route: "admin-unit-vehicle-xy", title: "Wartungen" }, - { route: "admin-unit-vehicle-xy", title: "Prüfungen" }, - { route: "admin-unit-vehicle-xy", title: "Schadensmeldungen" }, + { route: "admin-unit-vehicle-maintenance", title: "Wartungen" }, + { route: "admin-unit-vehicle-inspection", title: "Prüfungen" }, + { route: "admin-unit-vehicle-damage_report", title: "Schadensmeldungen" }, ], }; }, @@ -78,13 +76,6 @@ export default defineComponent({ }, methods: { ...mapActions(useVehicleStore, ["fetchVehicleByActiveId"]), - ...mapActions(useModalStore, ["openModal"]), - openDeleteModal() { - this.openModal( - markRaw(defineAsyncComponent(() => import("@/components/admin/club/member/DeleteMemberModal.vue"))), - this.vehicleId ?? "" - ); - }, }, }); From 5641dbb57f525ae83817747cc7d3bdf891814a7f Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Mon, 31 Mar 2025 10:59:41 +0200 Subject: [PATCH 11/32] equipmenttype form --- .../CreateEquipmentTypeModal.vue | 51 ++++++------------- src/demodata/equipmentType.ts | 2 +- src/router/index.ts | 4 +- .../admin/unit/equipmentType/equipmentType.ts | 2 +- .../equipmentType/equipmentType.models.ts | 6 +-- .../admin/unit/damageReport/DamageReport.vue | 2 +- .../unit/damageReport/DamageReportRouting.vue | 10 +--- .../unit/equipmentType/InspectionPlans.vue | 42 +++++++++++++++ .../admin/unit/equipmentType/Overview.vue | 47 +++++++++++++++++ 9 files changed, 114 insertions(+), 52 deletions(-) create mode 100644 src/views/admin/unit/equipmentType/InspectionPlans.vue create mode 100644 src/views/admin/unit/equipmentType/Overview.vue diff --git a/src/components/admin/unit/equipmentType/CreateEquipmentTypeModal.vue b/src/components/admin/unit/equipmentType/CreateEquipmentTypeModal.vue index b24549f..372ec7f 100644 --- a/src/components/admin/unit/equipmentType/CreateEquipmentTypeModal.vue +++ b/src/components/admin/unit/equipmentType/CreateEquipmentTypeModal.vue @@ -1,30 +1,23 @@