stat2025 commited on
Commit
5048956
·
verified ·
1 Parent(s): f9ac708

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +30 -18
app.js CHANGED
@@ -64,7 +64,7 @@ const LABEL_FIXES = [
64
  [/(^|\n)\s*اسم\s*المنطقة/gi, "$1المنطقة"],
65
  [/(^|\n)\s*اسم\s*المسح/gi, "$1المسح"],
66
  [/(^|\n)\s*الهاتف/gi, "$1رقم الجوال"],
67
- [/(^|\n)\س*جوال/gi, "$1رقم الجوال"]
68
  ];
69
  function fixLabels(s){
70
  let t = s;
@@ -72,6 +72,7 @@ function fixLabels(s){
72
  return t;
73
  }
74
 
 
75
  const H_MONTHS = ["محرم","صفر","ربيع الأول","ربيع الاول","ربيع الآخر","ربيع الاخر","جمادى الأولى","جمادى الاولى","جمادى الآخرة","جمادى الاخرة","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو القعده","ذو الحجة","ذو الحجه"];
76
  function monthIndexHijri(name){
77
  const i = H_MONTHS.findIndex(m => new RegExp("^"+m+"$", "i").test(name.trim()));
@@ -101,31 +102,41 @@ function detectHijriDate(str){
101
  if(m) return {hy:+m[3], hm:+m[2], hd:+m[1]};
102
  return null;
103
  }
 
 
104
  function normalizeDateOnly(raw){
105
  const t = normalizeText(raw);
106
  const hj = detectHijriDate(t);
107
- const hasGreg1 = /(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2,4})/.test(t);
108
- const hasGreg2 = /(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})/.test(t);
109
- const timeOnly1 = /(^|\s)\d{1,2}\s*(?:[:٫\.:\-]\d{2})\s*(?:ص|صباح(?:اً|ا)?|am|م|مساء|pm)?($|\s)/i.test(t);
110
  const timeOnly2 = /(^|\s)\d{1,2}\s*(?:ص|صباح(?:اً|ا)?|am|م|مساء|pm)($|\s)/i.test(t);
111
- if((timeOnly1||timeOnly2) && !hasGreg1 && !hasGreg2 && !hj) return "";
 
112
  if(hj){
113
  const [gy,gm,gd] = hijriToGregorian(hj.hy, hj.hm, hj.hd);
114
- return `${gy.toString().padStart(4,"0")}-${String(gm).padStart(2,"0")}-${String(gd).toString().padStart(2,"0")}`;
115
  }
116
- let m = t.match(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2,4})/);
117
- if(m){
118
- let d=+m[1], mo=+m[2], y=+m[3];
119
- if(y<100) y+=2000;
120
- return `${y.toString().padStart(4,"0")}-${String(mo).padStart(2,"0")}-${String(d).toString().padStart(2,"0")}`;
121
- }
122
- m = t.match(/(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})/);
123
  if(m){
124
- let y=+m[1], mo=+m[2], d=+m[3];
125
- return `${y.toString().padStart(4,"0")}-${String(mo).padStart(2,"0")}-${String(d).toString().padStart(2,"0")}`;
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
  return t;
128
  }
 
129
 
