add aha blatt parsing

This commit is contained in:
Luca Haid
2026-01-20 13:27:35 +01:00
parent b79be61ca9
commit d6d213a8d3
9 changed files with 412 additions and 140 deletions
+70 -28
View File
@@ -275,38 +275,59 @@ Vue.component('workorder-details-manager', {
</div>
<div v-if="showTechnicalData && technicalData && (technicalData.patchposition?.equipmentName || technicalData.rimoWorkorders?.length)" class="card mb-3">
<div class="card-header bg-purple text-white">
<h5 class="mb-0"><i class="fas fa-microchip mr-2"></i>Technische Daten</h5>
<div class="card-header bg-purple text-white d-flex justify-content-between align-items-center py-2">
<span><i class="fas fa-microchip mr-2"></i>Technische Daten</span>
<small v-if="technicalData.dropcable?.parsed_at" class="opacity-75">
<i class="fas fa-check mr-1"></i>{{ formatDate(technicalData.dropcable.parsed_at) }}
</small>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6" v-if="technicalData.patchposition?.equipmentName">
<h6>Patchposition</h6>
<table class="table table-sm table-striped mb-0">
<tr>
<th class="border-top-0">Equipment Name:</th>
<td class="border-top-0 text-monospace">{{ technicalData.patchposition.equipmentName }}</td>
</tr>
<tr v-if="technicalData.patchposition.equipmentPort">
<th>Equipment Port:</th>
<td class="text-monospace">{{ technicalData.patchposition.equipmentPort }}</td>
</tr>
</table>
</div>
<div class="col-md-6" v-if="technicalData.rimoWorkorders?.length">
<h6>AHA Blätter</h6>
<div v-for="wo in technicalData.rimoWorkorders" :key="wo.id" class="mb-2">
<div class="d-flex align-items-center justify-content-between border rounded p-2">
<div>
<strong>{{ wo.rimoName }}</strong>
<small class="text-muted ml-2">{{ wo.rimoStatus }}</small>
</div>
<a :href="wo.downloadUrl" target="_blank" class="btn btn-sm btn-outline-primary">
<i class="fas fa-file-pdf mr-1"></i> AHA Blatt
</a>
<div class="card-body py-2">
<div class="row small">
<div class="col-md-6 mb-2" v-if="technicalData.patchposition?.equipmentName">
<div class="d-flex">
<span class="text-muted mr-2"><i class="fas fa-ethernet"></i></span>
<div>
<span class="text-monospace font-weight-bold">{{ technicalData.patchposition.equipmentName }}</span>
<span v-if="technicalData.patchposition.equipmentPort" class="text-muted ml-1">Port {{ technicalData.patchposition.equipmentPort }}</span>
</div>
</div>
</div>
<div class="col-md-6 mb-2" v-if="technicalData.rimoWorkorders?.length">
<div v-for="wo in technicalData.rimoWorkorders" :key="wo.id" class="d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center">
<span class="text-muted mr-2"><i class="fas fa-file-alt"></i></span>
<span class="font-weight-bold">{{ wo.rimoName }}</span>
<span class="badge badge-light ml-2">{{ wo.rimoStatus }}</span>
</div>
<div class="btn-group btn-group-sm">
<a :href="wo.downloadUrl" target="_blank" class="btn btn-outline-secondary" title="AHA PDF"><i class="fas fa-file-pdf"></i></a>
<button @click="parseAha(wo)" class="btn btn-outline-secondary" :disabled="parsingAhaId === wo.id" :title="technicalData.dropcable?.parsed_at ? 'Aktualisieren' : 'Daten laden'">
<i :class="parsingAhaId === wo.id ? 'fas fa-spinner fa-spin' : 'fas fa-sync-alt'"></i>
</button>
</div>
</div>
</div>
</div>
<div v-if="technicalData.dropcable?.entries?.length" class="mt-2">
<table class="table table-sm table-bordered mb-0 small">
<thead class="thead-light">
<tr><th>Kabel-ID</th><th>Typ</th><th class="text-center">PLAN</th><th class="text-center">IST</th><th>Status</th></tr>
</thead>
<tbody>
<tr v-for="(dk, idx) in technicalData.dropcable.entries" :key="idx">
<td class="text-monospace">{{ dk.cable_id }}</td>
<td class="text-truncate" style="max-width:200px" :title="dk.type">{{ dk.type }}</td>
<td class="text-center">{{ dk.laenge_plan || '-' }}</td>
<td class="text-center">{{ dk.laenge_ist || '-' }}</td>
<td><span class="badge" :class="dk.status === 'Planfreigabe' ? 'badge-success' : 'badge-secondary'">{{ dk.status || '-' }}</span></td>
</tr>
</tbody>
</table>
</div>
<div v-if="technicalData.dropcable?.map_file" class="mt-2 text-center">
<a :href="technicalData.dropcable.map_file.download_url" target="_blank" class="d-block">
<img :src="technicalData.dropcable.map_file.download_url" class="img-fluid border rounded shadow-sm" style="max-height:300px;cursor:zoom-in" :alt="'Lageplan'" @error="$event.target.parentElement.style.display='none'">
</a>
</div>
</div>
</div>
@@ -368,6 +389,7 @@ Vue.component('workorder-details-manager', {
// Technical data
showTechnicalData: false,
technicalData: null,
parsingAhaId: null,
// Admin state
selectedDocs: [], correctionText: '', correctionLoading: false, showAcceptModal: false, showRevertModal: false,
}),
@@ -417,6 +439,8 @@ Vue.component('workorder-details-manager', {
// FIX: Ensure docs and journals are always arrays
this.docs = docsJournalsRes.data.docs || [];
this.journals = docsJournalsRes.data.journals || [];
// Reload tenant config to get updated technical data (AHA may have been auto-parsed)
if (this.showTechnicalData) this.loadTenantConfig();
} catch (e) {
window.notify('error', 'Details konnten nicht geladen werden.');
this.docs = []; // Ensure it's an array on error
@@ -576,6 +600,24 @@ Vue.component('workorder-details-manager', {
this.showAcceptModal = false;
},
getInterventionLabel(type) { return this.interventionTypes.find(t => t.value === type)?.text || type; },
async parseAha(wo) {
this.parsingAhaId = wo.id;
try {
const { data } = await axios.post(`${window.TT_CONFIG.BASE_PATH}/RimoWorkorder/parseAha`, { id: wo.id });
if (data.success) {
window.notify('success', `AHA-Daten geladen: ${data.dropkabel_count} Dropkabel${data.has_map ? ', Lageplan vorhanden' : ''}`);
// Reload technical data to show the parsed data
await this.loadTenantConfig();
} else {
window.notify('error', data.message || 'Fehler beim Laden der AHA-Daten');
}
} catch (e) {
window.notify('error', 'Netzwerkfehler beim Laden der AHA-Daten');
console.error(e);
} finally {
this.parsingAhaId = null;
}
},
async revertDocumentedStatus() {
// Optional: Add loading state if needed
try {