// RMLWorkorderAdmin.js
Vue.component('r-m-l-workorder-admin', {
template: `
{{ workordersToAssign.length }} Workorder(s) zuweisen:
Kunde: {{ row.customerCompany || row.customerName }}
Anschluss:
{{ row.street }} {{ row.hausnummer }}/{{ row.stiege }} / WE: {{ row.apartment }}, {{ row.plz }} {{ row.city }}
OAID: {{ row.oaid }}
{{ getStatusColumn(row.status).text }}
{{ row.companyName || 'N/A' }}
{{ formatDate(row.deadlineDate) }}
übrig: {{ row.daysUntilDeadline }} Tag{{ row.daysUntilDeadline !== 1 ? 'e' : '' }}
{{ formatDate(row.appointmentDate) }}
`,
data() {
return {
window,
workordersToAssign: [],
editingWorkorderId: null,
editingDeadlineId: null,
companies: [],
massAssignCompanyId: null,
massAssignLoading: false,
crudConfig: {
...window.TT_CONFIG.CRUD_CONFIG,
selectable: false,
expandable: true,
customRowClass: (row) => {
const deadlineDate = moment.unix(row.deadlineDate);
if (['completed', 'new'].includes(row.status) || !deadlineDate.isValid()) {
return 'tt-rml-workorder-irrelevant';
}
if (['correction_requested', 'intervention_required'].includes(row.status)) {
return 'tt-rml-workorder-high';
}
const daysLeft = deadlineDate.diff(moment(), 'days');
if (daysLeft <= 7) return 'tt-rml-workorder-urgent';
if (daysLeft <= 21) return 'tt-rml-workorder-medium';
return 'tt-rml-workorder-ontrack';
},
additionalActions: []
}
}
},
async mounted() {
const response = await axios.get(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/getCompanies`);
this.companies = response.data;
},
methods: {
addToAssignList(row) {
if (!this.workordersToAssign.includes(row.id)) {
this.workordersToAssign.push(row.id);
}
},
removeFromAssignList(row) {
this.workordersToAssign = this.workordersToAssign.filter(id => id !== row.id);
},
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');
},
async assignCompany(workorder, companyId) {
if (!companyId) {
this.editingWorkorderId = null;
return;
}
const payload = {
workorderId: workorder.id,
companyId: companyId
};
try {
const response = await axios.post(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/assignWorkorder`, payload);
if (response.data.success) {
window.notify('success', response.data.message);
this.$refs.table.$refs.table.refreshTable();
} else {
window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten.');
}
} catch (e) {
window.notify('error', 'Ein Netzwerkfehler ist aufgetreten.');
} finally {
this.editingWorkorderId = null;
}
},
async massAssignCompanies(companyId) {
if (!companyId) return;
if (!confirm(`${this.workordersToAssign.length} Workorder(s) der ausgewählten Firma zuweisen?`)) {
this.massAssignCompanyId = null; // Reset select on cancel
return;
}
this.massAssignLoading = true;
const payload = {
companyId: companyId,
workorderIds: this.workordersToAssign
};
try {
const response = await axios.post(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/massAssignWorkorders`, payload);
if (response.data.success) {
window.notify('success', response.data.message);
this.workordersToAssign = [];
this.$refs.table.$refs.table.refreshTable();
} else {
window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten.');
}
} catch (e) {
window.notify('error', 'Ein Netzwerkfehler ist aufgetreten.');
} finally {
this.massAssignLoading = false;
this.massAssignCompanyId = null;
}
},
async updateDeadline(workorder, newDate) {
if (!newDate) {
this.editingDeadlineId = null;
return;
}
try {
const response = await axios.post(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/updateDeadline`, {
workorderId: workorder.id,
deadlineDate: newDate
});
if (response.data.success) {
window.notify('success', response.data.message);
this.$refs.table.$refs.table.refreshTable();
} else {
window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten.');
}
} catch (e) {
window.notify('error', 'Ein Netzwerkfehler ist aufgetreten.');
} finally {
this.editingDeadlineId = null;
}
},
async acceptDocumentation(workorderId) {
if (!confirm('Soll die Dokumentation für diesen Arbeitsauftrag wirklich akzeptiert und der Auftrag abgeschlossen werden?')) return;
try {
const response = await axios.post(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/acceptDocumentation`, { workorderId });
if (response.data.success) {
window.notify('success', response.data.message);
this.$refs.table.$refs.table.refreshTable();
} else {
window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten.');
}
} catch (e) {
window.notify('error', 'Ein Netzwerkfehler ist aufgetreten.');
}
}
}
});
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: `●`
});
Vue.component('rml-documentation-viewer-admin', {
props: ['workorderId'],
template: `
Wählen Sie die zu korrigierenden Dokumente aus der Galerie aus und geben Sie einen Grund an.
Wenn die Dokumentation korrekt ist, können Sie sie hier akzeptieren.
-
{{ formatDate(log.create) }} ({{ log.createByName }}):
{{ log.text }}
Keine Journaleinträge.
`,
data() {
return {
loading: true,
correctionLoading: false,
docs: [],
journals: [],
selectedDocs: [],
correctionText: '',
newJournalMessage: '',
addingJournalEntry: false,
}
},
methods: {
async fetchData() {
this.loading = true;
try {
const response = await axios.get(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/getDocumentation`, { params: { workorderId: this.workorderId }});
this.docs = response.data.docs;
this.journals = response.data.journals;
} catch(e) {
window.notify('error', 'Dokumentation konnte nicht geladen werden.');
} finally {
this.loading = false;
}
},
async requestCorrection() {
if (!this.correctionText) return window.notify('error', 'Bitte geben Sie einen Grund für die Korrektur an.');
if (this.selectedDocs.length === 0) return window.notify('error', 'Bitte wählen Sie mindestens ein Dokument für die Korrektur aus.');
this.correctionLoading = true;
try {
const payload = {
workorderId: this.workorderId,
text: this.correctionText,
fileIds: this.selectedDocs
};
const response = await axios.post(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/requestCorrection`, payload);
if (response.data.success) {
window.notify('success', response.data.message);
this.correctionText = '';
this.selectedDocs = [];
await this.fetchData();
this.$emit('workorder-updated');
} else {
window.notify('error', response.data.message);
}
} catch (e) {
window.notify('error', 'Ein Netzwerkfehler ist aufgetreten.');
}
this.correctionLoading = false;
},
async addJournalEntry() {
if (!this.newJournalMessage.trim()) {
return window.notify('error', 'Bitte geben Sie eine Nachricht ein.');
}
this.addingJournalEntry = true;
try {
const response = await axios.post(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderAdmin/addJournal`, {
workorderId: this.workorderId,
text: this.newJournalMessage
});
if (response.data.success) {
window.notify('success', response.data.message || 'Journal-Eintrag hinzugefügt.');
this.newJournalMessage = '';
this.journals = response.data.journals;
} else {
window.notify('error', response.data.message || 'Eintrag konnte nicht gespeichert werden.');
}
} catch (e) {
window.notify('error', 'Ein Netzwerkfehler ist aufgetreten.');
} finally {
this.addingJournalEntry = false;
}
},
formatDate(timestamp) {
return window.moment.unix(timestamp).format('DD.MM.YYYY HH:mm');
},
},
mounted() {
this.fetchData();
}
});