Files
OCR/frontend/src/app/templates/templates.component.ts

163 lines
5.3 KiB
TypeScript

import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { DragDropModule, CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { SplitterModule } from 'primeng/splitter';
import { ButtonModule } from 'primeng/button';
import { DialogModule } from 'primeng/dialog';
import { InputTextModule } from 'primeng/inputtext';
import { DropdownModule } from 'primeng/dropdown';
import { TableModule } from 'primeng/table';
import { ToastModule } from 'primeng/toast';
import { MessageService } from 'primeng/api';
import { TemplateService, DocumentLayout, TemplateField } from '../services/template.service';
@Component({
selector: 'app-templates',
standalone: true,
imports: [
CommonModule,
FormsModule,
DragDropModule,
SplitterModule,
ButtonModule,
DialogModule,
InputTextModule,
DropdownModule,
TableModule,
ToastModule
],
providers: [MessageService],
templateUrl: './templates.component.html',
styleUrls: ['./templates.component.scss']
})
export class TemplatesComponent implements OnInit {
// Document State
documentId: string | null = null;
layoutNodes: DocumentLayout[] = [];
// Template State
templateName: string = '';
templateFields: TemplateField[] = [];
mappings: { [fieldId: number]: DocumentLayout[] } = {};
// UI State
displayAddField: boolean = false;
newField: TemplateField = { field_label: '', field_type: 'TEXT', display_order: 0, required_flag: false };
fieldTypes = [
{ label: 'TEXT', value: 'TEXT' },
{ label: 'NUMBER', value: 'NUMBER' },
{ label: 'DATE', value: 'DATE' },
{ label: 'AMOUNT', value: 'AMOUNT' },
{ label: 'ADDRESS', value: 'ADDRESS' },
{ label: 'TABLE_COLUMN', value: 'TABLE_COLUMN' }
];
constructor(
private templateService: TemplateService,
private messageService: MessageService
) {}
ngOnInit(): void {}
onFileUpload(event: any) {
const file = event.target.files[0];
if (file) {
this.templateService.uploadDocument(file).subscribe({
next: (res) => {
this.documentId = res.id || res.pk_document_id;
this.messageService.add({ severity: 'success', summary: 'Uploaded', detail: 'Document uploaded successfully.' });
this.fetchLayout();
},
error: (err) => {
this.messageService.add({ severity: 'error', summary: 'Error', detail: 'Upload failed.' });
}
});
}
}
fetchLayout() {
if (!this.documentId) return;
this.templateService.getDocumentLayout(this.documentId).subscribe({
next: (layouts) => {
if (layouts.length === 0) {
// Document might still be processing in the background Celery worker
// Poll again after 2 seconds
setTimeout(() => this.fetchLayout(), 2000);
return;
}
this.layoutNodes = layouts;
// Trigger auto-recognition
this.autoRecognize();
}
});
}
autoRecognize() {
if (!this.documentId) return;
this.templateService.recognizeTemplate(this.documentId).subscribe({
next: (res) => {
if (res.templateMatched) {
this.messageService.add({ severity: 'info', summary: 'Template Recognized', detail: `Confidence: ${res.confidence}%` });
// In a full implementation, we'd load the template fields and populate the mappings.
}
}
});
}
showAddFieldDialog() {
this.newField = { field_label: '', field_type: 'TEXT', display_order: this.templateFields.length, required_flag: false };
this.displayAddField = true;
}
addField() {
if (!this.newField.field_label) return;
this.newField.pk_template_field_id = new Date().getTime(); // mock ID until saved
this.templateFields.push({ ...this.newField });
this.mappings[this.newField.pk_template_field_id] = [];
this.displayAddField = false;
}
saveTemplateAndMappings() {
if (!this.templateName || this.templateName.trim() === '') {
this.messageService.add({ severity: 'warn', summary: 'Warning', detail: 'Please provide a template name.' });
return;
}
if (this.templateFields.length === 0) {
this.messageService.add({ severity: 'warn', summary: 'Warning', detail: 'Please add at least one template field.' });
return;
}
this.templateService.createTemplate({
template_name: this.templateName,
fields: this.templateFields
}).subscribe({
next: (res) => {
// In a real scenario, we pass res.templateId and map the layoutNodes
this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Template & Mappings saved successfully.' });
}
});
}
// Drag and Drop Logic
drop(event: CdkDragDrop<DocumentLayout[]>, fieldId?: number) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex,
);
}
}
getConnectedDropLists() {
// Return all field ID strings as drop lists
return this.templateFields.map(f => 'field-' + f.pk_template_field_id);
}
}