Add MAC address processing and clipboard functionality in CPE provisioning

This commit is contained in:
2025-12-01 09:21:19 +01:00
parent ed8a7cb8d8
commit 1df61765da

View File

@@ -68,10 +68,15 @@ Vue.component('Cpeprovisioning', {
<div class="cpe-card-content">
<div class="content-column">
<h5>Router Konfiguration</h5>
<tt-select label="Router" :options="routerOptions" v-model="item.cpe_data.routertype" @input="markDirty(item); checkShipping(item)" sm no-form-group/>
<tt-select label="Router" :options="routerOptions" v-model="item.cpe_data.routertype" @input="markDirty(item); checkShipping(item); handleRouterTypeChange(item)" sm no-form-group/>
<tt-input label="WLAN SSID" v-model="item.cpe_data.wifi_ssid" @input="markDirty(item)" sm no-form-group/>
<tt-input label="WPA Key" v-model="item.cpe_data.wifi_pass" @input="markDirty(item)" sm no-form-group/>
<tt-input label="Router MAC" v-model="item.cpe_data.mac" @input="markDirty(item)" sm no-form-group/>
<div class="d-flex align-items-center" style="gap: 5px;">
<tt-input label="Router MAC" v-model="item.cpe_data.mac" @input="handleMacInput(item)" sm no-form-group style="flex-grow: 1;"/>
<button @click="copyToClipboard(item.cpe_data.mac)" :disabled="!item.cpe_data.mac" class="btn btn-sm btn-primary" style="height: 28px; margin-top:28px; width: 38px; padding: 0;">
<i class="fas fa-copy"></i>
</button>
</div>
<tt-input v-if="item.termination_id" label="ONT SN" v-model="item.ont_sn" @input="markDirty(item)" sm no-form-group :additional-props="{ placeholder: item.ont_deployed ? 'ONT montiert' : 'ONT nicht montiert' }"/>
</div>
@@ -176,7 +181,8 @@ Vue.component('Cpeprovisioning', {
pagination: {},
debouncedFetchData: null,
extensionId: 'jglijfiddilckddlmbnlojmmlahboffh',
showExtensionIdModal: false
showExtensionIdModal: false,
processingMacItems: new Set() // Track items currently being processed
}
},
computed: {
@@ -200,6 +206,16 @@ Vue.component('Cpeprovisioning', {
window.removeEventListener('keydown', this.handleKeydown);
},
methods: {
copyToClipboard(text) {
navigator.clipboard.writeText(text)
.then(() => {
window.notify('success', 'Text erfolgreich in die Zwischenablage kopiert!');
})
.catch(err => {
console.error('Fehler beim Kopieren des Textes: ', err);
window.notify('error', 'Fehler beim Kopieren des Textes.');
});
},
handleKeydown(e) {
if (e.code === 'KeyE' && e.ctrlKey && e.altKey) {
e.preventDefault();
@@ -276,6 +292,160 @@ Vue.component('Cpeprovisioning', {
markDirty(item) {
this.$set(item, 'isDirty', true);
},
parseMacFromQrCode(qrCode) {
console.log('[MAC Parser] Raw QR Code input:', qrCode);
// Remove any whitespace/newlines (barcode scanner input doesn't support newlines, but just in case)
const cleaned = qrCode.replace(/\s+/g, '');
console.log('[MAC Parser] Cleaned QR Code:', cleaned);
// Extract MAC address from QR format: 00040E-802395709D7C
// The MAC address is the 12 hex characters AFTER the dash
const match = cleaned.match(/-([0-9A-Fa-f]{12})/);
console.log('[MAC Parser] Regex match result:', match);
if (match) {
const macAddress = match[1]; // Get only the part after the dash: 802395709D7C
console.log('[MAC Parser] Extracted MAC:', macAddress);
return macAddress;
}
console.log('[MAC Parser] No match found, returning null');
return null;
},
calculateMacOffset(macAddress, offset) {
console.log('[MAC Offset] Input MAC:', macAddress, 'Offset:', offset);
// Convert MAC to decimal using BigInt for large numbers
const macDecimal = BigInt('0x' + macAddress);
console.log('[MAC Offset] MAC as decimal:', macDecimal.toString());
// Apply offset (add or subtract)
const newMacDecimal = macDecimal + BigInt(offset);
console.log('[MAC Offset] New MAC as decimal:', newMacDecimal.toString());
// Convert back to hex (12 chars, padded with zeros)
let newMacHex = newMacDecimal.toString(16).toUpperCase();
newMacHex = newMacHex.padStart(12, '0');
console.log('[MAC Offset] Result MAC:', newMacHex);
return newMacHex;
},
formatMacAddress(macAddress) {
console.log('[MAC Format] Input MAC:', macAddress);
// Remove any existing formatting
const cleaned = macAddress.replace(/[:-]/g, '');
console.log('[MAC Format] Cleaned MAC:', cleaned);
// Format as AA:BB:CC:DD:EE:FF (uppercase)
const formatted = cleaned.match(/.{1,2}/g).join(':').toUpperCase();
console.log('[MAC Format] Formatted MAC:', formatted);
return formatted;
},
handleMacInput(item) {
console.log('[MAC Input] === START handleMacInput ===');
console.log('[MAC Input] Item:', item);
console.log('[MAC Input] Current MAC value:', item.cpe_data.mac);
console.log('[MAC Input] Router type:', item.cpe_data.routertype);
// Check if we're already processing this item to prevent recursion
const itemKey = item.orderproduct_id;
if (this.processingMacItems.has(itemKey)) {
console.log('[MAC Input] Already processing this item, returning to prevent recursion');
return;
}
this.markDirty(item);
this.processMacAddress(item);
},
handleRouterTypeChange(item) {
console.log('[Router Type Change] Router type changed, checking if MAC needs processing');
this.processMacAddress(item);
},
processMacAddress(item) {
const inputValue = item.cpe_data.mac;
const routerType = item.cpe_data.routertype;
const itemKey = item.orderproduct_id;
// Only process if it's a QR code format (contains dash, no colons)
// This prevents reprocessing already formatted MAC addresses
if (!inputValue) {
console.log('[MAC Process] No input value, returning');
return;
}
if (!inputValue.includes('-')) {
console.log('[MAC Process] No dash found in input, returning');
return;
}
if (inputValue.includes(':')) {
console.log('[MAC Process] Already formatted (contains colons), returning');
return;
}
console.log('[MAC Process] Input contains dash and no colons, proceeding...');
// Check if this is a 4050 or 7690 router
if (routerType !== 'FritzBox 4050' && routerType !== 'FritzBox 7690') {
console.log('[MAC Process] Router type is not FritzBox 4050 or FritzBox 7690, returning. Current type:', routerType);
return;
}
console.log('[MAC Process] Router type is valid:', routerType);
// Mark this item as being processed
this.processingMacItems.add(itemKey);
try {
// Parse MAC from QR code
const parsedMac = this.parseMacFromQrCode(inputValue);
if (!parsedMac) {
console.log('[MAC Process] Failed to parse MAC from QR code');
window.notify('error', 'Konnte MAC-Adresse nicht aus QR-Code parsen');
this.processingMacItems.delete(itemKey);
return;
}
console.log('[MAC Process] Successfully parsed MAC:', parsedMac);
// Calculate offset based on router type
const offset = routerType === 'FritzBox 4050' ? -3 : 2;
console.log('[MAC Process] Applying offset:', offset);
const newMac = this.calculateMacOffset(parsedMac, offset);
console.log('[MAC Process] Calculated new MAC:', newMac);
// Format MAC address
const formattedMac = this.formatMacAddress(newMac);
console.log('[MAC Process] Formatted MAC:', formattedMac);
// Update the field using Vue.set for proper reactivity
console.log('[MAC Process] Updating item.cpe_data.mac to:', formattedMac);
this.$set(item.cpe_data, 'mac', formattedMac);
// Force Vue to update the DOM
this.$nextTick(() => {
console.log('[MAC Process] After nextTick, MAC value is:', item.cpe_data.mac);
// Remove from processing set after DOM update
this.processingMacItems.delete(itemKey);
});
// Show notification
const offsetStr = offset > 0 ? `+${offset}` : `${offset}`;
window.notify('success', `MAC-Adresse aus QR-Code geparst (${offsetStr}): ${formattedMac}`);
} catch (error) {
console.error('[MAC Process] Error processing MAC:', error);
this.processingMacItems.delete(itemKey);
}
console.log('[MAC Process] === END processMacAddress ===');
},
checkShipping(item) {
if (item.cpe_data.shipping && item.cpe_data.routertype) {
const shippingData = this.window.TT_CONFIG.ROUTER_SHIPPING_DATA[item.cpe_data.routertype];