130
  function findStartsByLabels(text, labels){
131
  const lblRe = labels.map(l=>l.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')).join("|");
@@ -151,7 +162,7 @@ function findBlockAfterLabel(text, labels, allLabels = START_LABELS){
151
  const lblAlt = labels.map(esc).join("|");
152
  const allAlt = allLabels.map(esc).join("|");
153
  const re = new RegExp(
154
- `(?:^|\\n)\\s*(?:${lblAlt})\\s*(?::|:|\\s)\\s*([\\س\\S]*?)(?=\\n\\s*(?:${allAlt})\\s*(?::|:|\\s)|$)`,
155
  "i"
156
  );
157
  const m = hay.match(re);
@@ -188,7 +199,9 @@ function extractFields(ticketText){
188
  "رقم الهوية":"", "رقم الجهاز":"", "رقم الجوال":"", "المسح":"", "المنطقة":""
189
  };
190
 
 
191
  let v = findBlockAfterLabel(text, FIELD_ALIASES["نوع المشكلة"], START_LABELS);
 
192
  if(v) out["نوع المشكلة"] = normalizeText(v);
193
 
194
  v = findAfterLabel(text, FIELD_ALIASES["وقت حدوث المشكلة"]);
@@ -375,7 +388,7 @@ function toast(msg){
375
  setTimeout(()=>{ t.hidden = true; }, 2000);
376
  }
377
 
378
- /* === التعديل المطلوب فقط: تصدير التاريخ من "وقت حدوث المشكلة" بدلاً من تاريخ اليوم === */
379
  async function exportExcel(){
380
  const rows = readTable();
381
  if(!rows.length){ toast("لا يوجد بيانات لتصديرها."); return; }
@@ -457,7 +470,6 @@ async function exportExcel(){
457
  setTimeout(()=>URL.revokeObjectURL(url),1000);
458
  toast("تم تنزيل الملف بتنسيق القالب.");
459
  }
460
- /* === نهاية التعديل === */
461
 
462
  async function copyToClipboardTSV(){
463
  const rows = readTable();
 
64
  [/(^|\n)\s*اسم\s*المنطقة/gi, "$1المنطقة"],
65
  [/(^|\n)\s*اسم\s*المسح/gi, "$1المسح"],
66
  [/(^|\n)\s*الهاتف/gi, "$1رقم الجوال"],
67
+ [/(^|\n)\s*جوال/gi, "$1رقم الجوال"]
68
  ];
69
  function fixLabels(s){
70
  let t = s;
 
72
  return t;
73
  }
74
 
75
+ /* ==== تحويل/التقاط التاريخ ==== */
76
  const H_MONTHS = ["محرم","صفر","ربيع الأول","ربيع الاول","ربيع الآخر","ربيع الاخر","جمادى الأولى","جمادى الاولى","جمادى الآخرة","جمادى الاخرة","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو القعده","ذو الحجة","ذو الحجه"];
77
  function monthIndexHijri(name){
78
  const i = H_MONTHS.findIndex(m => new RegExp("^"+m+"$", "i").test(name.trim()));
 
102
  if(m) return {hy:+m[3], hm:+m[2], hd:+m[1]};
103
  return null;
104
  }
105
+
106
+ /* ✅ تُحافظ على YYYY/MM/DD وتدعم DD/MM/YYYY وتترك “الوقت فقط” فارغ */
107
  function normalizeDateOnly(raw){
108
  const t = normalizeText(raw);
109
  const hj = detectHijriDate(t);
110
+
111
+ const timeOnly1 = /(^|\s)\d{1,2}\s*(?:[:٫\.\-]\d{2})\s*(?:ص|صباح(?:اً|ا)?|am|م|مساء|pm)?($|\s)/i.test(t);
 
112
  const timeOnly2 = /(^|\s)\d{1,2}\s*(?:ص|صباح(?:اً|ا)?|am|م|مساء|pm)($|\s)/i.test(t);
113
+ if((timeOnly1||timeOnly2) && !hj && !/(\d{3,4}).(\d{1,2}).(\d{1,2})/.test(t)) return "";
114
+
115
  if(hj){
116
  const [gy,gm,gd] = hijriToGregorian(hj.hy, hj.hm, hj.hd);
117
+ return `${String(gy).padStart(4,"0")}-${String(gm).padStart(2,"0")}-${String(gd).padStart(2,"0")}`;
118
  }
119
+
120
+ const m = t.match(/(\d{1,4})[\/\-](\d{1,2})[\/\-](\d{1,4})/);
 
 
 
 
 
121
  if(m){
122
+ const a=m[1], b=m[2], c=m[3];
123
+ let A=+a, B=+b, C=+c;
124
+ let y, mo, d;
125
+
126
+ if(a.length===4){ y=A; mo=B; d=C; } // YYYY/MM/DD
127
+ else if(c.length===4){ y=C; mo=B; d=A; } // DD/MM/YYYY
128
+ else {
129
+ if(A>31){ y=A; mo=B; d=C; } // YY/MM/DD أو YYYY/MM/DD مختصر
130
+ else if(C>31){ y=C; mo=B; d=A; } // DD/MM/YY
131
+ else { y=C; mo=B; d=A; } // افتراضيًا DD/MM/YY
132
+ }
133
+ if(y<100) y += 2000;
134
+ if(mo>12 && d<=12){ const tmp=mo; mo=d; d=tmp; } // إصلاح لو حدث قلب
135
+ return `${String(y).padStart(4,"0")}-${String(mo).padStart(2,"0")}-${String(d).padStart(2,"0")}`;
136
  }
137
  return t;
138
  }
139
+ /* ==== نهاية التاريخ ==== */
140
 
141
  function findStartsByLabels(text, labels){
142
  const lblRe = labels.map(l=>l.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')).join("|");
 
162
  const lblAlt = labels.map(esc).join("|");
163
  const allAlt = allLabels.map(esc).join("|");
164
  const re = new RegExp(
165
+ `(?:^|\\n)\\s*(?:${lblAlt})\\s*(?::|:|\\s)\\s*([\\s\\S]*?)(?=\\n\\s*(?:${allAlt})\\s*(?::|:|\\s)|$)`,
166
  "i"
167
  );
168
  const m = hay.match(re);
 
199
  "رقم الهوية":"", "رقم الجهاز":"", "رقم الجوال":"", "المسح":"", "المنطقة":""
200
  };
201
 
202
+ // ✅ أولاً نحاول كتلة متعددة الأسطر، وإن فشلت نأخذ السطر الأول بعد الوسم
203
  let v = findBlockAfterLabel(text, FIELD_ALIASES["نوع المشكلة"], START_LABELS);
204
+ if(!v) v = findAfterLabel(text, FIELD_ALIASES["نوع المشكلة"]);
205
  if(v) out["نوع المشكلة"] = normalizeText(v);
206
 
207
  v = findAfterLabel(text, FIELD_ALIASES["وقت حدوث المشكلة"]);
 
388
  setTimeout(()=>{ t.hidden = true; }, 2000);
389
  }
390
 
391
+ /* التصدير يستخدم نفس تاريخ "وقت حدوث المشكلة" */
392
  async function exportExcel(){
393
  const rows = readTable();
394
  if(!rows.length){ toast("لا يوجد بيانات لتصديرها."); return; }
 
470
  setTimeout(()=>URL.revokeObjectURL(url),1000);
471
  toast("تم تنزيل الملف بتنسيق القالب.");
472
  }
 
473
 
474
  async function copyToClipboardTSV(){
475
  const rows = readTable();