OCR Template mapping done Now lets work on user and permission modules
This commit is contained in:
@@ -13,12 +13,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="preview-area p-4" style="overflow-y: auto;">
|
||||
<div *ngIf="layoutNodes.length === 0" class="empty-state">
|
||||
<i class="pi pi-file-pdf text-4xl mb-3"></i>
|
||||
<div class="preview-area p-4" style="overflow-y: auto; position: relative;">
|
||||
<div *ngIf="layoutNodes.length === 0 && !isScanning" class="empty-state">
|
||||
<i class="pi pi-file text-4xl mb-3"></i>
|
||||
<p>Upload a document to view its extracted layout structure.</p>
|
||||
</div>
|
||||
|
||||
<!-- Scanning Overlay -->
|
||||
<div *ngIf="isScanning" class="scanning-overlay">
|
||||
<div class="scanner-container">
|
||||
<i class="pi pi-file text-6xl text-gray-400 mb-4 scanner-doc"></i>
|
||||
<div class="laser-beam"></div>
|
||||
<div class="scanner-grid"></div>
|
||||
</div>
|
||||
<div class="scanning-text mt-4">
|
||||
<i class="pi pi-spin pi-cog mr-2"></i>
|
||||
<span class="font-semibold text-lg text-primary">Analyzing Document Layout...</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mt-2">Extracting text, tables, and regions</p>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let page of pages; let i = index" class="document-page-container mb-5">
|
||||
<div class="page-header text-sm font-semibold text-gray-500 mb-2">Page {{ page.page_number }}</div>
|
||||
|
||||
|
||||
@@ -225,3 +225,74 @@
|
||||
.cdk-drag-animating {
|
||||
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Scanning Overlay Animation */
|
||||
.scanning-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.scanner-container {
|
||||
position: relative;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #f8f9fa;
|
||||
box-shadow: inset 0 0 10px rgba(0,0,0,0.05);
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.scanner-doc {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.laser-beam {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: var(--primary-color, #3b82f6);
|
||||
box-shadow: 0 0 10px 2px var(--primary-color, #3b82f6);
|
||||
z-index: 2;
|
||||
animation: scan-laser 2s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
.scanner-grid {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: linear-gradient(var(--primary-100, #dbeafe) 1px, transparent 1px),
|
||||
linear-gradient(90deg, var(--primary-100, #dbeafe) 1px, transparent 1px);
|
||||
background-size: 10px 10px;
|
||||
z-index: 0;
|
||||
opacity: 0.5;
|
||||
animation: scan-grid 4s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes scan-laser {
|
||||
0% { top: -5%; opacity: 0; }
|
||||
10% { opacity: 1; }
|
||||
90% { opacity: 1; }
|
||||
100% { top: 105%; opacity: 0; }
|
||||
}
|
||||
|
||||
@keyframes scan-grid {
|
||||
0% { background-position: 0 0; }
|
||||
100% { background-position: 20px 20px; }
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ export class TemplatesComponent implements OnInit {
|
||||
{ label: 'TEXT', value: 'TEXT' },
|
||||
{ label: 'NUMBER', value: 'NUMBER' },
|
||||
{ label: 'DATE', value: 'DATE' },
|
||||
{ label: 'DATETIME', value: 'DATETIME' },
|
||||
{ label: 'AMOUNT', value: 'AMOUNT' },
|
||||
{ label: 'ADDRESS', value: 'ADDRESS' },
|
||||
{ label: 'TABLE_COLUMN', value: 'TABLE_COLUMN' }
|
||||
@@ -79,6 +80,7 @@ export class TemplatesComponent implements OnInit {
|
||||
next: (res) => {
|
||||
this.documentId = res.id || res.pk_document_id;
|
||||
this.messageService.add({ severity: 'success', summary: 'Uploaded', detail: 'Document uploaded successfully.' });
|
||||
this.isScanning = true;
|
||||
this.fetchLayout();
|
||||
},
|
||||
error: (err) => {
|
||||
@@ -98,6 +100,8 @@ export class TemplatesComponent implements OnInit {
|
||||
setTimeout(() => this.fetchLayout(), 2000);
|
||||
return;
|
||||
}
|
||||
|
||||
this.isScanning = false;
|
||||
this.layoutNodes = layouts;
|
||||
|
||||
const pageMap = new Map<number, { page_number: number, nodes: DocumentLayout[], width: number, height: number }>();
|
||||
@@ -300,6 +304,27 @@ export class TemplatesComponent implements OnInit {
|
||||
} else {
|
||||
clonedNode.text_value = '';
|
||||
}
|
||||
} else if (field && (field.field_type === 'DATE' || field.field_type === 'DATETIME') && clonedNode.text_value) {
|
||||
// Attempt to parse the date and output standard format
|
||||
const timestamp = Date.parse(clonedNode.text_value);
|
||||
if (!isNaN(timestamp)) {
|
||||
const parsedDate = new Date(timestamp);
|
||||
// Extract YYYY-MM-DD
|
||||
const yyyy = parsedDate.getFullYear();
|
||||
const mm = String(parsedDate.getMonth() + 1).padStart(2, '0');
|
||||
const dd = String(parsedDate.getDate()).padStart(2, '0');
|
||||
if (field.field_type === 'DATE') {
|
||||
clonedNode.text_value = `${yyyy}-${mm}-${dd}`;
|
||||
} else {
|
||||
const hh = String(parsedDate.getHours()).padStart(2, '0');
|
||||
const min = String(parsedDate.getMinutes()).padStart(2, '0');
|
||||
const ss = String(parsedDate.getSeconds()).padStart(2, '0');
|
||||
clonedNode.text_value = `${yyyy}-${mm}-${dd}T${hh}:${min}:${ss}`;
|
||||
}
|
||||
} else {
|
||||
// If we can't parse it reliably on frontend, we leave it or let backend handle it
|
||||
// We'll leave it as is to give user visual feedback, backend parser is more robust (dateutil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user