Files
thetool/public/js/pages/RMLWorkorderAdmin/RMLWorkorderAdmin.js
2025-07-23 20:44:25 +02:00

183 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// RMLWorkorderAdmin.js
Vue.component('r-m-l-workorder-admin', {
template: `
<tt-card>
<assign-company-modal
v-if="assignModalWorkorderId"
:workorder-id="assignModalWorkorderId"
@close="assignModalWorkorderId = null; $refs.table.$refs.table.refreshTable()"
/>
<documentation-viewer-modal
v-if="docsModalWorkorderId"
:workorder-id="docsModalWorkorderId"
@close="docsModalWorkorderId = null"
/>
<tt-table-crud
ref="table"
@assign="assignModalWorkorderId = $event.id"
@view_docs="docsModalWorkorderId = $event.id"
:crud-config="crudConfig"
>
<template v-slot:preorderinfo="{ row }">
<div v-html="row.preorderInfo" class="small"></div>
</template>
<template v-slot:status="{ row }">
<traffic-light :deadline="row.deadlineDate" :status="row.status" />
<i :class="getStatusColumn(row.status).icon" :title="getStatusColumn(row.status).text"></i>
<span class="ml-2">{{ getStatusColumn(row.status).text }}</span>
</template>
<template v-slot:deadlinedate="{ row }">
{{ formatDate(row.deadlineDate) }}
</template>
<template v-slot:appointmentdate="{ row }">
{{ formatDate(row.appointmentDate) }}
</template>
</tt-table-crud>
</tt-card>
`,
data() {
return {
assignModalWorkorderId: null,
docsModalWorkorderId: null,
crudConfig: {
...window.TT_CONFIG.CRUD_CONFIG,
additionalActions: [
{
"key": "assign",
"title": "Firma zuweisen",
"class": "fas fa-user-plus text-primary",
"condition": (row) => row.status === 'new',
},
{
"key": "view_docs",
"title": "Dokumentation ansehen",
"class": "fas fa-folder-open text-info",
"condition": (row) => ['documented', 'completed'].includes(row.status),
},
]
}
}
},
methods: {
getStatusColumn(status) {
const column = this.crudConfig.columns.find(c => c.key === 'status');
return column.table.filterOptions.find(opt => opt.value === status) || {};
},
formatDate(timestamp) {
if (!timestamp) return '';
return window.moment.unix(timestamp).format('DD.MM.YYYY');
}
}
});
Vue.component('traffic-light', {
props: ['deadline', 'status'],
computed: {
lightInfo() {
if (['completed', 'new'].includes(this.status)) return { color: '#cccccc', title: 'Status irrelevant für Dringlichkeit' };
const now = moment();
const deadlineDate = moment.unix(this.deadline);
if (!deadlineDate.isValid()) return { color: '#cccccc', title: 'Keine Deadline gesetzt' };
if (deadlineDate.isBefore(now)) return { color: '#dc3545', title: 'Deadline überschritten' };
const daysLeft = deadlineDate.diff(now, 'days');
if (daysLeft <= 7) return { color: '#dc3545', title: 'Dringend: Weniger als 1 Woche' };
if (daysLeft <= 21) return { color: '#ffc107', title: 'Mittel: Weniger als 3 Wochen' };
return { color: '#28a745', title: 'Im Plan: Mehr als 3 Wochen' };
}
},
template: `<span :style="{ color: lightInfo.color, fontSize: '1.2em' }" class="mr-2" :title="lightInfo.title">&#9679;</span>`
});
Vue.component('assign-company-modal', {
props: ['workorderId'],
template: `
<tt-modal :show="true" title="Firma zuweisen" @submit="submit" @update:show="$emit('close')">
<tt-select label="Firma" :options="companies" v-model="selectedCompanyId" sm row required />
</tt-modal>
`,
data() { return { companies: [], selectedCompanyId: null } },
async mounted() {
const response = await axios.get(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/getCompanies`);
this.companies = response.data;
},
methods: {
async submit() {
if (!this.selectedCompanyId) return window.notify('error', 'Bitte eine Firma auswählen.');
try {
const response = await axios.post(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/assignWorkorder`, {
workorderId: this.workorderId,
companyId: this.selectedCompanyId
});
if(response.data.success) {
window.notify('success', response.data.message);
this.$emit('close');
} else {
window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten.');
}
} catch (e) {
window.notify('error', 'Ein Netzwerkfehler ist aufgetreten.');
}
}
}
});
Vue.component('documentation-viewer-modal', {
props: ['workorderId'],
template: `
<tt-modal :show="true" :title="'Dokumentation für Auftrag #' + workorderId" :save="false" :delete="false" @update:show="$emit('close')">
<div class="card">
<div class="card-header">
<h5>Hochgeladene Dokumente</h5>
</div>
<div v-if="loading" class="card-body text-center"><i class="fas fa-spinner fa-spin fa-2x"></i></div>
<div v-else-if="!docs.length" class="card-body text-center text-muted">Keine Dokumente vorhanden.</div>
<ul v-else class="list-group list-group-flush">
<li v-for="doc in docs" :key="doc.id" class="list-group-item">
<a :href="'/File/download?id=' + doc.fileId" target="_blank">
<i class="fas fa-file-download mr-2"></i> {{ doc.fileName }}
</a>
<div class="text-muted small mt-1">
<strong>Typ:</strong> {{ getDocTypeText(doc.documentType) }} <br/>
<strong>Beschreibung:</strong> {{ doc.description || '-' }} <br/>
<strong>Hochgeladen von:</strong> {{ doc.userName }} am {{ formatDate(doc.create) }}
</div>
</li>
</ul>
</div>
</tt-modal>
`,
data() {
return { loading: false, docs: [] }
},
methods: {
async fetchDocs() {
this.loading = true;
const response = await axios.get(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/getDocumentation`, { params: { workorderId: this.workorderId }});
this.docs = response.data;
this.loading = false;
},
formatDate(timestamp) {
return window.moment.unix(timestamp).format('DD.MM.YYYY HH:mm');
},
getDocTypeText(type) {
const types = [
{ value: 'photo_before', text: 'Foto: Zustand vorher' },
{ value: 'photo_during', text: 'Foto: Während der Arbeit' },
{ value: 'photo_after', text: 'Foto: Zustand nachher' },
{ value: 'measurement_protocol', text: 'Messprotokoll (z.B. OTDR)' },
{ value: 'customer_signature', text: 'Unterschriebenes Arbeitsprotokoll' },
];
return types.find(t => t.value === type)?.text || type;
}
},
mounted() {
this.fetchDocs();
}
});