Merge branch 'RMLWorkorder/add-multiple-problem-selection' into 'master'

added multiple selection for problems

See merge request fronk/thetool!1678
This commit is contained in:
Luca Haid
2025-08-26 08:28:07 +00:00
2 changed files with 83 additions and 29 deletions

View File

@@ -327,6 +327,13 @@ class RMLWorkorderAdminController extends TTCrud
self::sendError("Die Dokumentation muss zuerst von der Firma als fertig markiert werden.");
}
$preorder = new Preorder($workorder->preorderId);
if ($preorder) {
$preorder->status_id = 11; // Assuming 11 is the status for "fiber in building"
$preorder->edit_by = $this->user->id;
$preorder->save();
}
$oldStatus = $workorder->status;
$workorder->status = 'completed';
RMLWorkorderModel::update((array)$workorder);

View File

@@ -300,18 +300,27 @@ Vue.component('documentation-manager', {
<tt-modal v-if="interventionData" :show="true" :delete="false" title="Eingriff anfordern" @update:show="interventionData = null" @submit="requestIntervention">
<tt-select
label="Art des Problems"
:options="[
{value: 'stuck', text: 'Ab X Laufmeter stecken geblieben'},
{value: 'stuck_fcp', text: 'Vom FCP nach HÜP nach X Laufmetern stecken geblieben'},
{value: 'stuck_hup', text: 'Vom HÜP nach FCP nach X Laufmetern stecken geblieben'},
{value: 'no_air', text: 'Keine Luftverbindung'},
{value: 'other', text: 'Sonstiges'}]"
v-model="interventionData.type"
:options="interventionTypes"
v-model="interventionData.types"
sm
row
multiple
/>
<tt-input v-if="['stuck', 'stuck_fcp', 'stuck_hup'].includes(interventionData.type)" label="Distanz (Meter)" type="number" v-model="interventionData.distance" sm row required />
<tt-textarea v-if="interventionData.type === 'other'" label="Grund" v-model="interventionData.otherReason" sm row required />
<div v-for="type in interventionData.types" :key="type">
<tt-input
v-if="['stuck', 'stuck_fcp', 'stuck_hup'].includes(type)"
:label="'Distanz (m) für \\'' + getInterventionLabel(type) + '\\''"
type="number"
v-model="interventionData.details[type].distance"
sm row required
/>
<tt-textarea
v-if="type === 'other'"
label="Grund für 'Sonstiges'"
v-model="interventionData.details.other.reason"
sm row required
/>
</div>
</tt-modal>
</div>
`,
@@ -326,6 +335,13 @@ Vue.component('documentation-manager', {
newJournalMessage: '',
addingJournalEntry: false,
interventionData: null,
interventionTypes: [
{value: 'stuck', text: 'Ab X Laufmeter stecken geblieben'},
{value: 'stuck_fcp', text: 'Vom FCP nach HÜP nach X Laufmetern stecken geblieben'},
{value: 'stuck_hup', text: 'Vom HÜP nach FCP nach X Laufmetern stecken geblieben'},
{value: 'no_air', text: 'Keine Luftverbindung'},
{value: 'other', text: 'Sonstiges'}
],
uploadData: {
files: [],
documentType: 'photo_hup_mounted',
@@ -508,31 +524,62 @@ Vue.component('documentation-manager', {
this.addingJournalEntry = false;
}
},
getInterventionLabel(type) {
return this.interventionTypes.find(t => t.value === type)?.text || type;
},
openInterventionModal() {
this.interventionData = { type: 'stuck', distance: '', otherReason: '' };
this.interventionData = {
types: [],
details: {
stuck: { distance: '' },
stuck_fcp: { distance: '' },
stuck_hup: { distance: '' },
other: { reason: '' }
}
};
},
async requestIntervention() {
let journalText = '';
const { type, distance, otherReason } = this.interventionData;
if (type === 'stuck') {
if (!distance || isNaN(distance)) return window.notify('error', 'Bitte eine gültige Distanz eingeben.');
journalText = `Ab ${distance} Laufmeter stecken geblieben.`;
} else if (type === 'stuck_fcp') {
if (!distance || isNaN(distance)) return window.notify('error', 'Bitte eine gültige Distanz eingeben.');
journalText = `Vom FCP nach HÜP nach ${distance} Laufmetern stecken geblieben.`;
} else if (type === 'stuck_hup') {
if (!distance || isNaN(distance)) return window.notify('error', 'Bitte eine gültige Distanz eingeben.');
journalText = `Vom HÜP nach FCP nach ${distance} Laufmetern stecken geblieben.`;
} else if (type === 'no_air') {
journalText = 'Keine Luftverbindung.';
} else if (type === 'other') {
if (!otherReason.trim()) return window.notify('error', 'Bitte geben Sie einen Grund an.');
journalText = otherReason.trim();
} else {
return window.notify('error', 'Ungültiger Problemtyp.');
const { types, details } = this.interventionData;
if (types.length === 0) {
return window.notify('error', 'Bitte wählen Sie mindestens ein Problem aus.');
}
let journalParts = [];
// Sort types to have a consistent order in the journal message
types.sort();
for (const type of types) {
let text = '';
const problemOption = this.interventionTypes.find(o => o.value === type);
const problemText = problemOption ? problemOption.text : 'Unbekanntes Problem';
if (['stuck', 'stuck_fcp', 'stuck_hup'].includes(type)) {
const distance = details[type]?.distance;
if (!distance || isNaN(distance) || distance <= 0) {
return window.notify('error', `Bitte eine gültige Distanz für "${problemText}" eingeben.`);
}
text = problemText.replace('X', distance);
} else if (type === 'no_air') {
text = problemText;
} else if (type === 'other') {
const reason = details.other?.reason;
if (!reason || !reason.trim()) {
return window.notify('error', 'Bitte geben Sie einen Grund für "Sonstiges" an.');
}
text = `Sonstiges: ${reason.trim()}`;
}
if (text) {
journalParts.push(text);
}
}
const journalText = journalParts.join('\\n');
if (!journalText) {
return window.notify('error', 'Keine gültigen Problemdetails zum Senden gefunden.');
}
try {
const response = await axios.post(`${window.TT_CONFIG.BASE_PATH}/RMLWorkorderCompany/requestIntervention`, {
workorderId: this.workorderId,