Update index.html
Browse files- index.html +142 -23
index.html
CHANGED
|
@@ -28,7 +28,6 @@
|
|
| 28 |
--shadow: 0 18px 60px rgba(0,0,0,.35);
|
| 29 |
--radius:18px;
|
| 30 |
|
| 31 |
-
--ok:#22c55e;
|
| 32 |
--warn:#f59e0b;
|
| 33 |
--bad:#ef4444;
|
| 34 |
}
|
|
@@ -169,6 +168,27 @@
|
|
| 169 |
border-color: rgba(245,158,11,.28);
|
| 170 |
}
|
| 171 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
.tableWrap{
|
| 173 |
overflow:auto;
|
| 174 |
border-radius: var(--radius);
|
|
@@ -235,6 +255,7 @@
|
|
| 235 |
<div class="wrap">
|
| 236 |
<div class="hero">
|
| 237 |
<p class="creditLine">تصميم وإعداد: نوف الناصر</p>
|
|
|
|
| 238 |
<h1 class="titleBar">إدارة حالات الإقرارات وتوثيق الاستلام</h1>
|
| 239 |
<p class="subNote">
|
| 240 |
أدخل البيانات ثم اختر الحالة. يتم الحفظ تلقائيًا ولا تختفي السجلات عند إغلاق الصفحة إلا بالحذف.
|
|
@@ -267,6 +288,7 @@
|
|
| 267 |
</select>
|
| 268 |
</div>
|
| 269 |
|
|
|
|
| 270 |
<div id="respondedBlock" style="grid-column:1/-1; display:none;">
|
| 271 |
<div class="formGrid">
|
| 272 |
<div style="grid-column:1/-1">
|
|
@@ -299,17 +321,16 @@
|
|
| 299 |
<input id="date" type="date" />
|
| 300 |
</div>
|
| 301 |
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
</div>
|
| 313 |
|
| 314 |
<div class="noteBox" id="respondedHelp">
|
| 315 |
عند اختيار <b>استجاب</b> يُفضّل تحديد (مركز/فرع مستقل/مفردة)، ثم تُكمل بيانات الاستلام إن توفرت.
|
|
@@ -336,6 +357,7 @@
|
|
| 336 |
</div>
|
| 337 |
</div>
|
| 338 |
|
|
|
|
| 339 |
<div class="card">
|
| 340 |
<h3>إدارة السجلات <span class="badge">بحث + حذف</span></h3>
|
| 341 |
|
|
@@ -353,6 +375,7 @@
|
|
| 353 |
</div>
|
| 354 |
</div>
|
| 355 |
|
|
|
|
| 356 |
<div class="card" style="margin-top:14px;">
|
| 357 |
<h3>الجدول</h3>
|
| 358 |
|
|
@@ -382,7 +405,7 @@
|
|
| 382 |
</div>
|
| 383 |
|
| 384 |
<script>
|
| 385 |
-
const STORAGE_KEY = "
|
| 386 |
|
| 387 |
const el = {
|
| 388 |
company: document.getElementById("company"),
|
|
@@ -394,7 +417,6 @@
|
|
| 394 |
mobile: document.getElementById("mobile"),
|
| 395 |
email: document.getElementById("email"),
|
| 396 |
date: document.getElementById("date"),
|
| 397 |
-
signature: document.getElementById("signature"),
|
| 398 |
extraNote: document.getElementById("extraNote"),
|
| 399 |
photoNote: document.getElementById("photoNote"),
|
| 400 |
|
|
@@ -410,6 +432,13 @@
|
|
| 410 |
deleteAllBtn: document.getElementById("deleteAllBtn"),
|
| 411 |
};
|
| 412 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 413 |
let records = [];
|
| 414 |
let editId = null;
|
| 415 |
|
|
@@ -491,7 +520,7 @@
|
|
| 491 |
if(el.receiver) el.receiver.value = "";
|
| 492 |
if(el.mobile) el.mobile.value = "";
|
| 493 |
if(el.email) el.email.value = "";
|
| 494 |
-
|
| 495 |
}
|
| 496 |
}
|
| 497 |
|
|
@@ -504,10 +533,10 @@
|
|
| 504 |
if(el.mobile) el.mobile.value = "";
|
| 505 |
if(el.email) el.email.value = "";
|
| 506 |
el.date.value = todayISO();
|
| 507 |
-
if(el.signature) el.signature.value = "";
|
| 508 |
el.extraNote.value = "";
|
| 509 |
editId = null;
|
| 510 |
el.saveBtn.textContent = "💾 حفظ";
|
|
|
|
| 511 |
updateConditionalUI();
|
| 512 |
}
|
| 513 |
|
|
@@ -520,11 +549,23 @@
|
|
| 520 |
if(el.mobile) el.mobile.value = rec.mobile || "";
|
| 521 |
if(el.email) el.email.value = rec.email || "";
|
| 522 |
el.date.value = rec.date || todayISO();
|
| 523 |
-
if(el.signature) el.signature.value = rec.signature || "";
|
| 524 |
el.extraNote.value = rec.extraNote || "";
|
| 525 |
editId = rec.id;
|
| 526 |
el.saveBtn.textContent = "✅ حفظ التعديل";
|
| 527 |
updateConditionalUI();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 528 |
window.scrollTo({ top: 0, behavior: "smooth" });
|
| 529 |
}
|
| 530 |
|
|
@@ -534,7 +575,7 @@
|
|
| 534 |
return records.filter(r => {
|
| 535 |
const hay = [
|
| 536 |
r.company, r.cr, statusLabel(r.status), respondedTypeLabel(r.respondedType),
|
| 537 |
-
r.receiver, r.mobile, r.email, r.date, r.
|
| 538 |
].join(" ").toLowerCase();
|
| 539 |
return hay.includes(q);
|
| 540 |
});
|
|
@@ -557,7 +598,7 @@
|
|
| 557 |
<td>${escapeHtml(r.mobile)}</td>
|
| 558 |
<td>${escapeHtml(r.email)}</td>
|
| 559 |
<td>${escapeHtml(r.date)}</td>
|
| 560 |
-
<td>${
|
| 561 |
<td>${escapeHtml(r.note || "")}${r.extraNote ? " | " + escapeHtml(r.extraNote) : ""}</td>
|
| 562 |
<td>
|
| 563 |
<button class="tinyBtn edit" data-action="edit" data-id="${r.id}">تعديل</button>
|
|
@@ -583,6 +624,78 @@
|
|
| 583 |
return "";
|
| 584 |
}
|
| 585 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 586 |
function save(){
|
| 587 |
const company = sanitize(el.company.value);
|
| 588 |
if(!company){
|
|
@@ -599,7 +712,6 @@
|
|
| 599 |
const mobile = normalizeMobile(mobileRaw);
|
| 600 |
const email = el.email ? sanitize(el.email.value) : "";
|
| 601 |
const date = el.date.value || todayISO();
|
| 602 |
-
const signature = el.signature ? sanitize(el.signature.value) : "";
|
| 603 |
const extraNote = sanitize(el.extraNote.value);
|
| 604 |
|
| 605 |
if(email && !isValidEmail(email)){
|
|
@@ -623,7 +735,7 @@
|
|
| 623 |
mobile: status === "RESPONDED" ? mobile : "",
|
| 624 |
email: status === "RESPONDED" ? email : "",
|
| 625 |
date: status === "RESPONDED" ? date : (date || todayISO()),
|
| 626 |
-
signature: status === "RESPONDED" ?
|
| 627 |
note,
|
| 628 |
extraNote,
|
| 629 |
updatedAt: new Date().toISOString()
|
|
@@ -685,7 +797,7 @@
|
|
| 685 |
"رقم الجوال": r.mobile,
|
| 686 |
"البريد الإلكتروني": r.email,
|
| 687 |
"التاريخ": r.date,
|
| 688 |
-
"التوقيع": r.signature,
|
| 689 |
"ملاحظة": (r.note || "") + (r.extraNote ? " | " + r.extraNote : "")
|
| 690 |
}));
|
| 691 |
|
|
@@ -701,10 +813,12 @@
|
|
| 701 |
{ wch: 18 },
|
| 702 |
{ wch: 28 },
|
| 703 |
{ wch: 14 },
|
| 704 |
-
{ wch:
|
| 705 |
{ wch: 42 },
|
| 706 |
];
|
| 707 |
|
|
|
|
|
|
|
| 708 |
const wb = XLSX.utils.book_new();
|
| 709 |
XLSX.utils.book_append_sheet(wb, ws, "الإقرارات");
|
| 710 |
XLSX.writeFile(wb, `EQ_${todayISO()}.xlsx`);
|
|
@@ -736,6 +850,11 @@
|
|
| 736 |
load();
|
| 737 |
updateConditionalUI();
|
| 738 |
render();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 739 |
</script>
|
| 740 |
</body>
|
| 741 |
</html>
|
|
|
|
| 28 |
--shadow: 0 18px 60px rgba(0,0,0,.35);
|
| 29 |
--radius:18px;
|
| 30 |
|
|
|
|
| 31 |
--warn:#f59e0b;
|
| 32 |
--bad:#ef4444;
|
| 33 |
}
|
|
|
|
| 168 |
border-color: rgba(245,158,11,.28);
|
| 169 |
}
|
| 170 |
|
| 171 |
+
/* ====== التوقيع اليدوي ====== */
|
| 172 |
+
.signatureBox{
|
| 173 |
+
width:100%;
|
| 174 |
+
height:180px;
|
| 175 |
+
background:#ffffff;
|
| 176 |
+
border-radius:14px;
|
| 177 |
+
border:2px dashed rgba(0,178,223,.6);
|
| 178 |
+
overflow:hidden;
|
| 179 |
+
position:relative;
|
| 180 |
+
}
|
| 181 |
+
.signatureBox canvas{
|
| 182 |
+
width:100%;
|
| 183 |
+
height:100%;
|
| 184 |
+
display:block;
|
| 185 |
+
touch-action:none;
|
| 186 |
+
}
|
| 187 |
+
.sigActions{
|
| 188 |
+
margin-top:8px;
|
| 189 |
+
text-align:left;
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
.tableWrap{
|
| 193 |
overflow:auto;
|
| 194 |
border-radius: var(--radius);
|
|
|
|
| 255 |
<div class="wrap">
|
| 256 |
<div class="hero">
|
| 257 |
<p class="creditLine">تصميم وإعداد: نوف الناصر</p>
|
| 258 |
+
<p class="titleTop">"بيان استلام"</p>
|
| 259 |
<h1 class="titleBar">إدارة حالات الإقرارات وتوثيق الاستلام</h1>
|
| 260 |
<p class="subNote">
|
| 261 |
أدخل البيانات ثم اختر الحالة. يتم الحفظ تلقائيًا ولا تختفي السجلات عند إغلاق الصفحة إلا بالحذف.
|
|
|
|
| 288 |
</select>
|
| 289 |
</div>
|
| 290 |
|
| 291 |
+
<!-- يظهر فقط عند استجاب -->
|
| 292 |
<div id="respondedBlock" style="grid-column:1/-1; display:none;">
|
| 293 |
<div class="formGrid">
|
| 294 |
<div style="grid-column:1/-1">
|
|
|
|
| 321 |
<input id="date" type="date" />
|
| 322 |
</div>
|
| 323 |
|
| 324 |
+
<div style="grid-column:1/-1">
|
| 325 |
+
<label>التوقيع اليدوي</label>
|
| 326 |
+
<div class="signatureBox">
|
| 327 |
+
<canvas id="signaturePad"></canvas>
|
| 328 |
+
</div>
|
| 329 |
+
<div class="sigActions">
|
| 330 |
+
<button type="button" class="tinyBtn" id="clearSignature">مسح التوقيع</button>
|
| 331 |
+
</div>
|
| 332 |
+
</div>
|
| 333 |
+
</div>
|
|
|
|
| 334 |
|
| 335 |
<div class="noteBox" id="respondedHelp">
|
| 336 |
عند اختيار <b>استجاب</b> يُفضّل تحديد (مركز/فرع مستقل/مفردة)، ثم تُكمل بيانات الاستلام إن توفرت.
|
|
|
|
| 357 |
</div>
|
| 358 |
</div>
|
| 359 |
|
| 360 |
+
<!-- إدارة السجلات -->
|
| 361 |
<div class="card">
|
| 362 |
<h3>إدارة السجلات <span class="badge">بحث + حذف</span></h3>
|
| 363 |
|
|
|
|
| 375 |
</div>
|
| 376 |
</div>
|
| 377 |
|
| 378 |
+
<!-- الجدول -->
|
| 379 |
<div class="card" style="margin-top:14px;">
|
| 380 |
<h3>الجدول</h3>
|
| 381 |
|
|
|
|
| 405 |
</div>
|
| 406 |
|
| 407 |
<script>
|
| 408 |
+
const STORAGE_KEY = "eq_records_v3";
|
| 409 |
|
| 410 |
const el = {
|
| 411 |
company: document.getElementById("company"),
|
|
|
|
| 417 |
mobile: document.getElementById("mobile"),
|
| 418 |
email: document.getElementById("email"),
|
| 419 |
date: document.getElementById("date"),
|
|
|
|
| 420 |
extraNote: document.getElementById("extraNote"),
|
| 421 |
photoNote: document.getElementById("photoNote"),
|
| 422 |
|
|
|
|
| 432 |
deleteAllBtn: document.getElementById("deleteAllBtn"),
|
| 433 |
};
|
| 434 |
|
| 435 |
+
// التوقيع اليدوي
|
| 436 |
+
const canvas = document.getElementById("signaturePad");
|
| 437 |
+
const ctx = canvas.getContext("2d");
|
| 438 |
+
let drawing = false;
|
| 439 |
+
let signatureData = null;
|
| 440 |
+
let scaledOnce = false;
|
| 441 |
+
|
| 442 |
let records = [];
|
| 443 |
let editId = null;
|
| 444 |
|
|
|
|
| 520 |
if(el.receiver) el.receiver.value = "";
|
| 521 |
if(el.mobile) el.mobile.value = "";
|
| 522 |
if(el.email) el.email.value = "";
|
| 523 |
+
clearSignaturePad();
|
| 524 |
}
|
| 525 |
}
|
| 526 |
|
|
|
|
| 533 |
if(el.mobile) el.mobile.value = "";
|
| 534 |
if(el.email) el.email.value = "";
|
| 535 |
el.date.value = todayISO();
|
|
|
|
| 536 |
el.extraNote.value = "";
|
| 537 |
editId = null;
|
| 538 |
el.saveBtn.textContent = "💾 حفظ";
|
| 539 |
+
clearSignaturePad();
|
| 540 |
updateConditionalUI();
|
| 541 |
}
|
| 542 |
|
|
|
|
| 549 |
if(el.mobile) el.mobile.value = rec.mobile || "";
|
| 550 |
if(el.email) el.email.value = rec.email || "";
|
| 551 |
el.date.value = rec.date || todayISO();
|
|
|
|
| 552 |
el.extraNote.value = rec.extraNote || "";
|
| 553 |
editId = rec.id;
|
| 554 |
el.saveBtn.textContent = "✅ حفظ التعديل";
|
| 555 |
updateConditionalUI();
|
| 556 |
+
|
| 557 |
+
// رسم التوقيع المخزن على اللوحة إن وجد
|
| 558 |
+
clearSignaturePad();
|
| 559 |
+
if(rec.signature){
|
| 560 |
+
const img = new Image();
|
| 561 |
+
img.onload = () => {
|
| 562 |
+
const rect = canvas.getBoundingClientRect();
|
| 563 |
+
ctx.drawImage(img, 0, 0, rect.width, rect.height);
|
| 564 |
+
signatureData = rec.signature;
|
| 565 |
+
};
|
| 566 |
+
img.src = rec.signature;
|
| 567 |
+
}
|
| 568 |
+
|
| 569 |
window.scrollTo({ top: 0, behavior: "smooth" });
|
| 570 |
}
|
| 571 |
|
|
|
|
| 575 |
return records.filter(r => {
|
| 576 |
const hay = [
|
| 577 |
r.company, r.cr, statusLabel(r.status), respondedTypeLabel(r.respondedType),
|
| 578 |
+
r.receiver, r.mobile, r.email, r.date, r.note, r.extraNote
|
| 579 |
].join(" ").toLowerCase();
|
| 580 |
return hay.includes(q);
|
| 581 |
});
|
|
|
|
| 598 |
<td>${escapeHtml(r.mobile)}</td>
|
| 599 |
<td>${escapeHtml(r.email)}</td>
|
| 600 |
<td>${escapeHtml(r.date)}</td>
|
| 601 |
+
<td>${r.signature ? `<img src="${r.signature}" style="height:50px; background:#fff; border-radius:8px; padding:2px;">` : ""}</td>
|
| 602 |
<td>${escapeHtml(r.note || "")}${r.extraNote ? " | " + escapeHtml(r.extraNote) : ""}</td>
|
| 603 |
<td>
|
| 604 |
<button class="tinyBtn edit" data-action="edit" data-id="${r.id}">تعديل</button>
|
|
|
|
| 624 |
return "";
|
| 625 |
}
|
| 626 |
|
| 627 |
+
/* ====== التوقيع اليدوي (Canvas) ====== */
|
| 628 |
+
function resizeCanvas(){
|
| 629 |
+
const ratio = window.devicePixelRatio || 1;
|
| 630 |
+
const rect = canvas.getBoundingClientRect();
|
| 631 |
+
|
| 632 |
+
const oldData = signatureData;
|
| 633 |
+
|
| 634 |
+
canvas.width = Math.max(1, Math.floor(rect.width * ratio));
|
| 635 |
+
canvas.height = Math.max(1, Math.floor(rect.height * ratio));
|
| 636 |
+
|
| 637 |
+
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
|
| 638 |
+
ctx.lineWidth = 2;
|
| 639 |
+
ctx.lineCap = "round";
|
| 640 |
+
ctx.strokeStyle = "#000";
|
| 641 |
+
|
| 642 |
+
// إعادة رسم التوقيع إذا كان موجودًا (عند تغيير المقاس)
|
| 643 |
+
if(oldData){
|
| 644 |
+
const img = new Image();
|
| 645 |
+
img.onload = () => {
|
| 646 |
+
ctx.drawImage(img, 0, 0, rect.width, rect.height);
|
| 647 |
+
signatureData = oldData;
|
| 648 |
+
};
|
| 649 |
+
img.src = oldData;
|
| 650 |
+
}
|
| 651 |
+
}
|
| 652 |
+
|
| 653 |
+
function clearSignaturePad(){
|
| 654 |
+
const rect = canvas.getBoundingClientRect();
|
| 655 |
+
ctx.clearRect(0, 0, rect.width, rect.height);
|
| 656 |
+
signatureData = null;
|
| 657 |
+
}
|
| 658 |
+
|
| 659 |
+
function getPos(e){
|
| 660 |
+
const rect = canvas.getBoundingClientRect();
|
| 661 |
+
if(e.touches && e.touches[0]){
|
| 662 |
+
return { x: e.touches[0].clientX - rect.left, y: e.touches[0].clientY - rect.top };
|
| 663 |
+
}
|
| 664 |
+
return { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
| 665 |
+
}
|
| 666 |
+
|
| 667 |
+
function startDraw(e){
|
| 668 |
+
drawing = true;
|
| 669 |
+
const p = getPos(e);
|
| 670 |
+
ctx.beginPath();
|
| 671 |
+
ctx.moveTo(p.x, p.y);
|
| 672 |
+
}
|
| 673 |
+
|
| 674 |
+
function draw(e){
|
| 675 |
+
if(!drawing) return;
|
| 676 |
+
e.preventDefault();
|
| 677 |
+
const p = getPos(e);
|
| 678 |
+
ctx.lineTo(p.x, p.y);
|
| 679 |
+
ctx.stroke();
|
| 680 |
+
}
|
| 681 |
+
|
| 682 |
+
function endDraw(){
|
| 683 |
+
if(!drawing) return;
|
| 684 |
+
drawing = false;
|
| 685 |
+
signatureData = canvas.toDataURL("image/png");
|
| 686 |
+
}
|
| 687 |
+
|
| 688 |
+
canvas.addEventListener("mousedown", startDraw);
|
| 689 |
+
canvas.addEventListener("mousemove", draw);
|
| 690 |
+
canvas.addEventListener("mouseup", endDraw);
|
| 691 |
+
canvas.addEventListener("mouseleave", endDraw);
|
| 692 |
+
|
| 693 |
+
canvas.addEventListener("touchstart", startDraw, { passive:false });
|
| 694 |
+
canvas.addEventListener("touchmove", draw, { passive:false });
|
| 695 |
+
canvas.addEventListener("touchend", endDraw);
|
| 696 |
+
|
| 697 |
+
document.getElementById("clearSignature").addEventListener("click", clearSignaturePad);
|
| 698 |
+
|
| 699 |
function save(){
|
| 700 |
const company = sanitize(el.company.value);
|
| 701 |
if(!company){
|
|
|
|
| 712 |
const mobile = normalizeMobile(mobileRaw);
|
| 713 |
const email = el.email ? sanitize(el.email.value) : "";
|
| 714 |
const date = el.date.value || todayISO();
|
|
|
|
| 715 |
const extraNote = sanitize(el.extraNote.value);
|
| 716 |
|
| 717 |
if(email && !isValidEmail(email)){
|
|
|
|
| 735 |
mobile: status === "RESPONDED" ? mobile : "",
|
| 736 |
email: status === "RESPONDED" ? email : "",
|
| 737 |
date: status === "RESPONDED" ? date : (date || todayISO()),
|
| 738 |
+
signature: (status === "RESPONDED") ? (signatureData || "") : "",
|
| 739 |
note,
|
| 740 |
extraNote,
|
| 741 |
updatedAt: new Date().toISOString()
|
|
|
|
| 797 |
"رقم الجوال": r.mobile,
|
| 798 |
"البريد الإلكتروني": r.email,
|
| 799 |
"التاريخ": r.date,
|
| 800 |
+
"التوقيع": r.signature ? "مرفق (صورة)" : "",
|
| 801 |
"ملاحظة": (r.note || "") + (r.extraNote ? " | " + r.extraNote : "")
|
| 802 |
}));
|
| 803 |
|
|
|
|
| 813 |
{ wch: 18 },
|
| 814 |
{ wch: 28 },
|
| 815 |
{ wch: 14 },
|
| 816 |
+
{ wch: 14 },
|
| 817 |
{ wch: 42 },
|
| 818 |
];
|
| 819 |
|
| 820 |
+
// ملاحظة: Excel عبر SheetJS لا يدعم إدراج الصور في الخلايا كصورة مباشرة في المتصفح بدون حلول إضافية.
|
| 821 |
+
// لذا نضع مؤشر "مرفق (صورة)" داخل Excel، بينما التوقيع يظهر كصورة داخل الصفحة.
|
| 822 |
const wb = XLSX.utils.book_new();
|
| 823 |
XLSX.utils.book_append_sheet(wb, ws, "الإقرارات");
|
| 824 |
XLSX.writeFile(wb, `EQ_${todayISO()}.xlsx`);
|
|
|
|
| 850 |
load();
|
| 851 |
updateConditionalUI();
|
| 852 |
render();
|
| 853 |
+
|
| 854 |
+
// تجهيز لوحة التوقيع بعد ظهورها (وعند تحميل الصفحة)
|
| 855 |
+
// نعمل resize الآن، وأيضًا عند تغيير الحجم
|
| 856 |
+
setTimeout(() => { resizeCanvas(); }, 0);
|
| 857 |
+
window.addEventListener("resize", () => { resizeCanvas(); });
|
| 858 |
</script>
|
| 859 |
</body>
|
| 860 |
</html>
|