tien_nemo

test load data

...@@ -17,13 +17,11 @@ class OcrController extends Controller ...@@ -17,13 +17,11 @@ class OcrController extends Controller
17 public function store(Request $request) 17 public function store(Request $request)
18 { 18 {
19 19
20 +// dd($request->all());
20 $request->validate([ 21 $request->validate([
21 'customer_name_text' => 'required|string', 22 'customer_name_text' => 'required|string',
22 'customer_name_xy' => 'required|string', 23 'customer_name_xy' => 'required|string',
23 'template_name' => 'required|string|unique:mst_template,tpl_name', 24 'template_name' => 'required|string|unique:mst_template,tpl_name',
24 - 'fields' => 'required|array',
25 - 'fields.*.name' => 'required|string',
26 - 'fields.*.xy' => 'required|string',
27 ]); 25 ]);
28 26
29 try { 27 try {
...@@ -35,11 +33,11 @@ class OcrController extends Controller ...@@ -35,11 +33,11 @@ class OcrController extends Controller
35 ]); 33 ]);
36 34
37 // Lưu các field khác vào dt_template 35 // Lưu các field khác vào dt_template
38 - foreach ($request->fields as $field) { 36 + foreach ($request->fields as $field => $value) {
39 DtTemplate::create([ 37 DtTemplate::create([
40 'tpl_id' => $mst->id, 38 'tpl_id' => $mst->id,
41 - 'field_name' => $field['name'], 39 + 'field_name' => $field,
42 - 'field_xy' => $field['xy'], 40 + 'field_xy' => is_array($value['coords']) ? implode(',', $value['coords']) : $value['coords'],
43 ]); 41 ]);
44 } 42 }
45 43
...@@ -61,7 +59,7 @@ class OcrController extends Controller ...@@ -61,7 +59,7 @@ class OcrController extends Controller
61 { 59 {
62 try { 60 try {
63 // Lấy template name từ request hoặc mặc định 61 // Lấy template name từ request hoặc mặc định
64 - $templateName = $request->get('template_name', 'nemo'); 62 + $templateName = $request->get('template_name', 'A');
65 63
66 // Giả sử file OCR JSON & ảnh nằm trong storage/app/public/image/ 64 // Giả sử file OCR JSON & ảnh nằm trong storage/app/public/image/
67 $jsonPath = public_path("image/data_picking_detail_1754967679.json"); 65 $jsonPath = public_path("image/data_picking_detail_1754967679.json");
...@@ -77,6 +75,7 @@ class OcrController extends Controller ...@@ -77,6 +75,7 @@ class OcrController extends Controller
77 } 75 }
78 76
79 $formData = []; 77 $formData = [];
78 + $dataMapping = [];
80 79
81 if ($templateName) { 80 if ($templateName) {
82 $mst = MstTemplate::where('tpl_name', $templateName)->first(); 81 $mst = MstTemplate::where('tpl_name', $templateName)->first();
...@@ -94,6 +93,11 @@ class OcrController extends Controller ...@@ -94,6 +93,11 @@ class OcrController extends Controller
94 93
95 // field_name => text 94 // field_name => text
96 $formData[$detail->field_name] = $text; 95 $formData[$detail->field_name] = $text;
96 +
97 + $dataMapping[$detail->field_name] = [
98 + 'text' => $text,
99 + 'coords' => $coords
100 + ];
97 } 101 }
98 } else { 102 } else {
99 $formData = [ 103 $formData = [
...@@ -112,6 +116,7 @@ class OcrController extends Controller ...@@ -112,6 +116,7 @@ class OcrController extends Controller
112 'ocrData' => $ocrData, 116 'ocrData' => $ocrData,
113 'pdfImageUrl' => $imgPath, 117 'pdfImageUrl' => $imgPath,
114 'formData' => $formData, 118 'formData' => $formData,
119 + 'dataMapping' => $dataMapping,
115 'fieldOptions' => [ 120 'fieldOptions' => [
116 [ 'value' => 'template_name', 'label' => 'Tên Mẫu PDF' ], 121 [ 'value' => 'template_name', 'label' => 'Tên Mẫu PDF' ],
117 [ 'value' => 'customer_name', 'label' => 'Tên khách hàng' ], 122 [ 'value' => 'customer_name', 'label' => 'Tên khách hàng' ],
......
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
26 } 26 }
27 27
28 .bbox.focus-highlight { 28 .bbox.focus-highlight {
29 - animation: focusPulse 2s ease-in-out; 29 + /*animation: focusPulse 2s ease-in-out;*/
30 - /*border-color: #ff6b35 !important;*/ 30 + border-color: #ff6b35 !important;
31 /*background-color: rgba(255, 107, 53, 0.4) !important;*/ 31 /*background-color: rgba(255, 107, 53, 0.4) !important;*/
32 } 32 }
33 33
...@@ -133,12 +133,11 @@ ...@@ -133,12 +133,11 @@
133 <input v-model="formData[field.value]" 133 <input v-model="formData[field.value]"
134 @focus="highlightField(field.value)" 134 @focus="highlightField(field.value)"
135 @click="onInputClick(field.value)" 135 @click="onInputClick(field.value)"
136 +{{-- @blur="removeManualBoxes"--}}
136 :readonly="field.value === 'customer_name' && !hasCustomerNameXY" 137 :readonly="field.value === 'customer_name' && !hasCustomerNameXY"
137 > 138 >
138 </div> 139 </div>
139 <button @click="saveTemplate">💾Save</button> 140 <button @click="saveTemplate">💾Save</button>
140 -{{-- <button @click="debugCoordinates" style="margin-left: 10px; background: #6c757d;">🐛Debug</button>--}}
141 -{{-- <button @click="testManualBox" style="margin-left: 10px; background: #28a745;">🧪Test Box</button>--}}
142 </div> 141 </div>
143 142
144 </div> 143 </div>
...@@ -156,6 +155,7 @@ ...@@ -156,6 +155,7 @@
156 activeIndex: null, 155 activeIndex: null,
157 manualField: "", 156 manualField: "",
158 formData: {}, 157 formData: {},
158 + manualBoxData: {},
159 fieldOptions: [], 159 fieldOptions: [],
160 customer_name_xy: '', 160 customer_name_xy: '',
161 hasCustomerNameXY: false, 161 hasCustomerNameXY: false,
...@@ -182,6 +182,10 @@ ...@@ -182,6 +182,10 @@
182 } 182 }
183 }, 183 },
184 methods: { 184 methods: {
185 + removeManualBoxes() {
186 + this.ocrData = this.ocrData.filter(b => !b.isManual);
187 + this.activeIndex = null;
188 + },
185 // Map field cho box (không set active, chỉ dùng để load data từ DB) 189 // Map field cho box (không set active, chỉ dùng để load data từ DB)
186 mapFieldToBox(index, fieldName, text = null) { 190 mapFieldToBox(index, fieldName, text = null) {
187 if (index == null) return; 191 if (index == null) return;
...@@ -230,21 +234,17 @@ ...@@ -230,21 +234,17 @@
230 } 234 }
231 }, 235 },
232 236
233 - // Assign field và set active (dùng khi user tương tác)
234 assignFieldToBox(index, fieldName, text = null) { 237 assignFieldToBox(index, fieldName, text = null) {
235 console.log(`Assigning field "${fieldName}" to box at index ${index} with text: "${text}"`); 238 console.log(`Assigning field "${fieldName}" to box at index ${index} with text: "${text}"`);
236 if (index == null) return; 239 if (index == null) return;
237 240
238 - // Xóa fieldName ở box khác 241 + // 1. Xóa box cũ của field này (nếu có)
239 - this.ocrData.forEach((box, i) => { 242 + this.ocrData = this.ocrData.filter((box, i) => {
240 - if (i !== index && box.field === fieldName) { 243 + return !(i !== index && box.field === fieldName && box.isManual);
241 - box.field = null;
242 - box.field_xy = null;
243 - }
244 }); 244 });
245 245
246 - // Nếu box này từng gán field khác thì bỏ 246 + // 2. Nếu box này từng gán field khác thì bỏ
247 - const prev = this.ocrData[index].field; 247 + const prev = this.ocrData[index]?.field;
248 if (prev && prev !== fieldName) { 248 if (prev && prev !== fieldName) {
249 if (prev === 'customer_name') { 249 if (prev === 'customer_name') {
250 this.hasCustomerNameXY = false; 250 this.hasCustomerNameXY = false;
...@@ -254,27 +254,34 @@ ...@@ -254,27 +254,34 @@
254 this.ocrData[index].field_xy = null; 254 this.ocrData[index].field_xy = null;
255 } 255 }
256 256
257 - // Gán field mới 257 + // 3. Gán field mới
258 const bbox = this.ocrData[index].bbox; // tọa độ OCR gốc [x1, y1, x2, y2] 258 const bbox = this.ocrData[index].bbox; // tọa độ OCR gốc [x1, y1, x2, y2]
259 - 259 + console.log('bbox', bbox);
260 - console.log('2222222222222222',bbox); 260 + const [x1, y1, w, h] = bbox;
261 - const x1 = bbox[0];
262 - const y1 = bbox[1];
263 - const w = bbox[2];
264 - const h = bbox[3];
265 -
266 const xyStr = `${x1},${y1},${w},${h}`; 261 const xyStr = `${x1},${y1},${w},${h}`;
267 262
268 this.ocrData[index].field = fieldName; 263 this.ocrData[index].field = fieldName;
269 this.ocrData[index].field_xy = xyStr; 264 this.ocrData[index].field_xy = xyStr;
270 265
271 - // Set text 266 + // 4. Gán text
272 - this.formData[fieldName] = (text !== null ? text : (this.ocrData[index].text || '')).trim(); 267 + const finalText = text !== null ? text : (this.ocrData[index].text || '');
268 + this.formData[fieldName] = finalText.trim();
269 + console.log(`formData ${fieldName}`, this.formData[fieldName]);
270 +
271 + // Nếu trong manualBoxData tồn tại field này hoặc muốn tạo lại manual box từ ocrData
272 + if (this.manualBoxData[fieldName]) {
273 + // Lấy tọa độ + text từ box hiện tại để tạo manual box mới
274 + this.createManualBoxFromDB(fieldName, this.ocrData[index].bbox, finalText);
275 + // Cập nhật manualBoxData
276 + this.manualBoxData[fieldName] = {
277 + coords: this.ocrData[index].bbox,
278 + text: finalText
279 + };
280 + }
273 281
274 - // Active index (focus vào box này) 282 + // 5. Active index
275 this.activeIndex = index; 283 this.activeIndex = index;
276 - 284 + // 6. Nếu là customer_name
277 - // Nếu là customer_name
278 if (fieldName === 'customer_name') { 285 if (fieldName === 'customer_name') {
279 this.hasCustomerNameXY = true; 286 this.hasCustomerNameXY = true;
280 this.customer_name_xy = xyStr; 287 this.customer_name_xy = xyStr;
...@@ -284,29 +291,47 @@ ...@@ -284,29 +291,47 @@
284 291
285 async saveTemplate() { 292 async saveTemplate() {
286 293
287 - if (!this.hasCustomerNameXY) { 294 + let customer_name = null;
295 + let customer_coords = null;
296 + let fields = [];
297 + if (this.manualBoxData.customer_name) {
298 + // Lấy từ manualBoxData nếu có
299 + customer_name = this.manualBoxData.customer_name.text;
300 + customer_coords = this.manualBoxData.customer_name.coords.join(',');
301 + fields = this.manualBoxData;
302 + } else {
303 + // Không có → tìm trong ocrData
304 + const found = this.ocrData.find(item => item.field === 'customer_name');
305 + if (found) {
306 + customer_name = found.text;
307 + customer_coords = found.field_xy;
308 + }
309 +
310 + const fieldsByName = {};
311 + this.ocrData.forEach(box => {
312 + if (box.field && !box.isDeleted) {
313 + // chỉ giữ 1 bản ghi cuối cùng cho mỗi field (box gần nhất)
314 + fieldsByName[box.field] = {
315 + text: box.field,
316 + coords: box.field_xy || ''
317 + };
318 + }
319 + });
320 + // // convert to array
321 + fields = (fieldsByName);
322 + }
323 +
324 + console.log('fields:', fields);
325 +
326 + if (!customer_coords) {
288 alert("Bạn phải map customer_name (quét/select) trước khi lưu."); 327 alert("Bạn phải map customer_name (quét/select) trước khi lưu.");
289 return; 328 return;
290 } 329 }
291 330
292 - // build fields array: lấy những box có field gán, map unique by field name -> sử dụng field_xy
293 - const fieldsByName = {};
294 - this.ocrData.forEach(box => {
295 - if (box.field && !box.isDeleted) {
296 - // chỉ giữ 1 bản ghi cuối cùng cho mỗi field (box gần nhất)
297 - fieldsByName[box.field] = {
298 - name: box.field,
299 - xy: box.field_xy || ''
300 - };
301 - }
302 - });
303 - // convert to array
304 - const fields = Object.values(fieldsByName);
305 -
306 const payload = { 331 const payload = {
307 - customer_name_text: this.formData.customer_name || '', 332 + customer_name_text: customer_name || '',
308 template_name: this.formData.template_name || this.formData.customer_name, 333 template_name: this.formData.template_name || this.formData.customer_name,
309 - customer_name_xy: this.customer_name_xy, 334 + customer_name_xy: customer_coords || [],
310 fields: fields 335 fields: fields
311 }; 336 };
312 // console.log(fields); 337 // console.log(fields);
...@@ -375,6 +400,7 @@ ...@@ -375,6 +400,7 @@
375 this.pdfImageUrl = data.pdfImageUrl; 400 this.pdfImageUrl = data.pdfImageUrl;
376 this.formData = data.formData; 401 this.formData = data.formData;
377 this.fieldOptions = data.fieldOptions; 402 this.fieldOptions = data.fieldOptions;
403 + this.dataMapping = data.dataMapping;
378 // Đợi image load xong trước khi xử lý 404 // Đợi image load xong trước khi xử lý
379 if (this.$refs.pdfImage && this.$refs.pdfImage.complete) { 405 if (this.$refs.pdfImage && this.$refs.pdfImage.complete) {
380 this.processLoadedData(); 406 this.processLoadedData();
...@@ -394,7 +420,6 @@ ...@@ -394,7 +420,6 @@
394 // Tự động map field cho các box OCR dựa trên formData đã load 420 // Tự động map field cho các box OCR dựa trên formData đã load
395 this.autoMapFieldsFromFormData(); 421 this.autoMapFieldsFromFormData();
396 // Kiểm tra và sửa lại tọa độ của các box manual 422 // Kiểm tra và sửa lại tọa độ của các box manual
397 - // this.validateManualBoxes();
398 423
399 // Force re-render để đảm bảo các box được vẽ 424 // Force re-render để đảm bảo các box được vẽ
400 this.$nextTick(() => { 425 this.$nextTick(() => {
...@@ -404,20 +429,13 @@ ...@@ -404,20 +429,13 @@
404 429
405 // Tự động map field cho các box OCR dựa trên formData đã load từ DB 430 // Tự động map field cho các box OCR dựa trên formData đã load từ DB
406 autoMapFieldsFromFormData() { 431 autoMapFieldsFromFormData() {
407 - // Duyệt qua tất cả các field trong formData 432 + this.manualBoxData = {}; // reset
408 - Object.keys(this.formData).forEach(fieldName => { 433 + Object.keys(this.dataMapping).forEach(fieldName => {
409 - const fieldValue = this.formData[fieldName]; 434 + const { text, coords } = this.dataMapping[fieldName];
410 - 435 + // Ví dụ: tạo box từ dữ liệu
411 - // Chỉ xử lý các field có giá trị (không phải template_name) 436 + //this.createManualBoxFromDB(fieldName, coords, text);
412 - if (fieldValue && fieldValue.trim() && fieldName !== 'template_name') { 437 +
413 - // Tìm box OCR phù hợp nhất để map 438 + this.manualBoxData[fieldName] = { text, coords };
414 - const bestMatchIndex = this.findBestMatchingBox(fieldName, fieldValue);
415 -
416 - if (bestMatchIndex !== -1) {
417 - // Chỉ map field, không set active (không focus)
418 - this.mapFieldToBox(bestMatchIndex, fieldName, fieldValue);
419 - }
420 - }
421 }); 439 });
422 440
423 }, 441 },
...@@ -512,9 +530,55 @@ ...@@ -512,9 +530,55 @@
512 }; 530 };
513 }, 531 },
514 532
533 + // highlightField(field) {
534 + // let idx = -1;
535 + // for (let i = this.ocrData.length - 1; i >= 0; i--) {
536 + // const it = this.ocrData[i];
537 + // if (!it.isDeleted && it.field === field) {
538 + // idx = i;
539 + // break;
540 + // }
541 + // }
542 + //
543 + // if (idx !== -1) {
544 + // // Set active index (chuyển trạng thái active và màu xanh)
545 + // this.activeIndex = idx;
546 + // // Scroll đến box tương ứng
547 + // this.scrollToBox(idx);
548 + // // Focus vào box để người dùng thấy rõ
549 + // this.focusOnBox(idx);
550 + // } else {
551 + // this.activeIndex = null;
552 + // }
553 + // },
554 +
515 highlightField(field) { 555 highlightField(field) {
556 + // Xóa tất cả manual box cũ trước khi tạo mới
557 + // this.ocrData = this.ocrData.filter(b => !b.isManual);
558 +
559 + let coords, text;
560 +
561 + // Kiểm tra xem ocrData đã có box nào với field này chưa
562 + const existingBox = this.ocrData.find(b => b.field === field && !b.isManual);
563 +
564 + if (existingBox) {
565 + coords = existingBox.bbox;
566 + text = existingBox.text;
567 + console.log(`Using ocrData for field "${field}":`, coords, text);
568 + } else if (this.manualBoxData[field]) {
569 + // Nếu không có trong ocrData, dùng manualBoxData
570 + coords = this.manualBoxData[field].coords;
571 + text = this.manualBoxData[field].text;
572 + console.log(`Using manualBoxData for field "${field}":`, coords, text);
573 + }
574 +
575 + // Nếu có coords thì tạo manual box
576 + if (coords) {
577 + this.createManualBoxFromDB(field, coords, text);
578 + }
579 +
580 + // Tìm lại index của box vừa tạo để set active
516 let idx = -1; 581 let idx = -1;
517 - console.log(`Highlighting field: ${field}`);
518 for (let i = this.ocrData.length - 1; i >= 0; i--) { 582 for (let i = this.ocrData.length - 1; i >= 0; i--) {
519 const it = this.ocrData[i]; 583 const it = this.ocrData[i];
520 if (!it.isDeleted && it.field === field) { 584 if (!it.isDeleted && it.field === field) {
...@@ -522,32 +586,27 @@ ...@@ -522,32 +586,27 @@
522 break; 586 break;
523 } 587 }
524 } 588 }
525 - console.log('ssss', idx, this.ocrData[idx]);
526 589
527 if (idx !== -1) { 590 if (idx !== -1) {
528 - // Set active index (chuyển trạng thái active và màu xanh)
529 this.activeIndex = idx; 591 this.activeIndex = idx;
530 - // Scroll đến box tương ứng
531 this.scrollToBox(idx); 592 this.scrollToBox(idx);
532 - // Focus vào box để người dùng thấy rõ
533 this.focusOnBox(idx); 593 this.focusOnBox(idx);
534 } else { 594 } else {
535 this.activeIndex = null; 595 this.activeIndex = null;
536 } 596 }
537 }, 597 },
538 598
599 +
539 // Scroll đến box tương ứng 600 // Scroll đến box tương ứng
540 scrollToBox(index) { 601 scrollToBox(index) {
541 if (!this.$refs.pdfContainer || index < 0 || index >= this.ocrData.length) return; 602 if (!this.$refs.pdfContainer || index < 0 || index >= this.ocrData.length) return;
542 603
543 const item = this.ocrData[index]; 604 const item = this.ocrData[index];
544 - console.log(`Scrolling to box at index ${index}:`, item);
545 if (!item || item.isDeleted) return; 605 if (!item || item.isDeleted) return;
546 606
547 // Tính vị trí hiển thị của box 607 // Tính vị trí hiển thị của box
548 - // const [x1, y1, x2, y2] = item.bbox; 608 + const [x1, y1, x2, y2] = item.bbox;
549 - const [x1, y1, x2, y2] = item.field_xy.split(',').map(Number); 609 + //const [x1, y1, x2, y2] = item.field_xy.split(',').map(Number);
550 - console.log(`Box coordinates for scrolling: [${x1}, ${y1}, ${x2}, ${y2}]`);
551 if (!this.imageWidth || !this.imageHeight || !this.$refs.pdfImage) return; 610 if (!this.imageWidth || !this.imageHeight || !this.$refs.pdfImage) return;
552 611
553 const displayedWidth = this.$refs.pdfImage.clientWidth; 612 const displayedWidth = this.$refs.pdfImage.clientWidth;
...@@ -587,9 +646,6 @@ ...@@ -587,9 +646,6 @@
587 const boxElement = document.querySelector(`[data-field="${item.field}"]`); 646 const boxElement = document.querySelector(`[data-field="${item.field}"]`);
588 if (boxElement) { 647 if (boxElement) {
589 boxElement.classList.add('focus-highlight'); 648 boxElement.classList.add('focus-highlight');
590 - setTimeout(() => {
591 - boxElement.classList.remove('focus-highlight');
592 - }, 2000);
593 } 649 }
594 }); 650 });
595 }, 651 },
...@@ -683,6 +739,7 @@ ...@@ -683,6 +739,7 @@
683 739
684 e.stopPropagation(); 740 e.stopPropagation();
685 e.preventDefault(); 741 e.preventDefault();
742 +
686 } 743 }
687 , 744 ,
688 applyMapping() { 745 applyMapping() {
...@@ -707,9 +764,6 @@ ...@@ -707,9 +764,6 @@
707 const manualIndex = this.manualIndex; 764 const manualIndex = this.manualIndex;
708 765
709 const newBbox = this.ocrData[manualIndex].bbox; 766 const newBbox = this.ocrData[manualIndex].bbox;
710 - console.log(`33333 ${manualIndex} with field "${this.manualField}" new box ${newBbox}`);
711 - // console.log('Applying manual mapping for field:', this.manualField);
712 - // console.log('Manual bbox:', newBbox);
713 767
714 let combinedText = []; 768 let combinedText = [];
715 let foundItems = []; 769 let foundItems = [];
...@@ -725,8 +779,6 @@ ...@@ -725,8 +779,6 @@
725 } 779 }
726 }); 780 });
727 781
728 - // console.log('Found OCR items in manual area:', foundItems);
729 -
730 // Sắp xếp các item theo vị trí (từ trái sang phải, từ trên xuống dưới) 782 // Sắp xếp các item theo vị trí (từ trái sang phải, từ trên xuống dưới)
731 foundItems.sort((a, b) => { 783 foundItems.sort((a, b) => {
732 // Ưu tiên theo Y trước (hàng), sau đó theo X (cột) 784 // Ưu tiên theo Y trước (hàng), sau đó theo X (cột)
...@@ -745,6 +797,8 @@ ...@@ -745,6 +797,8 @@
745 // console.log('Combined text:', finalText); 797 // console.log('Combined text:', finalText);
746 798
747 // Gán field và text cho box manual 799 // Gán field và text cho box manual
800 + console.log(`Assigning manual field "${this.manualField}" to box at index ${manualIndex} with text: "${finalText}"`);
801 + // console.log(this.ocrData[manualIndex]);
748 this.assignFieldToBox(manualIndex, this.manualField, finalText); 802 this.assignFieldToBox(manualIndex, this.manualField, finalText);
749 803
750 // Reset trạng thái chọn 804 // Reset trạng thái chọn
...@@ -794,18 +848,7 @@ ...@@ -794,18 +848,7 @@
794 const startIndex = Math.floor(startRatio * text.length); 848 const startIndex = Math.floor(startRatio * text.length);
795 const endIndex = Math.ceil(endRatio * text.length); 849 const endIndex = Math.ceil(endRatio * text.length);
796 850
797 - const partialText = text.substring(startIndex, endIndex).trim(); 851 + return text.substring(startIndex, endIndex).trim();
798 -
799 - // console.log('Partial text calculation:', {
800 - // originalText: text,
801 - // bbox: bbox,
802 - // selectBbox: selectBbox,
803 - // startRatio, endRatio,
804 - // startIndex, endIndex,
805 - // partialText
806 - // });
807 -
808 - return partialText;
809 }, 852 },
810 getSelectStyle(item) { 853 getSelectStyle(item) {
811 if (!this.imageWidth) return { position: 'absolute' }; 854 if (!this.imageWidth) return { position: 'absolute' };
...@@ -824,133 +867,6 @@ ...@@ -824,133 +867,6 @@
824 }; 867 };
825 }, 868 },
826 869
827 - // Debug method để kiểm tra tọa độ
828 - debugCoordinates() {
829 - console.log('=== DEBUG COORDINATES ===');
830 - console.log('Image dimensions:', {
831 - natural: { width: this.imageWidth, height: this.imageHeight },
832 - displayed: {
833 - width: this.$refs.pdfImage?.clientWidth,
834 - height: this.$refs.pdfImage?.clientHeight
835 - }
836 - });
837 -
838 - console.log('Scale factors:', {
839 - scaleX: this.$refs.pdfImage ? this.$refs.pdfImage.clientWidth / this.imageWidth : 'N/A',
840 - scaleY: this.$refs.pdfImage ? this.$refs.pdfImage.clientHeight / this.imageHeight : 'N/A'
841 - });
842 -
843 - console.log('OCR Data with coordinates:');
844 - this.ocrData.forEach((item, index) => {
845 - if (!item.isDeleted) {
846 - console.log(`Item ${index}:`, {
847 - text: item.text,
848 - bbox: item.bbox,
849 - field: item.field,
850 - isManual: item.isManual
851 - });
852 - }
853 - });
854 - console.log('=== END DEBUG ===');
855 - },
856 -
857 - // Kiểm tra và sửa lại tọa độ của các box manual
858 - validateManualBoxes() {
859 - if (!this.imageWidth || !this.imageHeight) {
860 - console.log('validateManualBoxes: Image not loaded yet');
861 - return;
862 - }
863 -
864 - this.ocrData.forEach((item, index) => {
865 - if (item.isManual && !item.isDeleted) {
866 - const [x1, y1, x2, y2] = item.bbox;
867 -
868 - const isValid = (
869 - x1 >= 0 && y1 >= 0 &&
870 - x2 > x1 && y2 > y1 &&
871 - x2 <= this.imageWidth && y2 <= this.imageHeight
872 - );
873 -
874 - if (!isValid) {
875 - // Thử sửa lại tọa độ nếu có thể
876 - this.fixManualBoxCoordinates(item, index);
877 - }
878 - }
879 - });
880 -
881 - console.log('=== END VALIDATION ===');
882 -
883 - // Force re-render để đảm bảo các box được vẽ đúng
884 - this.$nextTick(() => {
885 - this.$forceUpdate();
886 - });
887 - },
888 -
889 - // Sửa lại tọa độ của box manual nếu bị lỗi
890 - fixManualBoxCoordinates(item, index) {
891 - console.log(`Attempting to fix manual box ${index}:`, item);
892 -
893 - // Nếu tọa độ âm, đặt về 0
894 - let [x1, y1, x2, y2] = item.bbox;
895 -
896 - if (x1 < 0) x1 = 0;
897 - if (y1 < 0) y1 = 0;
898 - if (x2 <= x1) x2 = x1 + 100; // Tạo width mặc định
899 - if (y2 <= y1) y2 = y1 + 50; // Tạo height mặc định
900 -
901 - // Đảm bảo không vượt quá image bounds
902 - if (x2 > this.imageWidth) x2 = this.imageWidth;
903 - if (y2 > this.imageHeight) y2 = this.imageHeight;
904 -
905 - const fixedBbox = [x1, y1, x2, y2];
906 - console.log(`Fixed bbox for manual box ${index}:`, {
907 - original: item.bbox,
908 - fixed: fixedBbox
909 - });
910 -
911 - // Cập nhật tọa độ
912 - this.$set(this.ocrData[index], 'bbox', fixedBbox);
913 - },
914 -
915 - // Test method để tạo box manual test
916 - testManualBox() {
917 - if (!this.imageWidth || !this.imageHeight) {
918 - alert('Image chưa được load. Vui lòng đợi image load xong.');
919 - return;
920 - }
921 -
922 - // Tạo một box manual test ở giữa image
923 - const centerX = Math.round(this.imageWidth / 2);
924 - const centerY = Math.round(this.imageHeight / 2);
925 - const boxSize = 100;
926 -
927 - const testBbox = [
928 - centerX - boxSize/2, // x1
929 - centerY - boxSize/2, // y1
930 - centerX + boxSize/2, // x2
931 - centerY + boxSize/2 // y2
932 - ];
933 -
934 - console.log('Creating test manual box:', {
935 - bbox: testBbox,
936 - imageDimensions: { width: this.imageWidth, height: this.imageHeight }
937 - });
938 -
939 - // Thêm box test
940 - this.ocrData.push({
941 - text: "TEST BOX",
942 - bbox: testBbox,
943 - field: "test_field",
944 - isManual: true,
945 - showDelete: true,
946 - isDeleted: false,
947 - hideBorder: false
948 - });
949 -
950 - // Force re-render
951 - this.$forceUpdate();
952 - },
953 -
954 // Tạo box manual từ tọa độ trong DB 870 // Tạo box manual từ tọa độ trong DB
955 createManualBoxFromDB(fieldName, coordinates, text) { 871 createManualBoxFromDB(fieldName, coordinates, text) {
956 if (!this.imageWidth || !this.imageHeight) { 872 if (!this.imageWidth || !this.imageHeight) {
...@@ -971,13 +887,6 @@ ...@@ -971,13 +887,6 @@
971 887
972 const [x1, y1, x2, y2] = coords; 888 const [x1, y1, x2, y2] = coords;
973 889
974 - console.log('Creating manual box from DB:', {
975 - fieldName,
976 - coordinates,
977 - parsed: coords,
978 - imageDimensions: { width: this.imageWidth, height: this.imageHeight }
979 - });
980 -
981 // Kiểm tra tọa độ có hợp lệ không 890 // Kiểm tra tọa độ có hợp lệ không
982 if (x1 >= 0 && y1 >= 0 && x2 > x1 && y2 > y1 && 891 if (x1 >= 0 && y1 >= 0 && x2 > x1 && y2 > y1 &&
983 x2 <= this.imageWidth && y2 <= this.imageHeight) { 892 x2 <= this.imageWidth && y2 <= this.imageHeight) {
...@@ -988,13 +897,13 @@ ...@@ -988,13 +897,13 @@
988 bbox: coords, 897 bbox: coords,
989 field: fieldName, 898 field: fieldName,
990 isManual: true, 899 isManual: true,
991 - showDelete: true, 900 + showDelete: false,
992 isDeleted: false, 901 isDeleted: false,
993 - hideBorder: false 902 + hideBorder: true
994 }; 903 };
995 904
996 this.ocrData.push(manualBox); 905 this.ocrData.push(manualBox);
997 - console.log('Manual box created successfully:', manualBox); 906 + // console.log('Manual box created successfully:', manualBox);
998 907
999 // Force re-render 908 // Force re-render
1000 this.$forceUpdate(); 909 this.$forceUpdate();
......