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:
@@ -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>
|
||||
+61
@@ -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("&", "&")
|
||||
.replaceAll("<", "<")
|
||||
.replaceAll(">", ">")
|
||||
.replaceAll("\"", """);
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
+50
@@ -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>
|
||||
Reference in New Issue
Block a user