@nettyapps/ntybase 21.1.37 → 21.1.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/{nettyapps-ntybase-en-USbase-C1t7F-R0.mjs → nettyapps-ntybase-en-USbase-Bl-neyoj.mjs} +6 -2
- package/fesm2022/{nettyapps-ntybase-en-USbase-C1t7F-R0.mjs.map → nettyapps-ntybase-en-USbase-Bl-neyoj.mjs.map} +1 -1
- package/fesm2022/{nettyapps-ntybase-tr-TRbase-BXQ_UTZY.mjs → nettyapps-ntybase-tr-TRbase-CO4HBOmj.mjs} +6 -2
- package/fesm2022/{nettyapps-ntybase-tr-TRbase-BXQ_UTZY.mjs.map → nettyapps-ntybase-tr-TRbase-CO4HBOmj.mjs.map} +1 -1
- package/fesm2022/nettyapps-ntybase.mjs +192 -176
- package/fesm2022/nettyapps-ntybase.mjs.map +1 -1
- package/package.json +1 -1
- package/translations/en-USbase.json +5 -1
- package/translations/tr-TRbase.json +5 -1
- package/types/nettyapps-ntybase.d.ts +60 -59
|
@@ -281,6 +281,9 @@ var enUSbase = {
|
|
|
281
281
|
"@maxLengthError": "Please enter at most {{value}} characters",
|
|
282
282
|
"@dateCannotBeBeforeStart": "Selected date cannot be earlier than the start date",
|
|
283
283
|
"@dateCannotBeAfterEnd": "Selected date cannot be later than the end date",
|
|
284
|
+
"@selectFile": "Select File",
|
|
285
|
+
"@uploadFile": "Upload File",
|
|
286
|
+
"@displayLogs": "Display Logs",
|
|
284
287
|
"@EXCEL_PARSER": {
|
|
285
288
|
noFileChosen: "Please select a file",
|
|
286
289
|
errorLoadingFile: "Error loading file",
|
|
@@ -290,7 +293,8 @@ var enUSbase = {
|
|
|
290
293
|
defaultValueSet: "'{{prop}}' field is empty, default value assigned.",
|
|
291
294
|
requiredFieldMissing: "'{{prop}}' is required but its value is empty.",
|
|
292
295
|
conversionError: "Could not convert type of data '{{value}}' for field '{{prop}}'.",
|
|
293
|
-
rowSkipped: "This row was skipped due to errors."
|
|
296
|
+
rowSkipped: "This row was skipped due to errors.",
|
|
297
|
+
sampleFile: "Sample File"
|
|
294
298
|
},
|
|
295
299
|
"@EXCEL_PARSER_LOG": {
|
|
296
300
|
all: "All",
|
|
@@ -307,4 +311,4 @@ var enUSbase = {
|
|
|
307
311
|
};
|
|
308
312
|
|
|
309
313
|
export { AG_GRID, DASHBOARD, ENVIRONMENT_INFO, GANTT, enUSbase as default, mfaCode };
|
|
310
|
-
//# sourceMappingURL=nettyapps-ntybase-en-USbase-
|
|
314
|
+
//# sourceMappingURL=nettyapps-ntybase-en-USbase-Bl-neyoj.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nettyapps-ntybase-en-USbase-
|
|
1
|
+
{"version":3,"file":"nettyapps-ntybase-en-USbase-Bl-neyoj.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -281,6 +281,9 @@ var trTRbase = {
|
|
|
281
281
|
"@maxLengthError": "En fazla {{value}} karakter girebilirsiniz",
|
|
282
282
|
"@dateCannotBeBeforeStart": "Seçilen tarih, başlangıç tarihinden önce olamaz",
|
|
283
283
|
"@dateCannotBeAfterEnd": "Seçilen tarih, bitiş tarihinden sonra olamaz",
|
|
284
|
+
"@selectFile": "Dosya Seç",
|
|
285
|
+
"@uploadFile": "Dosya Yükle",
|
|
286
|
+
"@displayLogs": "Logları Görüntüle",
|
|
284
287
|
"@EXCEL_PARSER": {
|
|
285
288
|
noFileChosen: "Lütfen bir dosya seçin",
|
|
286
289
|
errorLoadingFile: "Dosya yüklenirken hata oluştu",
|
|
@@ -290,7 +293,8 @@ var trTRbase = {
|
|
|
290
293
|
defaultValueSet: "'{{prop}}' alanı boş olduğu için varsayılan değer atandı.",
|
|
291
294
|
requiredFieldMissing: "'{{prop}}' zorunlu bir alan ancak değeri boş.",
|
|
292
295
|
conversionError: "'{{prop}}' alanı için '{{value}}' verisinin tipi dönüştürülemedi.",
|
|
293
|
-
rowSkipped: "Bu satır hatalardan dolayı atlandı."
|
|
296
|
+
rowSkipped: "Bu satır hatalardan dolayı atlandı.",
|
|
297
|
+
sampleFile: "Örnek Dosya"
|
|
294
298
|
},
|
|
295
299
|
"@EXCEL_PARSER_LOG": {
|
|
296
300
|
all: "Tümü",
|
|
@@ -307,4 +311,4 @@ var trTRbase = {
|
|
|
307
311
|
};
|
|
308
312
|
|
|
309
313
|
export { AG_GRID, DASHBOARD, ENVIRONMENT_INFO, GANTT, trTRbase as default, mfaCode };
|
|
310
|
-
//# sourceMappingURL=nettyapps-ntybase-tr-TRbase-
|
|
314
|
+
//# sourceMappingURL=nettyapps-ntybase-tr-TRbase-CO4HBOmj.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nettyapps-ntybase-tr-TRbase-
|
|
1
|
+
{"version":3,"file":"nettyapps-ntybase-tr-TRbase-CO4HBOmj.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -28,7 +28,7 @@ import * as i2$2 from '@angular/material/tooltip';
|
|
|
28
28
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
29
29
|
import * as i2$3 from '@angular/material/menu';
|
|
30
30
|
import { MatMenuModule } from '@angular/material/menu';
|
|
31
|
-
import
|
|
31
|
+
import { ExcelLogViewer } from '@nettyapps/ntyux';
|
|
32
32
|
import { I18nService } from '@nettyapps/ntyi18n';
|
|
33
33
|
import * as i1$4 from '@angular/forms';
|
|
34
34
|
import { FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
@@ -2731,33 +2731,196 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
|
|
|
2731
2731
|
args: ['saveForm']
|
|
2732
2732
|
}] } });
|
|
2733
2733
|
|
|
2734
|
+
class ParseLog {
|
|
2735
|
+
rowIndex = 0; // Excel line no (1-based)
|
|
2736
|
+
message = ""; // Error or info message (fallback)
|
|
2737
|
+
level = "INFO";
|
|
2738
|
+
messageKey; // i18n translation key
|
|
2739
|
+
messageParams; // parameters for translation
|
|
2740
|
+
init() {
|
|
2741
|
+
this.rowIndex = 0;
|
|
2742
|
+
this.message = "";
|
|
2743
|
+
this.level = "INFO";
|
|
2744
|
+
this.messageKey = undefined;
|
|
2745
|
+
this.messageParams = undefined;
|
|
2746
|
+
}
|
|
2747
|
+
compare(other) { return this; }
|
|
2748
|
+
getPK() { return this.rowIndex; }
|
|
2749
|
+
setPK(pk) { this.rowIndex = pk; }
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
class ExcelParserError extends Error {
|
|
2753
|
+
key;
|
|
2754
|
+
params;
|
|
2755
|
+
constructor(key, params) {
|
|
2756
|
+
super(key);
|
|
2757
|
+
this.key = key;
|
|
2758
|
+
this.params = params;
|
|
2759
|
+
this.name = 'ExcelParserError';
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
class ExcelParser {
|
|
2763
|
+
mappings;
|
|
2764
|
+
constructor(mappings) {
|
|
2765
|
+
this.mappings = mappings;
|
|
2766
|
+
}
|
|
2767
|
+
async parse(file, options) {
|
|
2768
|
+
// PERFORMANS: XLSX library only loads at parse time!
|
|
2769
|
+
const XLSX = await import('xlsx');
|
|
2770
|
+
const sheetIndex = options?.sheetIndex ?? 0;
|
|
2771
|
+
const headerRowIndex = options?.headerRowIndex ?? 0; // 0-based
|
|
2772
|
+
return new Promise((resolve, reject) => {
|
|
2773
|
+
const reader = new FileReader();
|
|
2774
|
+
reader.onload = (e) => {
|
|
2775
|
+
try {
|
|
2776
|
+
const data = new Uint8Array(e.target?.result);
|
|
2777
|
+
const workbook = XLSX.read(data, { type: 'array' });
|
|
2778
|
+
if (!workbook.SheetNames[sheetIndex]) {
|
|
2779
|
+
throw new ExcelParserError('@EXCEL_PARSER.sheetNotFound', { index: sheetIndex });
|
|
2780
|
+
}
|
|
2781
|
+
const sheetName = workbook.SheetNames[sheetIndex];
|
|
2782
|
+
const sheet = workbook.Sheets[sheetName];
|
|
2783
|
+
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 });
|
|
2784
|
+
const logs = [];
|
|
2785
|
+
const result = [];
|
|
2786
|
+
// Skip headerline
|
|
2787
|
+
const dataRows = rows.slice(headerRowIndex + 1);
|
|
2788
|
+
dataRows.forEach((row, i) => {
|
|
2789
|
+
// Skip empty lines
|
|
2790
|
+
if (!row || row.length === 0)
|
|
2791
|
+
return;
|
|
2792
|
+
const obj = {};
|
|
2793
|
+
let hasError = false;
|
|
2794
|
+
const actualRowIndex = headerRowIndex + i + 2; // Excel line no (1-based)
|
|
2795
|
+
this.mappings.forEach(m => {
|
|
2796
|
+
let rawValue = row[m.index];
|
|
2797
|
+
if ((rawValue === undefined || rawValue === null || rawValue === '') && m.defaultValue !== undefined) {
|
|
2798
|
+
rawValue = m.defaultValue;
|
|
2799
|
+
logs.push(Object.assign(new ParseLog(), {
|
|
2800
|
+
rowIndex: actualRowIndex,
|
|
2801
|
+
message: `Boş alan için default değer atandı: ${String(m.prop)}`,
|
|
2802
|
+
level: 'INFO',
|
|
2803
|
+
messageKey: '@EXCEL_PARSER.defaultValueSet',
|
|
2804
|
+
messageParams: { prop: String(m.prop) }
|
|
2805
|
+
}));
|
|
2806
|
+
}
|
|
2807
|
+
if (m.required && (rawValue === undefined || rawValue === null || rawValue === '')) {
|
|
2808
|
+
logs.push(Object.assign(new ParseLog(), {
|
|
2809
|
+
rowIndex: actualRowIndex,
|
|
2810
|
+
message: `Zorunlu alan boş: ${String(m.prop)}`,
|
|
2811
|
+
level: 'ERROR',
|
|
2812
|
+
messageKey: '@EXCEL_PARSER.requiredFieldMissing',
|
|
2813
|
+
messageParams: { prop: String(m.prop) }
|
|
2814
|
+
}));
|
|
2815
|
+
hasError = true;
|
|
2816
|
+
}
|
|
2817
|
+
try {
|
|
2818
|
+
obj[m.prop] = m.converter ? m.converter(rawValue) : rawValue;
|
|
2819
|
+
}
|
|
2820
|
+
catch (err) {
|
|
2821
|
+
logs.push(Object.assign(new ParseLog(), {
|
|
2822
|
+
rowIndex: actualRowIndex,
|
|
2823
|
+
message: `Tip dönüşüm hatası: ${String(m.prop)} -> ${rawValue}`,
|
|
2824
|
+
level: 'ERROR',
|
|
2825
|
+
messageKey: '@EXCEL_PARSER.conversionError',
|
|
2826
|
+
messageParams: { prop: String(m.prop), value: rawValue }
|
|
2827
|
+
}));
|
|
2828
|
+
hasError = true;
|
|
2829
|
+
}
|
|
2830
|
+
});
|
|
2831
|
+
if (!hasError) {
|
|
2832
|
+
result.push(obj);
|
|
2833
|
+
}
|
|
2834
|
+
else {
|
|
2835
|
+
logs.push(Object.assign(new ParseLog(), {
|
|
2836
|
+
rowIndex: actualRowIndex,
|
|
2837
|
+
message: `Satır atlandı`,
|
|
2838
|
+
level: 'WARN',
|
|
2839
|
+
messageKey: '@EXCEL_PARSER.rowSkipped'
|
|
2840
|
+
}));
|
|
2841
|
+
}
|
|
2842
|
+
});
|
|
2843
|
+
resolve({ data: result, logs });
|
|
2844
|
+
}
|
|
2845
|
+
catch (error) {
|
|
2846
|
+
reject(error);
|
|
2847
|
+
}
|
|
2848
|
+
};
|
|
2849
|
+
reader.onerror = () => reject(reader.error);
|
|
2850
|
+
reader.readAsArrayBuffer(file);
|
|
2851
|
+
});
|
|
2852
|
+
}
|
|
2853
|
+
async generateSampleExcel(options) {
|
|
2854
|
+
const sampleCount = options?.sampleCount ?? 5;
|
|
2855
|
+
const fileName = (options?.fileName ?? 'sample-import.xlsx').endsWith('.xlsx')
|
|
2856
|
+
? (options?.fileName ?? 'sample-import.xlsx')
|
|
2857
|
+
: `${options?.fileName}.xlsx`;
|
|
2858
|
+
const sheetName = (options?.sheetName ?? 'Sample').substring(0, 15);
|
|
2859
|
+
const XLSX = await import('xlsx');
|
|
2860
|
+
// Header row: property names according to column order
|
|
2861
|
+
const headers = this.mappings.map(m => m.headerName || String(m.prop));
|
|
2862
|
+
const rows = [];
|
|
2863
|
+
for (let i = 1; i <= sampleCount; i++) {
|
|
2864
|
+
const row = this.mappings.map(m => {
|
|
2865
|
+
if (m.sampleValue !== undefined) {
|
|
2866
|
+
// Use sampleValue if it exists
|
|
2867
|
+
return typeof m.sampleValue === 'function'
|
|
2868
|
+
? m.sampleValue(i) // if it's a function, generate value based on index
|
|
2869
|
+
: m.sampleValue; // if it's a constant value, use it directly
|
|
2870
|
+
}
|
|
2871
|
+
});
|
|
2872
|
+
rows.push(row);
|
|
2873
|
+
}
|
|
2874
|
+
const worksheet = XLSX.utils.aoa_to_sheet([headers, ...rows]);
|
|
2875
|
+
const workbook = XLSX.utils.book_new();
|
|
2876
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
|
|
2877
|
+
XLSX.writeFile(workbook, fileName);
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2734
2881
|
class ExcelImportBase extends NettyAgGridListBase {
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2882
|
+
isFileSelectionHidden = signal(false, ...(ngDevMode ? [{ debugName: "isFileSelectionHidden" }] : []));
|
|
2883
|
+
isFileValid = signal(false, ...(ngDevMode ? [{ debugName: "isFileValid" }] : []));
|
|
2884
|
+
logs = signal([], ...(ngDevMode ? [{ debugName: "logs" }] : []));
|
|
2885
|
+
hasLogs = computed(() => this.logs().length > 0, ...(ngDevMode ? [{ debugName: "hasLogs" }] : []));
|
|
2886
|
+
logDialog = inject(MatDialog);
|
|
2887
|
+
parser = new ExcelParser([]);
|
|
2888
|
+
// override methods
|
|
2889
|
+
onBtnClick(e) { }
|
|
2890
|
+
loadData() { }
|
|
2891
|
+
// Methods
|
|
2892
|
+
onFilesSelected(evt) {
|
|
2893
|
+
const files = Array.isArray(evt) ? evt : evt.target.files;
|
|
2894
|
+
if (!files || files.length !== 1) {
|
|
2895
|
+
return;
|
|
2896
|
+
}
|
|
2897
|
+
const file = files[0];
|
|
2898
|
+
if (file) {
|
|
2899
|
+
this.recordList.set([]);
|
|
2900
|
+
this.logs.set([]);
|
|
2901
|
+
this.parser.parse(file).then(result => {
|
|
2902
|
+
this.recordList.set(result.data);
|
|
2903
|
+
this.logs.set(result.logs);
|
|
2904
|
+
this.isFileSelectionHidden.set(true);
|
|
2905
|
+
if (result.logs.length > 0)
|
|
2906
|
+
this.showLogs();
|
|
2907
|
+
});
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
downloadSampleExcel() {
|
|
2911
|
+
this.parser.generateSampleExcel();
|
|
2912
|
+
}
|
|
2913
|
+
showLogs() {
|
|
2914
|
+
const dialogRef = this.logDialog.open(ExcelLogViewer, {
|
|
2915
|
+
height: '70%',
|
|
2916
|
+
width: '90%',
|
|
2917
|
+
maxWidth: '100vw',
|
|
2918
|
+
maxHeight: '100vh'
|
|
2919
|
+
});
|
|
2920
|
+
dialogRef.componentInstance.setParseData(this.logs());
|
|
2921
|
+
dialogRef.componentInstance.selectedElement.subscribe((element) => {
|
|
2922
|
+
dialogRef.close();
|
|
2923
|
+
});
|
|
2761
2924
|
}
|
|
2762
2925
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ExcelImportBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
2763
2926
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ExcelImportBase, isStandalone: true, selector: "ntybase-excel-import-base", usesInheritance: true, ngImport: i0, template: ``, isInline: true });
|
|
@@ -4370,8 +4533,8 @@ class NettyBaseApp {
|
|
|
4370
4533
|
alertService = inject(AlertService);
|
|
4371
4534
|
async loadBaseTranslations() {
|
|
4372
4535
|
try {
|
|
4373
|
-
const enUSBase = await import('./nettyapps-ntybase-en-USbase-
|
|
4374
|
-
const trTRBase = await import('./nettyapps-ntybase-tr-TRbase-
|
|
4536
|
+
const enUSBase = await import('./nettyapps-ntybase-en-USbase-Bl-neyoj.mjs');
|
|
4537
|
+
const trTRBase = await import('./nettyapps-ntybase-tr-TRbase-CO4HBOmj.mjs');
|
|
4375
4538
|
this.i18nService.addTranslations('English', enUSBase.default);
|
|
4376
4539
|
this.i18nService.addTranslations('Türkçe', trTRBase.default);
|
|
4377
4540
|
}
|
|
@@ -4644,153 +4807,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
|
|
|
4644
4807
|
args: [{ selector: 'ntybase-netty-apps-base', imports: [], template: `` }]
|
|
4645
4808
|
}], ctorParameters: () => [], propDecorators: { isFilterExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "isFilterExpanded", required: false }] }, { type: i0.Output, args: ["isFilterExpandedChange"] }], filteredRecords: [{ type: i0.Output, args: ["filteredRecords"] }], filterSelectionChanged: [{ type: i0.Output, args: ["filterSelectionChanged"] }], refresh: [{ type: i0.Input, args: [{ isSignal: true, alias: "refresh", required: false }] }], fileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileName", required: false }] }] } });
|
|
4646
4809
|
|
|
4647
|
-
class ParseLog {
|
|
4648
|
-
rowIndex = 0; // Excel line no (1-based)
|
|
4649
|
-
message = ""; // Error or info message (fallback)
|
|
4650
|
-
level = "INFO";
|
|
4651
|
-
messageKey; // i18n translation key
|
|
4652
|
-
messageParams; // parameters for translation
|
|
4653
|
-
init() {
|
|
4654
|
-
this.rowIndex = 0;
|
|
4655
|
-
this.message = "";
|
|
4656
|
-
this.level = "INFO";
|
|
4657
|
-
this.messageKey = undefined;
|
|
4658
|
-
this.messageParams = undefined;
|
|
4659
|
-
}
|
|
4660
|
-
compare(other) { return this; }
|
|
4661
|
-
getPK() { return this.rowIndex; }
|
|
4662
|
-
setPK(pk) { this.rowIndex = pk; }
|
|
4663
|
-
}
|
|
4664
|
-
|
|
4665
|
-
class ExcelParserError extends Error {
|
|
4666
|
-
key;
|
|
4667
|
-
params;
|
|
4668
|
-
constructor(key, params) {
|
|
4669
|
-
super(key);
|
|
4670
|
-
this.key = key;
|
|
4671
|
-
this.params = params;
|
|
4672
|
-
this.name = 'ExcelParserError';
|
|
4673
|
-
}
|
|
4674
|
-
}
|
|
4675
|
-
class ExcelParser {
|
|
4676
|
-
mappings;
|
|
4677
|
-
constructor(mappings) {
|
|
4678
|
-
this.mappings = mappings;
|
|
4679
|
-
}
|
|
4680
|
-
async parse(file, options) {
|
|
4681
|
-
// PERFORMANS: XLSX library only loads at parse time!
|
|
4682
|
-
const XLSX = await import('xlsx');
|
|
4683
|
-
const sheetIndex = options?.sheetIndex ?? 0;
|
|
4684
|
-
const headerRowIndex = options?.headerRowIndex ?? 0; // 0-based
|
|
4685
|
-
return new Promise((resolve, reject) => {
|
|
4686
|
-
const reader = new FileReader();
|
|
4687
|
-
reader.onload = (e) => {
|
|
4688
|
-
try {
|
|
4689
|
-
const data = new Uint8Array(e.target?.result);
|
|
4690
|
-
const workbook = XLSX.read(data, { type: 'array' });
|
|
4691
|
-
if (!workbook.SheetNames[sheetIndex]) {
|
|
4692
|
-
throw new ExcelParserError('@EXCEL_PARSER.sheetNotFound', { index: sheetIndex });
|
|
4693
|
-
}
|
|
4694
|
-
const sheetName = workbook.SheetNames[sheetIndex];
|
|
4695
|
-
const sheet = workbook.Sheets[sheetName];
|
|
4696
|
-
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 });
|
|
4697
|
-
const logs = [];
|
|
4698
|
-
const result = [];
|
|
4699
|
-
// Skip headerline
|
|
4700
|
-
const dataRows = rows.slice(headerRowIndex + 1);
|
|
4701
|
-
dataRows.forEach((row, i) => {
|
|
4702
|
-
// Skip empty lines
|
|
4703
|
-
if (!row || row.length === 0)
|
|
4704
|
-
return;
|
|
4705
|
-
const obj = {};
|
|
4706
|
-
let hasError = false;
|
|
4707
|
-
const actualRowIndex = headerRowIndex + i + 2; // Excel line no (1-based)
|
|
4708
|
-
this.mappings.forEach(m => {
|
|
4709
|
-
let rawValue = row[m.index];
|
|
4710
|
-
if ((rawValue === undefined || rawValue === null || rawValue === '') && m.defaultValue !== undefined) {
|
|
4711
|
-
rawValue = m.defaultValue;
|
|
4712
|
-
logs.push(Object.assign(new ParseLog(), {
|
|
4713
|
-
rowIndex: actualRowIndex,
|
|
4714
|
-
message: `Boş alan için default değer atandı: ${String(m.prop)}`,
|
|
4715
|
-
level: 'INFO',
|
|
4716
|
-
messageKey: '@EXCEL_PARSER.defaultValueSet',
|
|
4717
|
-
messageParams: { prop: String(m.prop) }
|
|
4718
|
-
}));
|
|
4719
|
-
}
|
|
4720
|
-
if (m.required && (rawValue === undefined || rawValue === null || rawValue === '')) {
|
|
4721
|
-
logs.push(Object.assign(new ParseLog(), {
|
|
4722
|
-
rowIndex: actualRowIndex,
|
|
4723
|
-
message: `Zorunlu alan boş: ${String(m.prop)}`,
|
|
4724
|
-
level: 'ERROR',
|
|
4725
|
-
messageKey: '@EXCEL_PARSER.requiredFieldMissing',
|
|
4726
|
-
messageParams: { prop: String(m.prop) }
|
|
4727
|
-
}));
|
|
4728
|
-
hasError = true;
|
|
4729
|
-
}
|
|
4730
|
-
try {
|
|
4731
|
-
obj[m.prop] = m.converter ? m.converter(rawValue) : rawValue;
|
|
4732
|
-
}
|
|
4733
|
-
catch (err) {
|
|
4734
|
-
logs.push(Object.assign(new ParseLog(), {
|
|
4735
|
-
rowIndex: actualRowIndex,
|
|
4736
|
-
message: `Tip dönüşüm hatası: ${String(m.prop)} -> ${rawValue}`,
|
|
4737
|
-
level: 'ERROR',
|
|
4738
|
-
messageKey: '@EXCEL_PARSER.conversionError',
|
|
4739
|
-
messageParams: { prop: String(m.prop), value: rawValue }
|
|
4740
|
-
}));
|
|
4741
|
-
hasError = true;
|
|
4742
|
-
}
|
|
4743
|
-
});
|
|
4744
|
-
if (!hasError) {
|
|
4745
|
-
result.push(obj);
|
|
4746
|
-
}
|
|
4747
|
-
else {
|
|
4748
|
-
logs.push(Object.assign(new ParseLog(), {
|
|
4749
|
-
rowIndex: actualRowIndex,
|
|
4750
|
-
message: `Satır atlandı`,
|
|
4751
|
-
level: 'WARN',
|
|
4752
|
-
messageKey: '@EXCEL_PARSER.rowSkipped'
|
|
4753
|
-
}));
|
|
4754
|
-
}
|
|
4755
|
-
});
|
|
4756
|
-
resolve({ data: result, logs });
|
|
4757
|
-
}
|
|
4758
|
-
catch (error) {
|
|
4759
|
-
reject(error);
|
|
4760
|
-
}
|
|
4761
|
-
};
|
|
4762
|
-
reader.onerror = () => reject(reader.error);
|
|
4763
|
-
reader.readAsArrayBuffer(file);
|
|
4764
|
-
});
|
|
4765
|
-
}
|
|
4766
|
-
async generateSampleExcel(options) {
|
|
4767
|
-
const sampleCount = options?.sampleCount ?? 5;
|
|
4768
|
-
const fileName = (options?.fileName ?? 'sample-import.xlsx').endsWith('.xlsx')
|
|
4769
|
-
? (options?.fileName ?? 'sample-import.xlsx')
|
|
4770
|
-
: `${options?.fileName}.xlsx`;
|
|
4771
|
-
const sheetName = (options?.sheetName ?? 'Sample').substring(0, 15);
|
|
4772
|
-
const XLSX = await import('xlsx');
|
|
4773
|
-
// Header row: property names according to column order
|
|
4774
|
-
const headers = this.mappings.map(m => m.headerName || String(m.prop));
|
|
4775
|
-
const rows = [];
|
|
4776
|
-
for (let i = 1; i <= sampleCount; i++) {
|
|
4777
|
-
const row = this.mappings.map(m => {
|
|
4778
|
-
if (m.sampleValue !== undefined) {
|
|
4779
|
-
// Use sampleValue if it exists
|
|
4780
|
-
return typeof m.sampleValue === 'function'
|
|
4781
|
-
? m.sampleValue(i) // if it's a function, generate value based on index
|
|
4782
|
-
: m.sampleValue; // if it's a constant value, use it directly
|
|
4783
|
-
}
|
|
4784
|
-
});
|
|
4785
|
-
rows.push(row);
|
|
4786
|
-
}
|
|
4787
|
-
const worksheet = XLSX.utils.aoa_to_sheet([headers, ...rows]);
|
|
4788
|
-
const workbook = XLSX.utils.book_new();
|
|
4789
|
-
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
|
|
4790
|
-
XLSX.writeFile(workbook, fileName);
|
|
4791
|
-
}
|
|
4792
|
-
}
|
|
4793
|
-
|
|
4794
4810
|
// converters.ts
|
|
4795
4811
|
// Sayı dönüştürücü (hem . hem , destekler)
|
|
4796
4812
|
const toNumber = (v) => {
|