/** * ADBNetzgebiet - Netzgebietverwaltung (Vue 3 + TT-Core) */ const ADBNetzgebiet = { name: 'ADBNetzgebiet', template: `
Netzgebietverwaltung

Name / ExtRef Quelle Freigaben Netzwerk Kampagne Zustimmung
{{ item.netzgebiet.name || '(Ohne Name)' }}
{{ item.netzgebiet.extref }}
{{ item.netzgebiet.source || '—' }}
{{ item.netzgebiet.source_id }}
{{ f.charAt(0).toUpperCase() }}
Erstellen Erstellen
Lade Netzgebiete...
Keine Netzgebiete gefunden.
{{ paginationStart }}–{{ paginationEnd }} von {{ filteredNetzgebiete.length }} Netzgebieten
{{ currentPage }} / {{ totalPages }}
Kein Verlauf vorhanden.
{{ translateAction(entry.action) }} {{ translateField(entry.field) }} {{ entry.user_name || 'System' }} · {{ formatTimestamp(entry.timestamp) }}
{{ formatValue(entry.field, entry.old_value) }} {{ formatValue(entry.field, entry.new_value) }}
Lade Log...
Kein Log vorhanden.
{{ rimoLogContent }}
`, data() { return { window: window, isLoading: true, isSaving: false, netzgebiete: [], currentPage: 1, pageSize: 50, filters: { name: '', extref: '', source: '', hasNetwork: '', hasCampaign: '', hasConsent: '' }, filterDebounce: null, showEditModal: false, editItem: null, showHistoryModal: false, historyLoading: false, historyItems: [], historyTitle: 'Verlauf', expandedIds: {}, // RIMO Import importStatus: {}, showRimoLogModal: false, rimoLogContent: '', rimoLogTitle: '', rimoLogStatus: 'idle', rimoLogInterval: null, statusInterval: null, freigabeLabels: { interest: 'Interest', provision: 'Provision', order: 'Order', reorder: 'Reorder' }, freigabeOptions: [ { key: 'interest', label: 'Interest' }, { key: 'provision', label: 'Provision' }, { key: 'order', label: 'Order' }, { key: 'reorder', label: 'Reorder' } ], optionsConfig: [ { key: 'create_address_parts', label: 'create_address_parts', tooltip: 'Neue Straßen/PLZ/Ort anlegen' }, { key: 'update_freigabe', label: 'update_freigabe', tooltip: 'Setzt Freigabe auf Basis Netzgebiet' }, { key: 'update_address', label: 'update_address', tooltip: 'Straßennamen ändern' }, { key: 'hausnummer_dont_overwrite_netzgebiet', label: 'dont_overwrite_netzgebiet', tooltip: 'Netzgebiete nicht überschreiben' }, { key: 'create_preorder', label: 'create_preorder', tooltip: 'Bestellungen erstellen (SBIDI)' }, { key: 'preorder_only_oaid', label: 'preorder_only_oaid', tooltip: 'SBIDI OAID aus RIMO' }, { key: 'wo_ignore_status', label: 'wo_ignore_status', tooltip: 'Status ignorieren' }, { key: 'delete_units', label: 'delete_units', tooltip: 'Homes löschen die nicht in RIMO sind' }, { key: 'unit_create_oaid', label: 'unit_create_oaid', tooltip: 'OAID bei Unit erstellen' } ], defaultOptions: { create_address_parts: 0, update_freigabe: 1, update_address: 1, hausnummer_dont_overwrite_netzgebiet: 0, create_preorder: 0, preorder_only_oaid: 0, wo_ignore_status: 0, delete_units: 0, mph_min_homes_tool_automatic_count: 3, unit_create_oaid: 0 } }; }, computed: { availableSources() { const sources = new Set(); this.netzgebiete.forEach(item => { if (item.netzgebiet?.source) sources.add(item.netzgebiet.source); }); return Array.from(sources).sort(); }, hasActiveFilters() { return Object.values(this.filters).some(v => v); }, filteredNetzgebiete() { return this.netzgebiete.filter(item => { const n = item.netzgebiet; if (!n) return false; if (this.filters.name && !n.name?.toLowerCase().includes(this.filters.name.toLowerCase())) return false; if (this.filters.extref && !n.extref?.toLowerCase().includes(this.filters.extref.toLowerCase())) return false; if (this.filters.source && n.source !== this.filters.source) return false; const hasNetwork = item.related?.networks?.length > 0; const hasCampaign = item.related?.campaigns?.length > 0; const hasConsent = item.related?.consent_projects?.length > 0; if (this.filters.hasNetwork === 'yes' && !hasNetwork) return false; if (this.filters.hasNetwork === 'no' && hasNetwork) return false; if (this.filters.hasCampaign === 'yes' && !hasCampaign) return false; if (this.filters.hasCampaign === 'no' && hasCampaign) return false; if (this.filters.hasConsent === 'yes' && !hasConsent) return false; if (this.filters.hasConsent === 'no' && hasConsent) return false; return true; }); }, totalPages() { return Math.ceil(this.filteredNetzgebiete.length / this.pageSize) || 1; }, paginatedItems() { const start = (this.currentPage - 1) * this.pageSize; return this.filteredNetzgebiete.slice(start, start + this.pageSize); }, paginationStart() { return this.filteredNetzgebiete.length ? (this.currentPage - 1) * this.pageSize + 1 : 0; }, paginationEnd() { return Math.min(this.currentPage * this.pageSize, this.filteredNetzgebiete.length); }, filteredHistory() { return this.historyItems.filter(e => !['edit', 'create'].includes(e.field)); } }, watch: { filteredNetzgebiete() { if (this.currentPage > this.totalPages) this.currentPage = 1; } }, async mounted() { await this.fetchNetzgebiete(); this.fetchImportStatus(); this.statusInterval = setInterval(this.fetchImportStatus, 15000); // Poll every 15s }, beforeDestroy() { clearInterval(this.statusInterval); clearInterval(this.rimoLogInterval); }, methods: { formatConsentName(name) { if (name && name.startsWith('Glasfaserprojekt')) { return name.replace('Glasfaserprojekt', 'Glasfaserprojekt
'); } return name; }, debouncedFilter() { clearTimeout(this.filterDebounce); this.filterDebounce = setTimeout(() => this.currentPage = 1, 300); }, applyFilter() { this.currentPage = 1; }, clearFilters() { this.filters = { name: '', extref: '', source: '', hasNetwork: '', hasCampaign: '', hasConsent: '' }; this.currentPage = 1; }, async fetchNetzgebiete() { this.isLoading = true; try { const response = await axios.get(window.TT_CONFIG.GET_URL); this.netzgebiete = response.data.success ? (response.data.data || []) : (response.data || []); } catch (error) { console.error('Fehler:', error); window.notify?.('error', 'Netzgebiete konnten nicht geladen werden.'); } finally { this.isLoading = false; } }, parsedFreigabe(json) { try { return JSON.parse(json || '[]') || []; } catch { return []; } }, openCreateModal() { this.editItem = { id: null, name: '', extref: '', source: '', source_id: '', freigabe: { interest: true, provision: true, order: true, reorder: true }, options: { ...this.defaultOptions } }; this.showEditModal = true; }, openEditModal(item) { const n = item.netzgebiet; let options = {}; try { options = JSON.parse(n.options || '{}'); } catch {} let freigabeArr = []; try { freigabeArr = JSON.parse(n.freigabe || '[]') || []; } catch {} const freigabeObj = {}; ['interest', 'provision', 'order', 'reorder'].forEach(f => freigabeObj[f] = freigabeArr.includes(f)); this.editItem = { id: n.id, name: n.name || '', extref: n.extref || '', source: n.source || '', source_id: n.source_id || '', freigabe: freigabeObj, options: { ...this.defaultOptions, ...options } }; this.showEditModal = true; }, async copyNetzgebiet(item) { const n = item.netzgebiet; let options = {}; try { options = JSON.parse(n.options || '{}'); } catch {} let freigabeArr = []; try { freigabeArr = JSON.parse(n.freigabe || '[]') || []; } catch {} const freigabeObj = {}; ['interest', 'provision', 'order', 'reorder'].forEach(f => freigabeObj[f] = freigabeArr.includes(f)); this.editItem = { id: null, name: '', extref: '', source: n.source || '', source_id: '', freigabe: freigabeObj, options: { ...this.defaultOptions, ...options } }; this.showEditModal = true; }, async saveNetzgebiet() { if (!this.editItem?.name) return; this.isSaving = true; const freigabeArray = Object.keys(this.editItem.freigabe).filter(k => this.editItem.freigabe[k]); const payload = { id: this.editItem.id, name: this.editItem.name, extref: this.editItem.extref, source: this.editItem.source, source_id: this.editItem.source_id, freigabe: freigabeArray, options: this.editItem.options }; try { const response = await axios.post(window.TT_CONFIG.SAVE_URL, payload); if (response.data.success) { window.notify?.('success', response.data.message); this.showEditModal = false; await this.fetchNetzgebiete(); } else { window.notify?.('error', response.data.message || 'Fehler beim Speichern.'); } } catch { window.notify?.('error', 'Netzwerkfehler.'); } finally { this.isSaving = false; } }, async openHistoryModal(item) { this.historyTitle = `Verlauf: ${item.netzgebiet.name}`; this.showHistoryModal = true; this.historyLoading = true; this.historyItems = []; try { const response = await axios.get(window.TT_CONFIG.HISTORY_URL + '?id=' + item.netzgebiet.id); this.historyItems = response.data.success ? (response.data.data || []) : (response.data || []); } catch { window.notify?.('error', 'Verlauf konnte nicht geladen werden.'); } finally { this.historyLoading = false; } }, // RIMO Import Methods async fetchImportStatus() { const rimoIds = this.netzgebiete .filter(item => item.netzgebiet.source && item.netzgebiet.source.startsWith('rimo-')) .map(item => item.netzgebiet.id); if (!rimoIds.length) return; try { const response = await axios.post(window.TT_CONFIG.GET_RIMO_IMPORT_STATUS_URL, { ids: rimoIds }); if (response.data.success) { this.importStatus = response.data.data; } } catch (error) { console.error("Could not fetch RIMO import statuses.", error); } }, handleRimoImportClick(item) { const status = this.importStatus[item.netzgebiet.id]?.status || 'idle'; if (status === 'running') { this.openRimoLogModal(item); } else if (status === 'cooldown') { const remaining = this.importStatus[item.netzgebiet.id]?.remaining || 0; window.notify?.('info', `Bitte warten Sie noch ${Math.ceil(remaining / 60)} Minuten.`); this.openRimoLogModal(item); } else { this.startRimoImport(item); } }, getImportButtonTitle(id) { const status = this.importStatus[id]?.status || 'idle'; if (status === 'running') return 'Import-Log anzeigen'; if (status === 'cooldown') return 'Manueller RIMO-Import (Abkühlphase)'; return 'Manuellen RIMO-Import starten'; }, getImportButtonDisabled(id) { const status = this.importStatus[id]?.status || 'idle'; return false; // Never truly disabled, just changes action }, getImportButtonIcon(id) { const status = this.importStatus[id]?.status || 'idle'; if (status === 'running') return 'fa-spinner fa-spin'; if (status === 'cooldown') return 'fa-hourglass-half'; return 'fa-rocket'; }, async startRimoImport(item) { try { const response = await axios.get(window.TT_CONFIG.START_RIMO_IMPORT_URL + '?id=' + item.netzgebiet.id); if (response.data.success) { window.notify?.('success', 'RIMO Import gestartet.'); this.importStatus[item.netzgebiet.id] = { status: 'running' }; this.openRimoLogModal(item); } else { window.notify?.('error', response.data.message || 'Import konnte nicht gestartet werden.'); } } catch (error) { window.notify?.('error', 'Fehler beim Starten des Imports.'); console.error(error); } }, openRimoLogModal(item) { this.rimoLogTitle = `RIMO Import: ${item.netzgebiet.name}`; this.showRimoLogModal = true; this.fetchRimoLog(item); // initial fetch this.rimoLogInterval = setInterval(() => this.fetchRimoLog(item), 3000); }, closeRimoLogModal() { this.showRimoLogModal = false; clearInterval(this.rimoLogInterval); this.rimoLogContent = ''; this.rimoLogTitle = ''; this.rimoLogStatus = 'idle'; }, async fetchRimoLog(item) { try { const response = await axios.get(window.TT_CONFIG.GET_RIMO_IMPORT_LOG_URL + '?id=' + item.netzgebiet.id); if (response.data.success) { this.rimoLogContent = response.data.data.log; this.rimoLogStatus = response.data.data.status; // If no longer running, stop polling if (this.rimoLogStatus !== 'running') { clearInterval(this.rimoLogInterval); this.fetchImportStatus(); // refresh overall status } } } catch (error) { console.error('Could not fetch RIMO log.', error); clearInterval(this.rimoLogInterval); } }, translateAction(action) { return { create: 'Erstellt', update: 'Geändert', delete: 'Gelöscht' }[action] || action; }, translateField(field) { return { name: 'Name', extref: 'ExtRef', source: 'Quelle', source_id: 'Source ID', freigabe: 'Freigaben', options: 'Optionen', unit_counts: 'Einheiten' }[field] || field; }, formatTimestamp(ts) { if (!ts) return '—'; try { return new Date(ts.replace(' ', 'T')).toLocaleString('de-AT'); } catch { return ts; } }, formatValue(field, value) { if (value === null || value === undefined || value === '') return '—'; if (['freigabe', 'options'].includes(field)) { try { const parsed = typeof value === 'string' ? JSON.parse(value) : value; if (field === 'freigabe' && Array.isArray(parsed)) return parsed.join(', ') || '—'; if (field === 'options' && typeof parsed === 'object') { const entries = Object.entries(parsed).filter(([,v]) => v !== 0 && v !== '0'); return entries.map(([k,v]) => `${k}: ${v}`).join(', ') || '—'; } } catch {} } return String(value); }, isLongValue(field, value) { return this.formatValue(field, value).length > 40; }, toggleExpand(id) { this.expandedIds[id] = !this.expandedIds[id]; } } }; if (window.VueApp) { window.VueApp.component('a-d-b-netzgebiet', ADBNetzgebiet); }