added mph workorders to thetool
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
// WorkorderMphCompany.js
|
||||
Vue.component('workorder-mph-company', {
|
||||
template: `
|
||||
<tt-card>
|
||||
<tt-table-crud ref="table" :crud-config="crudConfig">
|
||||
<template v-slot:hausnummerinfo="{ row }">
|
||||
<div class="small">
|
||||
<div><strong>Adresse:</strong> {{ row.street }} {{ row.hausnummer }}<template v-if="row.stiege">/{{ row.stiege }}</template></div>
|
||||
<div><strong>Ort:</strong> {{ row.plz }} {{ row.city }}</div>
|
||||
<div><strong>Wohneinheiten:</strong> {{ row.wohneinheitCount }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:status="{ row }">
|
||||
<traffic-light-mph :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 }">
|
||||
<div v-if="editingAppointmentId === row.id">
|
||||
<tt-date-picker :value="row.appointmentDate" :date-range="false" time-picker
|
||||
@input="scheduleAppointment(row, $event)" @blur="editingAppointmentId = null"
|
||||
sm no-form-group/>
|
||||
</div>
|
||||
<div v-else class="d-flex align-items-center">
|
||||
<span>{{ formatDate(row.appointmentDate, true) }}</span>
|
||||
<tt-button v-if="canSchedule(row)" icon="fas fa-edit"
|
||||
@click="editingAppointmentId = row.id"
|
||||
additional-class="btn-link btn-sm p-0 ml-2" title="Termin planen"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:additionalinfo="{ row }">
|
||||
<span style="white-space: pre-wrap; max-width: 250px; display: inline-block;">{{ row.additionalInfo || '-' }}</span>
|
||||
</template>
|
||||
|
||||
<template v-slot:expandedRow="{ row }">
|
||||
<div class="row">
|
||||
<!-- Action Buttons -->
|
||||
<div class="col-12 mb-3" v-if="!['completed', 'cancelled', 'documented'].includes(row.status)">
|
||||
<div class="btn-group" role="group">
|
||||
<tt-button v-if="row.status === 'assigned'" text="Termin planen"
|
||||
@click="editingAppointmentId = row.id" icon="fas fa-calendar-plus"
|
||||
additional-class="btn-primary"/>
|
||||
<tt-button v-if="row.status === 'scheduled'" text="Arbeit beginnen"
|
||||
@click="startWork(row)" icon="fas fa-play" additional-class="btn-success"/>
|
||||
<tt-button v-if="row.status === 'scheduled'" text="Termin verschieben"
|
||||
@click="openRescheduleModal(row)" icon="fas fa-calendar-alt"
|
||||
additional-class="btn-warning"/>
|
||||
<tt-button v-if="row.status === 'in_progress'" text="Auftrag abschließen"
|
||||
@click="openCompleteModal(row)" icon="fas fa-check-double"
|
||||
additional-class="btn-success"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Wohneinheit Manager -->
|
||||
<div class="col-12">
|
||||
<wohneinheit-status-manager :workorder-mph-id="parseInt(row.id)" :is-admin="false"
|
||||
@wohneinheit-updated="checkAllWohneinheitenHaveNotes(row.id)"/>
|
||||
</div>
|
||||
|
||||
<!-- Checkbox Documentation -->
|
||||
<div class="col-12 mt-3">
|
||||
<checkbox-documentation :workorder-mph-id="parseInt(row.id)" :is-admin="false"/>
|
||||
</div>
|
||||
|
||||
<!-- Details Manager (Docs & Journal) -->
|
||||
<div class="col-12 mt-3">
|
||||
<workorder-mph-details-manager :workorder-mph-id="row.id" :is-admin="false"
|
||||
@workorder-completed="$refs.table.$refs.table.refreshTable()"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</tt-table-crud>
|
||||
|
||||
<tt-modal v-if="rescheduleModalData" :show.sync="rescheduleModalData"
|
||||
title="Termin verschieben" @submit="rescheduleAppointment">
|
||||
<p>Aktueller Termin: <strong>{{ formatDate(rescheduleModalData.currentDate, true) }}</strong></p>
|
||||
<tt-date-picker label="Neuer Termin" v-model="rescheduleModalData.newDate"
|
||||
:date-range="false" time-picker sm row required/>
|
||||
<tt-textarea label="Grund" v-model="rescheduleModalData.reason" sm row required/>
|
||||
</tt-modal>
|
||||
|
||||
<tt-modal v-if="completeModalData" :show.sync="completeModalData"
|
||||
title="Auftrag abschließen" @submit="completeWorkorder" :delete="false">
|
||||
<p>Möchten Sie diesen Auftrag wirklich abschließen und zur Prüfung einreichen?</p>
|
||||
<div class="alert alert-warning small">
|
||||
<i class="fas fa-exclamation-triangle mr-2"></i>
|
||||
Bitte stellen Sie sicher, dass alle Wohneinheiten dokumentiert sind und alle erforderlichen Dokumente hochgeladen wurden.
|
||||
</div>
|
||||
</tt-modal>
|
||||
</tt-card>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
window,
|
||||
editingAppointmentId: null,
|
||||
rescheduleModalData: null,
|
||||
completeModalData: null,
|
||||
crudConfig: {
|
||||
...window.TT_CONFIG.CRUD_CONFIG,
|
||||
selectable: false,
|
||||
expandable: true,
|
||||
customRowClass: (row) => {
|
||||
if (['completed', 'new', 'cancelled'].includes(row.status)) return 'tt-mph-workorder-irrelevant';
|
||||
const deadlineDate = moment.unix(row.deadlineDate);
|
||||
if (!deadlineDate.isValid()) return 'tt-mph-workorder-irrelevant';
|
||||
const daysLeft = deadlineDate.diff(moment(), 'days');
|
||||
if (daysLeft <= 7) return 'tt-mph-workorder-urgent';
|
||||
if (daysLeft <= 21) return 'tt-mph-workorder-medium';
|
||||
return 'tt-mph-workorder-ontrack';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getStatusColumn(status) {
|
||||
const column = this.crudConfig.columns.find(c => c.key === 'status');
|
||||
return column.table.filterOptions.find(opt => opt.value === status) || {};
|
||||
},
|
||||
formatDate(timestamp, withTime = false) {
|
||||
if (!timestamp) return '–';
|
||||
return window.moment.unix(timestamp).format(withTime ? 'DD.MM.YYYY HH:mm' : 'DD.MM.YYYY');
|
||||
},
|
||||
canSchedule(row) {
|
||||
return ['assigned', 'scheduled'].includes(row.status);
|
||||
},
|
||||
async scheduleAppointment(row, newDate) {
|
||||
if (!newDate) {
|
||||
this.editingAppointmentId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const hour = parseInt(moment.unix(newDate).format('H'));
|
||||
if (hour >= 23 || hour < 1) {
|
||||
window.notify('error', 'Bitte geben Sie eine Uhrzeit zwischen 01:00 und 22:59 an!');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await axios.post(`${window.TT_CONFIG.BASE_PATH}/WorkorderMphCompany/scheduleAppointment`, {
|
||||
workorderId: row.id,
|
||||
appointmentDate: newDate
|
||||
});
|
||||
if (data.success) {
|
||||
window.notify('success', data.message);
|
||||
this.$refs.table.$refs.table.refreshTable();
|
||||
} else {
|
||||
window.notify('error', data.message || 'Ein Fehler ist aufgetreten.');
|
||||
}
|
||||
} catch (e) {
|
||||
window.notify('error', 'Netzwerkfehler.');
|
||||
} finally {
|
||||
this.editingAppointmentId = null;
|
||||
}
|
||||
},
|
||||
openRescheduleModal(row) {
|
||||
this.rescheduleModalData = {
|
||||
workorderId: row.id,
|
||||
currentDate: row.appointmentDate,
|
||||
newDate: null,
|
||||
reason: ''
|
||||
};
|
||||
},
|
||||
async rescheduleAppointment() {
|
||||
if (!this.rescheduleModalData.newDate || !this.rescheduleModalData.reason) {
|
||||
return window.notify('error', 'Bitte füllen Sie alle Felder aus.');
|
||||
}
|
||||
|
||||
const hour = parseInt(moment.unix(this.rescheduleModalData.newDate).format('H'));
|
||||
if (hour >= 23 || hour < 1) {
|
||||
window.notify('error', 'Bitte geben Sie eine Uhrzeit zwischen 01:00 und 22:59 an!');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await axios.post(`${window.TT_CONFIG.BASE_PATH}/WorkorderMphCompany/rescheduleAppointment`, {
|
||||
workorderId: this.rescheduleModalData.workorderId,
|
||||
appointmentDate: this.rescheduleModalData.newDate,
|
||||
reason: this.rescheduleModalData.reason
|
||||
});
|
||||
if (data.success) {
|
||||
window.notify('success', data.message);
|
||||
this.$refs.table.$refs.table.refreshTable();
|
||||
this.rescheduleModalData = null;
|
||||
} else {
|
||||
window.notify('error', data.message || 'Ein Fehler ist aufgetreten.');
|
||||
}
|
||||
} catch (e) {
|
||||
window.notify('error', 'Netzwerkfehler.');
|
||||
}
|
||||
},
|
||||
async startWork(row) {
|
||||
if (!confirm(`Möchten Sie mit der Arbeit an Auftrag #${row.id} beginnen?`)) return;
|
||||
|
||||
try {
|
||||
const { data } = await axios.post(`${window.TT_CONFIG.BASE_PATH}/WorkorderMphCompany/startWork`, {
|
||||
workorderId: row.id
|
||||
});
|
||||
if (data.success) {
|
||||
window.notify('success', data.message);
|
||||
this.$refs.table.$refs.table.refreshTable();
|
||||
} else {
|
||||
window.notify('error', data.message || 'Ein Fehler ist aufgetreten.');
|
||||
}
|
||||
} catch (e) {
|
||||
window.notify('error', 'Netzwerkfehler.');
|
||||
}
|
||||
},
|
||||
openCompleteModal(row) {
|
||||
this.completeModalData = { workorderId: row.id };
|
||||
},
|
||||
async completeWorkorder() {
|
||||
try {
|
||||
const { data } = await axios.post(`${window.TT_CONFIG.BASE_PATH}/WorkorderMphCompany/completeWorkorder`, {
|
||||
workorderId: this.completeModalData.workorderId
|
||||
});
|
||||
if (data.success) {
|
||||
window.notify('success', data.message);
|
||||
this.$refs.table.$refs.table.refreshTable();
|
||||
this.completeModalData = null;
|
||||
} else {
|
||||
window.notify('error', data.message || 'Abschluss fehlgeschlagen.');
|
||||
}
|
||||
} catch (e) {
|
||||
window.notify('error', 'Ein Netzwerkfehler ist aufgetreten.');
|
||||
}
|
||||
},
|
||||
async checkAllWohneinheitenHaveNotes(workorderId) {
|
||||
// This is called when a wohneinheit is updated
|
||||
// Could be used to enable/disable the complete button
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user