+
+
Upload a document to view its extracted layout structure.
+
+
+
+
+
+ Analyzing Document Layout...
+
+
Extracting text, tables, and regions
+
+
diff --git a/frontend/src/app/templates/templates.component.scss b/frontend/src/app/templates/templates.component.scss
index d46f485..152b485 100644
--- a/frontend/src/app/templates/templates.component.scss
+++ b/frontend/src/app/templates/templates.component.scss
@@ -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; }
+}
diff --git a/frontend/src/app/templates/templates.component.ts b/frontend/src/app/templates/templates.component.ts
index 728a13a..615b3b8 100644
--- a/frontend/src/app/templates/templates.component.ts
+++ b/frontend/src/app/templates/templates.component.ts
@@ -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();
@@ -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)
+ }
}
}