Introduce machine types management for Self-Serve module:

- Add `DepartmentSelfServeMachineTypes` component with pagination and table for machine types.
- Extend Self-Serve objects to support machine type attributes and CRUD operations.
- Update UI flows for managing machine types, tasks, and conditions.
- Implement reusable forms for creating and editing machine types, tasks, and conditions.
- Add API integration for machine type operations.
- Enhance translations and component reuse across Self-Serve views.
This commit is contained in:
Jeppe Bundgaard
2026-03-16 13:39:43 +01:00
parent 260fb8d8e9
commit f6050740ec
5 changed files with 711 additions and 0 deletions
@@ -0,0 +1,55 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { usePaginatedListInstance } from "@/components/pagination/paginatedList.vue";
import EditableTableColumn from "@/components/displays/buttons/EditableTableColumn.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
const { t } = useI18n();
const { loadList } = usePaginatedListInstance();
defineProps({
objects: {
type: Array,
required: true,
},
});
</script>
<template>
<table class="table is-fullwidth is-bordered">
<thead>
<tr>
<th>{{ SessionUser.objects.self_serve_machine_types.columns.id.label }}</th>
<th>{{ SessionUser.objects.self_serve_machine_types.columns.name.label }}</th>
<th>{{ SessionUser.objects.self_serve_machine_types.columns.description.label }}</th>
<th class="has-text-right">{{ t('tables.actions') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="object in objects" :key="object.id">
<td>{{ object.id }}</td>
<EditableTableColumn
:object="object"
:loadList="loadList"
column="name"
:edit-function="SessionUser.objects.self_serve_machine_types.showEditObjectFieldForm"
:permission-check-function="SessionUser.canAccessAdmin"
/>
<EditableTableColumn
:object="object"
:loadList="loadList"
column="description"
:edit-function="SessionUser.objects.self_serve_machine_types.showEditObjectFieldForm"
:permission-check-function="SessionUser.canAccessAdmin"
/>
<td class="has-text-right">
<button class="button is-small is-danger is-light" @click="SessionUser.objects.self_serve_machine_types.functions.showDeleteObjectForm(object.id, loadList)">
<span class="icon is-small">
<i class="fas fa-trash"></i>
</span>
</button>
</td>
</tr>
</tbody>
</table>
</template>
@@ -0,0 +1,61 @@
<script setup>
import { defineProps, provide, computed } from "vue";
import {
usePaginatedList,
PaginatedListKey
} from "@/components/pagination/paginatedList.vue";
import TableLabeledPagination from "@/components/displays/pagination/TableLabeledPagination.vue";
import SelfServeMachineTypesTable from "@/components/displays/department/tables/SelfServeMachineTypesTable.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps({
autoLoad: {
type: Boolean,
required: false,
default: false,
},
});
const paginatedList = usePaginatedList();
provide(PaginatedListKey, paginatedList);
const {
list,
loadList,
setEndpoint,
} = paginatedList;
setEndpoint(SessionUser.objects.self_serve_machine_types.meta.endpoint, false);
if (props.autoLoad) {
loadList();
}
const sortedList = computed(() => [...list.value]);
defineExpose({
loadList
});
</script>
<template>
<TableLabeledPagination :label="SessionUser.objects.self_serve_machine_types.meta.title">
<template #buttons="{ loadList }">
<slot name="buttons" :loadList="loadList">
<button
class="button is-primary is-small"
@click="SessionUser.objects.self_serve_machine_types.showCreateObjectForm({}, loadList)"
>
<span class="icon is-small">
<i class="fas fa-plus"></i>
</span>
<span>{{ t('common.add') }} {{ SessionUser.objects.self_serve_machine_types.meta.labels.single }}</span>
</button>
</slot>
</template>
<SelfServeMachineTypesTable :objects="sortedList" />
</TableLabeledPagination>
</template>
@@ -0,0 +1,122 @@
<script>
import { ObjectsGlobal } from "@/components/session/token/SessionUser/Objects/ObjectsGlobal.vue";
/**
* The SelfServeMachineTypes object
*/
export const SelfServeMachineTypes = {
meta: {
title: "Self-serve maskintyper",
icon: "fas fa-cubes",
description: "Genbrugelige maskintyper til self-serve",
endpoint: "/department/selfserve/machine-types",
labels: {
single: "maskintype",
multiple: "maskintyper"
}
},
columns: {
id: {
label: "ID",
type: "number",
sortable: true,
creation: {
required: false
}
},
name: {
label: "Navn",
type: "string",
sortable: true,
creation: {
required: true
}
},
description: {
label: "Beskrivelse",
type: "string",
sortable: true,
creation: {
required: false
}
},
created_at: {
label: "Oprettet",
type: "datetime",
sortable: true,
creation: {
required: false
}
},
updated_at: {
label: "Opdateret",
type: "datetime",
sortable: true,
creation: {
required: false
}
},
},
add: async (nameOrPayload, description = null) => {
const payload = typeof nameOrPayload === "object"
? nameOrPayload
: {
name: nameOrPayload,
description: description || null,
};
return ObjectsGlobal.add.object(SelfServeMachineTypes.meta.endpoint, payload);
},
set: {
name: async (id, name) => {
return ObjectsGlobal.set.column(SelfServeMachineTypes.meta.endpoint, id, "name", name);
},
description: async (id, description) => {
return ObjectsGlobal.set.column(
SelfServeMachineTypes.meta.endpoint,
id,
"description",
description || null
);
},
},
get: {
all: async (filters = {}) => {
return ObjectsGlobal.get.objects(SelfServeMachineTypes.meta.endpoint, filters);
},
single: async (id) => {
return ObjectsGlobal.get.object(SelfServeMachineTypes.meta.endpoint, id);
}
},
delete: async (id) => {
return ObjectsGlobal.delete.object(SelfServeMachineTypes.meta.endpoint, id);
},
functions: {
getMachineTypeName: async (id, fallback = null) => {
if (!id) {
return fallback ?? ObjectsGlobal.language.none;
}
const machineTypes = await SelfServeMachineTypes.get.all();
const machineType = machineTypes.find((entry) => parseInt(entry.id) === parseInt(id));
return machineType ? machineType.name : fallback ?? ObjectsGlobal.language.no_data;
},
showDeleteObjectForm: (id, onAfterSubmit = null) => {
return ObjectsGlobal.showDeleteObjectForm(SelfServeMachineTypes, id, onAfterSubmit);
},
},
showCreateObjectForm: (initialData = {}, onAfterSubmit = null) => {
return ObjectsGlobal.showCreateObjectForm(SelfServeMachineTypes, onAfterSubmit, initialData);
},
showEditObjectFieldForm: (id, column, value, onAfterSubmit = null, options = {}) => {
return ObjectsGlobal.showEditObjectFieldForm(
SelfServeMachineTypes,
id,
column,
value,
onAfterSubmit,
options
);
}
};
</script>
@@ -0,0 +1,423 @@
import Swal from "sweetalert2";
import { authenticatedRequest } from "@/components/session/authenticatedRequest.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
const escapeHtml = (value = "") => String(value)
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("\"", "&quot;");
const parseNullableInt = (value, fallback = null) => {
if (value === null || typeof value === "undefined" || value === "") {
return fallback;
}
const parsed = Number.parseInt(value, 10);
return Number.isNaN(parsed) ? fallback : parsed;
};
const parseIntOrZero = (value) => {
const parsed = Number.parseInt(value, 10);
return Number.isNaN(parsed) ? 0 : parsed;
};
const buildOptionHtml = (options, selectedValue = null) =>
options.map((option) => {
const optionValue = option?.id ?? "";
const isSelected = String(optionValue) === String(selectedValue ?? "");
return `<option value="${escapeHtml(optionValue)}" ${isSelected ? "selected" : ""}>${escapeHtml(option?.name ?? optionValue)}</option>`;
}).join("");
const getFieldValue = (id) => document.getElementById(id)?.value ?? "";
const setFieldValue = (id, value) => {
const element = document.getElementById(id);
if (element) {
element.value = value ?? "";
}
};
const setFieldDisplay = (wrapperId, visible) => {
const element = document.getElementById(wrapperId);
if (element) {
element.style.display = visible ? "block" : "none";
}
};
const populateSelect = (id, options, selectedValue = null) => {
const element = document.getElementById(id);
if (!element) {
return;
}
element.innerHTML = buildOptionHtml(options, selectedValue);
};
const getCheckedValues = (name) => Array.from(document.querySelectorAll(`input[name="${name}"]:checked`))
.map((element) => element.value);
const wrapField = (id, label, innerHtml, visible = true) => `
<div class="field" id="${id}-wrapper" style="display: ${visible ? "block" : "none"}">
<label class="label has-text-black">${escapeHtml(label)}</label>
<div class="control">${innerHtml}</div>
</div>
`;
const buildInput = (id, value = "", type = "text", min = null) =>
`<input class="input has-background-light has-text-black" type="${type}" id="${id}" value="${escapeHtml(value)}" ${min !== null ? `min="${min}"` : ""}>`;
const buildSelect = (id, options, selectedValue = null) =>
`<div class="select is-fullwidth"><select id="${id}" class="has-background-light has-text-black">${buildOptionHtml(options, selectedValue)}</select></div>`;
const buildCheckboxList = (name, options, selectedValues = []) => options.map((option) => {
const checked = selectedValues.includes(String(option.id)) || selectedValues.includes(option.id);
return `
<label class="checkbox is-block has-text-black" style="margin-bottom: 0.5rem;">
<input type="checkbox" name="${name}" value="${escapeHtml(option.id)}" ${checked ? "checked" : ""}>
${escapeHtml(option.name ?? option.id)}
</label>
`;
}).join("");
const showValidationMessage = (message) => {
Swal.showValidationMessage(message);
return false;
};
const saveRecord = async (endpoint, payload, recordId = null) => {
if (recordId) {
await authenticatedRequest(endpoint, "PUT", { id: recordId, ...payload });
return;
}
await authenticatedRequest(endpoint, "POST", payload);
};
const questionScopeModeFor = (record, initialData = {}) => {
const department = parseIntOrZero(record?.department ?? initialData.department);
const lane = parseIntOrZero(record?.lane ?? initialData.lane);
const product = parseIntOrZero(record?.product ?? initialData.product);
return department === 0 && lane === 0 && product === 0 ? "shared" : "legacy";
};
const scopedModeFor = (record, initialData = {}) => {
const machineTypeId = parseNullableInt(record?.machine_type_id ?? initialData.machine_type_id);
return machineTypeId ? "machine_type" : "legacy";
};
export const showSelfServeQuestionForm = async ({ object, record = null, initialData = {}, onAfterSubmit = null }) => {
const products = await SessionUser.objects.products.get.all();
const scopeMode = questionScopeModeFor(record, initialData);
const initialDepartment = parseIntOrZero(record?.department ?? initialData.department);
const initialLane = parseIntOrZero(record?.lane ?? initialData.lane);
const initialProduct = parseIntOrZero(record?.product ?? initialData.product);
const initialConditionId = parseNullableInt(record?.condition_id ?? initialData.condition_id, 0);
const initialOrderPriority = parseIntOrZero(record?.order_priority ?? initialData.order_priority);
const html = [
wrapField("scope_mode", "Scope", buildSelect("scope_mode", [
{ id: "shared", name: "Fælles" },
{ id: "legacy", name: "Afdeling / bane / køretøjstype" },
], scopeMode)),
wrapField("department", "Afdeling", buildInput("department", initialDepartment, "number", 0), scopeMode === "legacy"),
wrapField("lane", "Bane", buildInput("lane", initialLane, "number", 0), scopeMode === "legacy"),
wrapField("product", "Køretøjstype", buildSelect("product", [{ id: 0, name: "Ingen" }, ...products], initialProduct), scopeMode === "legacy"),
wrapField("condition_id", "Betingelse (Hvis)", buildSelect("condition_id", [{ id: 0, name: "Ingen" }], initialConditionId)),
wrapField("question", "Spørgsmål", buildInput("question", record?.question ?? initialData.question ?? "")),
wrapField("description", "Beskrivelse", buildInput("description", record?.description ?? initialData.description ?? "")),
wrapField("order_priority", "Rækkefølge", buildInput("order_priority", initialOrderPriority, "number", 0)),
].join("");
return Swal.fire({
title: record ? `Rediger ${object.meta.labels.single}` : `Opret ${object.meta.labels.single}`,
html,
showCancelButton: true,
confirmButtonText: SessionUser.objects.global.language.save,
cancelButtonText: SessionUser.objects.global.language.cancel,
didOpen: async () => {
const updateScopeVisibility = () => {
const isLegacy = getFieldValue("scope_mode") === "legacy";
setFieldDisplay("department-wrapper", isLegacy);
setFieldDisplay("lane-wrapper", isLegacy);
setFieldDisplay("product-wrapper", isLegacy);
};
const updateConditionOptions = async () => {
const isLegacy = getFieldValue("scope_mode") === "legacy";
const options = await object.columns.condition_id.options({
department: isLegacy ? getFieldValue("department") : 0,
product: isLegacy ? getFieldValue("product") : 0,
});
populateSelect("condition_id", options, getFieldValue("condition_id") || initialConditionId || 0);
};
document.getElementById("scope_mode")?.addEventListener("change", async () => {
updateScopeVisibility();
await updateConditionOptions();
});
document.getElementById("department")?.addEventListener("change", updateConditionOptions);
document.getElementById("product")?.addEventListener("change", updateConditionOptions);
updateScopeVisibility();
await updateConditionOptions();
},
preConfirm: async () => {
const payload = {
question: getFieldValue("question").trim(),
description: getFieldValue("description").trim(),
order_priority: parseIntOrZero(getFieldValue("order_priority")),
condition_id: parseNullableInt(getFieldValue("condition_id")),
};
if (!payload.question) {
return showValidationMessage("Spørgsmål er påkrævet.");
}
if (!payload.description) {
return showValidationMessage("Beskrivelse er påkrævet.");
}
if (getFieldValue("scope_mode") === "legacy") {
payload.department = parseIntOrZero(getFieldValue("department"));
payload.lane = parseIntOrZero(getFieldValue("lane"));
payload.product = parseIntOrZero(getFieldValue("product"));
} else {
payload.department = 0;
payload.lane = 0;
payload.product = 0;
}
try {
await saveRecord(object.meta.endpoint, payload, record?.id);
if (onAfterSubmit) {
await onAfterSubmit();
}
} catch (error) {
return showValidationMessage(error?.response?.data?.message || error?.message || "Kunne ikke gemme spørgsmålet.");
}
}
});
};
export const showSelfServeConditionForm = async ({ object, record = null, initialData = {}, onAfterSubmit = null }) => {
const products = await SessionUser.objects.products.get.all();
const machineTypes = await SessionUser.objects.self_serve_machine_types.get.all();
const scopeMode = scopedModeFor(record, initialData);
const initialDepartment = parseIntOrZero(record?.department ?? initialData.department);
const initialLane = parseIntOrZero(record?.lane ?? initialData.lane);
const initialProduct = parseIntOrZero(record?.product ?? initialData.product);
const initialMachineTypeId = parseNullableInt(record?.machine_type_id ?? initialData.machine_type_id, 0);
const initialConditionId = parseNullableInt(record?.condition_id ?? initialData.condition_id, 0);
const html = [
wrapField("scope_mode", "Scope", buildSelect("scope_mode", [
{ id: "machine_type", name: "Maskintype" },
{ id: "legacy", name: "Afdeling / bane / køretøjstype" },
], scopeMode)),
wrapField("machine_type_id", "Maskintype", buildSelect("machine_type_id", [{ id: 0, name: "Vælg maskintype" }, ...machineTypes], initialMachineTypeId), scopeMode === "machine_type"),
wrapField("department", "Afdeling", buildInput("department", initialDepartment, "number", 0), scopeMode === "legacy"),
wrapField("lane", "Bane", buildInput("lane", initialLane, "number", 0), scopeMode === "legacy"),
wrapField("product", "Køretøjstype", buildSelect("product", [{ id: 0, name: "Ingen" }, ...products], initialProduct), scopeMode === "legacy"),
wrapField("condition_id", "Overordnet betingelse", buildSelect("condition_id", [{ id: 0, name: "Ingen" }], initialConditionId)),
wrapField("name", "Navn", buildInput("name", record?.name ?? initialData.name ?? "")),
wrapField("description", "Beskrivelse", buildInput("description", record?.description ?? initialData.description ?? "")),
].join("");
return Swal.fire({
title: record ? `Rediger ${object.meta.labels.single}` : `Opret ${object.meta.labels.single}`,
html,
showCancelButton: true,
confirmButtonText: SessionUser.objects.global.language.save,
cancelButtonText: SessionUser.objects.global.language.cancel,
didOpen: async () => {
const updateScopeVisibility = () => {
const isMachineType = getFieldValue("scope_mode") === "machine_type";
setFieldDisplay("machine_type_id-wrapper", isMachineType);
setFieldDisplay("department-wrapper", !isMachineType);
setFieldDisplay("lane-wrapper", !isMachineType);
setFieldDisplay("product-wrapper", !isMachineType);
};
const updateConditionOptions = async () => {
const isMachineType = getFieldValue("scope_mode") === "machine_type";
const options = await object.columns.condition_id.options({
department: isMachineType ? 0 : getFieldValue("department"),
product: isMachineType ? 0 : getFieldValue("product"),
machine_type_id: isMachineType ? getFieldValue("machine_type_id") : null,
});
populateSelect("condition_id", options, getFieldValue("condition_id") || initialConditionId || 0);
};
document.getElementById("scope_mode")?.addEventListener("change", async () => {
updateScopeVisibility();
await updateConditionOptions();
});
document.getElementById("machine_type_id")?.addEventListener("change", updateConditionOptions);
document.getElementById("department")?.addEventListener("change", updateConditionOptions);
document.getElementById("product")?.addEventListener("change", updateConditionOptions);
updateScopeVisibility();
await updateConditionOptions();
},
preConfirm: async () => {
const payload = {
name: getFieldValue("name").trim(),
description: getFieldValue("description").trim(),
condition_id: parseNullableInt(getFieldValue("condition_id")),
};
if (!payload.name) {
return showValidationMessage("Navn er påkrævet.");
}
if (!payload.description) {
return showValidationMessage("Beskrivelse er påkrævet.");
}
if (getFieldValue("scope_mode") === "machine_type") {
payload.machine_type_id = parseNullableInt(getFieldValue("machine_type_id"));
payload.department = 0;
payload.lane = 0;
payload.product = 0;
if (!payload.machine_type_id) {
return showValidationMessage("Maskintype er påkrævet for denne scope.");
}
} else {
payload.machine_type_id = null;
payload.department = parseIntOrZero(getFieldValue("department"));
payload.lane = parseIntOrZero(getFieldValue("lane"));
payload.product = parseIntOrZero(getFieldValue("product"));
}
try {
await saveRecord(object.meta.endpoint, payload, record?.id);
if (onAfterSubmit) {
await onAfterSubmit();
}
} catch (error) {
return showValidationMessage(error?.response?.data?.message || error?.message || "Kunne ikke gemme betingelsen.");
}
}
});
};
export const showSelfServeTaskForm = async ({ object, record = null, initialData = {}, onAfterSubmit = null }) => {
const products = await SessionUser.objects.products.get.all();
const machineTypes = await SessionUser.objects.self_serve_machine_types.get.all();
const scopeMode = scopedModeFor(record, initialData);
const initialDepartment = parseIntOrZero(record?.department ?? initialData.department);
const initialLane = parseIntOrZero(record?.lane ?? initialData.lane);
const initialProduct = parseIntOrZero(record?.product ?? initialData.product);
const initialMachineTypeId = parseNullableInt(record?.machine_type_id ?? initialData.machine_type_id, 0);
const initialConditionId = parseNullableInt(record?.condition_id ?? initialData.condition_id, 0);
const initialOrderPriority = parseIntOrZero(record?.order_priority ?? initialData.order_priority);
const html = [
wrapField("scope_mode", "Scope", buildSelect("scope_mode", [
{ id: "machine_type", name: "Maskintype" },
{ id: "legacy", name: "Afdeling / bane / køretøjstype" },
], scopeMode)),
wrapField("machine_type_id", "Maskintype", buildSelect("machine_type_id", [{ id: 0, name: "Vælg maskintype" }, ...machineTypes], initialMachineTypeId), scopeMode === "machine_type"),
wrapField("department", "Afdeling", buildInput("department", initialDepartment, "number", 0), scopeMode === "legacy"),
wrapField("lane", "Bane", buildInput("lane", initialLane, "number", 0), scopeMode === "legacy"),
wrapField("product", "Køretøjstype", buildSelect("product", [{ id: 0, name: "Ingen" }, ...products], initialProduct), scopeMode === "legacy"),
wrapField("condition_id", "Hvis", buildSelect("condition_id", [{ id: 0, name: "Altid" }], initialConditionId)),
wrapField("task", "Opgave", buildInput("task", record?.task ?? initialData.task ?? "")),
wrapField("description", "Beskrivelse", buildInput("description", record?.description ?? initialData.description ?? "")),
wrapField("order_priority", "Rækkefølge", buildInput("order_priority", initialOrderPriority, "number", 0)),
wrapField("services", "Tjenester", buildCheckboxList("services", [
{ id: "MACHINE", name: "MACHINE" }
], record?.services ?? initialData.services ?? [])),
wrapField("buttons", "Knapper", buildCheckboxList(
"buttons",
Array.from({ length: 12 }, (_, index) => ({ id: index, name: `Button ${index}` })),
(record?.buttons ?? initialData.buttons ?? []).map(String)
)),
wrapField("dynamic_images_vehicle_type", "Køretøjstype (maskine UI)", buildSelect(
"dynamic_images_vehicle_type",
[{ id: "", name: "Ingen" }, ...products],
record?.dynamic_images_vehicle_type ?? initialData.dynamic_images_vehicle_type ?? ""
)),
].join("");
return Swal.fire({
title: record ? `Rediger ${object.meta.labels.single}` : `Opret ${object.meta.labels.single}`,
html,
showCancelButton: true,
confirmButtonText: SessionUser.objects.global.language.save,
cancelButtonText: SessionUser.objects.global.language.cancel,
didOpen: async () => {
const updateScopeVisibility = () => {
const isMachineType = getFieldValue("scope_mode") === "machine_type";
setFieldDisplay("machine_type_id-wrapper", isMachineType);
setFieldDisplay("department-wrapper", !isMachineType);
setFieldDisplay("lane-wrapper", !isMachineType);
setFieldDisplay("product-wrapper", !isMachineType);
};
const updateConditionOptions = async () => {
const isMachineType = getFieldValue("scope_mode") === "machine_type";
const options = await object.columns.condition_id.options({
department: isMachineType ? 0 : getFieldValue("department"),
product: isMachineType ? 0 : getFieldValue("product"),
machine_type_id: isMachineType ? getFieldValue("machine_type_id") : null,
});
populateSelect("condition_id", options, getFieldValue("condition_id") || initialConditionId || 0);
};
document.getElementById("scope_mode")?.addEventListener("change", async () => {
updateScopeVisibility();
await updateConditionOptions();
});
document.getElementById("machine_type_id")?.addEventListener("change", updateConditionOptions);
document.getElementById("department")?.addEventListener("change", updateConditionOptions);
document.getElementById("product")?.addEventListener("change", updateConditionOptions);
updateScopeVisibility();
await updateConditionOptions();
},
preConfirm: async () => {
const payload = {
task: getFieldValue("task").trim(),
description: getFieldValue("description").trim(),
order_priority: parseIntOrZero(getFieldValue("order_priority")),
condition_id: parseNullableInt(getFieldValue("condition_id")),
services: getCheckedValues("services"),
buttons: getCheckedValues("buttons").map((value) => parseIntOrZero(value)),
dynamic_images_vehicle_type: parseNullableInt(getFieldValue("dynamic_images_vehicle_type")),
};
if (!payload.task) {
return showValidationMessage("Opgave er påkrævet.");
}
if (!payload.description) {
return showValidationMessage("Beskrivelse er påkrævet.");
}
if (getFieldValue("scope_mode") === "machine_type") {
payload.machine_type_id = parseNullableInt(getFieldValue("machine_type_id"));
payload.department = 0;
payload.lane = 0;
payload.product = 0;
if (!payload.machine_type_id) {
return showValidationMessage("Maskintype er påkrævet for denne scope.");
}
} else {
payload.machine_type_id = null;
payload.department = parseIntOrZero(getFieldValue("department"));
payload.lane = parseIntOrZero(getFieldValue("lane"));
payload.product = parseIntOrZero(getFieldValue("product"));
}
try {
await saveRecord(object.meta.endpoint, payload, record?.id);
if (onAfterSubmit) {
await onAfterSubmit();
}
} catch (error) {
return showValidationMessage(error?.response?.data?.message || error?.message || "Kunne ikke gemme opgaven.");
}
}
});
};
@@ -0,0 +1,50 @@
<script setup>
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import DepartmentDashboardPageWrapper from "@/views/dashboards/departmentDashboard/DepartmentDashboardPageWrapper.vue";
import NotFoundFallBackPageWrapper from "@/components/page/wrappers/NotFoundFallBackPageWrapper.vue";
import SelfServeMachineTypesPagination from "@/components/displays/pagination/models/DepartmentDashboard/SelfServeMachineTypesPagination.vue";
import PageTitle from "@/components/global/PageTitle.vue";
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const departmentId = SessionUser.functions.getDepartmentIdFromUrl();
</script>
<template>
<RestrictedPageWrapper :hasPermission="SessionUser.canAccessAdmin()">
<DepartmentDashboardPageWrapper>
<NotFoundFallBackPageWrapper :exists="SessionUser.functions.getDepartmentIdFromUrl() && SessionUser.canAccessDepartment(SessionUser.functions.getDepartmentIdFromUrl())" :error="$t('admin.errors.select_department')">
<PageTitle :title="SessionUser.objects.self_serve_machine_types.meta.title" :subtitle="SessionUser.objects.self_serve_machine_types.meta.description" />
<SelfServeMachineTypesPagination :autoLoad="true">
<template #buttons="{ loadList }">
<div class="buttons">
<button
class="button is-primary"
@click="SessionUser.objects.self_serve_machine_types.showCreateObjectForm({}, loadList)"
>
<span class="icon">
<i class="fas fa-plus"></i>
</span>
<span>{{ t('common.add') }} {{ SessionUser.objects.self_serve_machine_types.meta.labels.single }}</span>
</button>
<router-link :to="{ name: 'selfserveconditions', params: { departmentId: departmentId } }" class="button is-link is-light">
<span class="icon">
<i class="fas fa-filter"></i>
</span>
<span>{{ t('admin.self_serve.conditions.manage') }}</span>
</router-link>
<router-link :to="{ name: 'selfservetasks', params: { departmentId: departmentId } }" class="button is-link is-light">
<span class="icon">
<i class="fas fa-tasks"></i>
</span>
<span>{{ t('admin.self_serve.tasks.manage') }}</span>
</router-link>
</div>
</template>
</SelfServeMachineTypesPagination>
</NotFoundFallBackPageWrapper>
</DepartmentDashboardPageWrapper>
</RestrictedPageWrapper>
</template>