Added FCPs to TheToolAdded WarehouseOffer and WarehouseOfferTemplate, also fixed menu for Lager Point
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
Vue.component('csv-import-modal', {
|
||||
props: {
|
||||
show: { type: Boolean, required: true },
|
||||
title: { type: String, required: true },
|
||||
apiUrl: { type: String, required: true },
|
||||
showNetworkAreas: { type: Boolean, default: false },
|
||||
networkAreas: { type: Array, default: () => [] }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedFile: null,
|
||||
loading: false,
|
||||
errorMessage: null,
|
||||
fileInputKey: Date.now(),
|
||||
selectedNetworkArea: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleFileChange(event) {
|
||||
const file = event.target.files[0];
|
||||
this.resetInputState();
|
||||
if (!file) return;
|
||||
|
||||
const fileNameLower = file.name.toLowerCase();
|
||||
const allowedTypes = ['text/csv', 'application/vnd.ms-excel'];
|
||||
if (!fileNameLower.endsWith('.csv') && !allowedTypes.includes(file.type)) {
|
||||
this.errorMessage = 'Bitte wählen Sie eine gültige CSV-Datei aus (.csv).';
|
||||
this.resetFileInputVisuals();
|
||||
return;
|
||||
}
|
||||
this.selectedFile = file;
|
||||
},
|
||||
|
||||
readFileAsString() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.selectedFile) {
|
||||
return reject(new Error("Keine Datei ausgewählt."));
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => resolve(e.target.result);
|
||||
reader.onerror = () => reject(new Error("Fehler beim Lesen der Datei."));
|
||||
reader.readAsText(this.selectedFile, 'UTF-8');
|
||||
});
|
||||
},
|
||||
|
||||
parseCSV(csvText) {
|
||||
if (!csvText || typeof csvText !== 'string') return [];
|
||||
const lines = csvText.trim().split(/\r?\n/);
|
||||
if (lines.length < 2) return [];
|
||||
|
||||
const headers = lines[0].split(';').map(h => this.cleanValue(h));
|
||||
const data = [];
|
||||
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (!line) continue;
|
||||
|
||||
const values = line.split(';');
|
||||
if (values.length !== headers.length) continue;
|
||||
|
||||
const entry = {};
|
||||
headers.forEach((header, j) => {
|
||||
entry[header] = this.cleanValue(values[j]);
|
||||
});
|
||||
data.push(entry);
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
cleanValue(value) {
|
||||
if (typeof value !== 'string') return value;
|
||||
let cleaned = value.trim();
|
||||
if (cleaned.startsWith('"') && cleaned.endsWith('"')) {
|
||||
cleaned = cleaned.slice(1, -1).replace(/""/g, '"');
|
||||
}
|
||||
return cleaned;
|
||||
},
|
||||
|
||||
async submit() {
|
||||
if (!this.selectedFile) {
|
||||
this.errorMessage = 'Bitte wählen Sie zuerst eine Datei aus.';
|
||||
return;
|
||||
}
|
||||
if (this.showNetworkAreas && !this.selectedNetworkArea) {
|
||||
this.errorMessage = 'Bitte wählen Sie einen Netzbereich aus.';
|
||||
return;
|
||||
}
|
||||
this.errorMessage = null;
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
const csvString = await this.readFileAsString();
|
||||
const parsedData = this.parseCSV(csvString);
|
||||
|
||||
const payload = { data: parsedData };
|
||||
if (this.showNetworkAreas) {
|
||||
payload.networkAreaId = this.selectedNetworkArea;
|
||||
}
|
||||
|
||||
const response = await axios.post(this.apiUrl, payload);
|
||||
window.notify(response.data.success ? 'success' : 'warning', response.data.message || 'Import erfolgreich.');
|
||||
this.$emit('close', true);
|
||||
|
||||
} catch (error) {
|
||||
let backendMsg = error.response?.data?.message || '';
|
||||
let detailsMsg = '';
|
||||
if (error.response?.data?.errors) {
|
||||
detailsMsg = Object.values(error.response.data.errors).flat().join(', ');
|
||||
}
|
||||
this.errorMessage = `Importfehler: ${error.message || 'Unbekannter Fehler.'}${backendMsg ? ' Server: ' + backendMsg : ''}${detailsMsg ? ' Details: ' + detailsMsg : ''}`;
|
||||
window.notify('error', this.errorMessage);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
if (!this.loading) {
|
||||
this.$emit('close', false);
|
||||
}
|
||||
},
|
||||
|
||||
resetFileInputVisuals() {
|
||||
this.fileInputKey = Date.now();
|
||||
},
|
||||
|
||||
resetInputState() {
|
||||
this.selectedFile = null;
|
||||
this.errorMessage = null;
|
||||
},
|
||||
|
||||
resetAll() {
|
||||
this.resetInputState();
|
||||
this.resetFileInputVisuals();
|
||||
this.selectedNetworkArea = null;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(newVal) {
|
||||
if (!newVal) {
|
||||
this.resetAll();
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<tt-modal
|
||||
:show="show"
|
||||
@update:show="closeModal"
|
||||
:title="title"
|
||||
@submit="submit"
|
||||
:save-loading="loading"
|
||||
save-text="Importieren"
|
||||
:delete="false"
|
||||
>
|
||||
<tt-loader :absolute="false" v-if="loading"/>
|
||||
<template v-else>
|
||||
<div v-if="showNetworkAreas" class="form-group" style="margin: 10px 0">
|
||||
<tt-select
|
||||
label="Netzbereich auswählen"
|
||||
v-model="selectedNetworkArea"
|
||||
:options="networkAreas"
|
||||
:required="true"
|
||||
:disabled="loading || !networkAreas || networkAreas.length === 0"
|
||||
sm
|
||||
row
|
||||
/>
|
||||
<small v-if="!networkAreas || networkAreas.length === 0" class="form-text text-danger">
|
||||
Keine Netzbereiche verfügbar.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin: 10px 0">
|
||||
<label>CSV-Datei auswählen (Trennzeichen: Semikolon ';')</label>
|
||||
<input
|
||||
type="file"
|
||||
class="form-control"
|
||||
accept=".csv, text/csv, application/vnd.ms-excel"
|
||||
@change="handleFileChange"
|
||||
:key="fileInputKey"
|
||||
:disabled="loading"
|
||||
/>
|
||||
<small v-if="selectedFile" class="form-text text-muted">
|
||||
Ausgewählt: {{ selectedFile.name }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div v-if="errorMessage" class="alert alert-danger mt-2" role="alert">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
</template>
|
||||
</tt-modal>
|
||||
`
|
||||
});
|
||||
|
||||
Vue.component('a-d-b-rimo-fcp', {
|
||||
template: `
|
||||
<tt-card>
|
||||
<tt-table-crud ref="table">
|
||||
<template #table-top-buttons>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<tt-button icon="fas fa-upload" text="FCPs Importieren" additional-class="btn-outline-success" @click="showImportFCPModal = true" />
|
||||
<tt-button icon="fas fa-upload" text="Locations Importieren" additional-class="btn-outline-success" @click="showImportLocationsModal = true" />
|
||||
</div>
|
||||
</template>
|
||||
</tt-table-crud>
|
||||
|
||||
<csv-import-modal
|
||||
v-if="showImportFCPModal"
|
||||
:show="showImportFCPModal"
|
||||
:show-network-areas="true"
|
||||
:network-areas="networkAreas"
|
||||
title="FCPs Importieren"
|
||||
:api-url="fcpApiUrl"
|
||||
@close="handleModalClose"
|
||||
/>
|
||||
|
||||
<csv-import-modal
|
||||
v-if="showImportLocationsModal"
|
||||
:show="showImportLocationsModal"
|
||||
:show-network-areas="true"
|
||||
:network-areas="networkAreas"
|
||||
title="Locations Importieren"
|
||||
:api-url="locationsApiUrl"
|
||||
@close="handleModalClose"
|
||||
/>
|
||||
</tt-card>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
showImportFCPModal: false,
|
||||
showImportLocationsModal: false,
|
||||
networkAreas: window.TT_CONFIG?.CRUD_CONFIG?.columns?.find(col => col.key === 'netzgebiet_id')?.modal?.items || [],
|
||||
fcpApiUrl: window.TT_CONFIG['BASE_PATH'] + '/ADBRimoFcp/ImportFCPs',
|
||||
locationsApiUrl: window.TT_CONFIG['BASE_PATH'] + '/ADBRimoFcp/ImportLocations'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleModalClose(importWasSuccessful) {
|
||||
this.showImportFCPModal = false;
|
||||
this.showImportLocationsModal = false;
|
||||
|
||||
if (importWasSuccessful) this.$refs.table.$refs.table.refreshTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user