stat2025 commited on
Commit
96512b4
·
verified ·
1 Parent(s): 41ab682

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +107 -13
app.js CHANGED
@@ -1,5 +1,7 @@
1
  /* ========= منطق التحليل والتصدير والنسخ (Static فقط) ========= */
 
2
  const EXPORT_COLUMNS = [
 
3
  "نوع المشكلة","وقت حدوث المشكلة","اسم صاحب المشكلة",
4
  "رقم الهوية","رقم الجهاز","رقم الجوال","المسح","المنطقة"
5
  ];
@@ -17,9 +19,70 @@ const FIELD_ALIASES = {
17
 
18
  const LABEL_SEP = "(?::|:)?\\s*";
19
  const TICKET_SEP = /\n\s*(?:\n|—+|-{3,}|={3,}|🔴+)+\s*\n/;
20
-
21
  const arabicDigitsMap = {"٠":"0","١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9"};
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  function normalizeText(s){
24
  if(typeof s!=="string") return "";
25
  return s.replace(/[\u200f\u200e\u202a-\u202e\u2066-\u2069\u00a0]/g," ")
@@ -39,19 +102,16 @@ function normalizeTime(val){
39
  }
40
  function normalizeDate(v){
41
  v=(v||"").trim();
42
- // 1) 21/8/2025 أو 21-08-25
43
  let m=v.match(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2,4})/);
44
  if(m){
45
  let d=+m[1], mo=+m[2], y=+m[3]; if(y<100) y+=2000;
46
  return `${y.toString().padStart(4,"0")}-${String(mo).padStart(2,"0")}-${String(d).padStart(2,"0")}`;
47
  }
48
- // 2) 2025/08/21
49
  m=v.match(/(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})/);
50
  if(m){
51
  let y=+m[1], mo=+m[2], d=+m[3];
52
  return `${y.toString().padStart(4,"0")}-${String(mo).padStart(2,"0")}-${String(d).padStart(2,"0")}`;
53
  }
54
- // 3) 21 أغسطس 2025 / 21 آب 2025
55
  const months = {
56
  "يناير":1,"فبراير":2,"مارس":3,"أبريل":4,"ابريل":4,"مايو":5,"يونيو":6,"يوليو":7,"أغسطس":8,"اغسطس":8,"سبتمبر":9,"أكتوبر":10,"اكتوبر":10,"نوفمبر":11,"ديسمبر":12,
57
  "كانون الثاني":1,"شباط":2,"آذار":3,"نيسان":4,"أيار":5,"حزيران":6,"تموز":7,"آب":8,"أيلول":9,"تشرين الأول":10,"تشرين الثاني":11,"كانون الأول":12
@@ -65,6 +125,8 @@ function normalizeDate(v){
65
  }
66
  return v;
67
  }
 
 
68
  function splitTickets(raw){
69
  raw = normalizeText(raw);
70
  if(!raw) return [];
@@ -125,8 +187,32 @@ function extractFields(ticketText){
125
  }
126
  return data;
127
  }
128
- function parseTickets(raw){ return splitTickets(raw||"").map(extractFields); }
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  function buildTable(rows){
131
  const theadRow = document.getElementById("theadRow");
132
  const tbody = document.getElementById("tbody");
@@ -148,8 +234,6 @@ function buildTable(rows){
148
  tbody.appendChild(tr);
149
  });
150
  }
151
-
152
- /* قراءة الجدول */
153
  function readTable(){
154
  const tbody = document.getElementById("tbody");
155
  const rows = [];
@@ -293,7 +377,19 @@ const SAMPLE = `نوع المشكلة : لا استطيع اكمال الاست
293
  المنطقة: الشرقية`;
294
 
295
  /* ================= حفظ واسترجاع الحالة ================= */
296
- const STATE_KEY = "ticketParserState_v1";
 
 
 
 
 
 
 
 
 
 
 
 
297
  function saveState(){
298
  try{
299
  const raw = document.getElementById("raw")?.value || "";
@@ -307,9 +403,10 @@ function loadState(){
307
  try{
308
  const s = localStorage.getItem(STATE_KEY);
309
  if(!s) return false;
310
- const { raw, fname, rows } = JSON.parse(s);
311
  if(typeof raw === "string"){ const el=document.getElementById("raw"); if(el) el.value = raw; }
312
  if(typeof fname === "string"){ const el=document.getElementById("fname"); if(el) el.value = fname; }
 
313
  if(Array.isArray(rows) && rows.length){
314
  buildTable(rows);
315
  validateCells();
@@ -343,7 +440,7 @@ function init(){
343
  const rawEl = document.getElementById("raw");
344
  const fnameEl = document.getElementById("fname");
345
 
346
- // استرجاع الحالة المخزنة (لا نمسح شيئًا عند الدخول)
347
  loadState();
348
 
349
  parseBtn.addEventListener("click", ()=>{
@@ -371,9 +468,6 @@ function init(){
371
  rawEl.addEventListener("input", saveState);
372
  fnameEl.addEventListener("input", saveState);
373
 
374
- // لا نضيف أي مسح عند الخروج/الإغلاق — تلبية لطلبك
375
- // (أزلنا pagehide / beforeunload / visibilitychange)
376
-
377
  // اختصارات لوحة المفاتيح
378
  document.addEventListener("keydown", (e)=>{
379
  const ctrl = e.ctrlKey || e.metaKey;
 
1
  /* ========= منطق التحليل والتصدير والنسخ (Static فقط) ========= */
2
+ /* تمت إضافة عمود "التصنيف" + قواعد تصنيف بالكلمات المفتاحية */
3
  const EXPORT_COLUMNS = [
4
+ "التصنيف", // جديد: أول عمود
5
  "نوع المشكلة","وقت حدوث المشكلة","اسم صاحب المشكلة",
6
  "رقم الهوية","رقم الجهاز","رقم الجوال","المسح","المنطقة"
7
  ];
 
19
 
20
  const LABEL_SEP = "(?::|:)?\\s*";
21
  const TICKET_SEP = /\n\s*(?:\n|—+|-{3,}|={3,}|🔴+)+\s*\n/;
 
22
  const arabicDigitsMap = {"٠":"0","١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9"};
23
 
24
+ /* ===== قواعد التصنيف بالكلمات المفتاحية =====
25
+ نبحث في نص التذكرة و"نوع المشكلة" ونرجّع أول تصنيف مطابق بالترتيب */
26
+ const CLASS_RULES = {
27
+ "استفسار": [
28
+ "استفسار","سؤال","استعلام","معلومة","استفسارات"
29
+ ],
30
+ "إضافة أجهزة": [
31
+ "اضافة جهاز","إضافة أجهزة","اضافة اجهزة","تركيب جهاز","جهاز جديد","تسجيل جهاز","ربط جهاز","اضافة ماسح","إضافة ماسح"
32
+ ],
33
+ "الاستمارة": [
34
+ "الاستمارة","استمارة","النموذج","نموذج","الفورم","تعليق الاستمارة","لا استطيع اكمال الاستمارة","التعبئة"
35
+ ],
36
+ "التقييم": [
37
+ "التقييم","تقييم","feedback","survey","رضا","نجوم"
38
+ ],
39
+ "الخرائط": [
40
+ "الخرائط","خرائط","map","gps","تحديد الموقع","احداثيات","إحداثيات","الموقع الجغرافي"
41
+ ],
42
+ "السوتي": [
43
+ "السوتي","سوتي","soti","soti assist","mobicontrol","soti mobicontrol"
44
+ ],
45
+ "الشبكة": [
46
+ "الشبكة","شبكة","نت","انترنت","إنترنت","wifi","واي فاي","4g","5g","ضعف الشبكة","stc","mobily","زين","weak signal","no signal"
47
+ ],
48
+ "النسخة": [
49
+ "النسخة","نسخة","الإصدار","اصدار","version","build","release","تحديث نسخة","ترقية النسخة"
50
+ ],
51
+ "النظام المكتبي": [
52
+ "النظام المكتبي","نسخة ويندوز","ويندوز","windows","pc app","برنامج المكتب","التطبيق على الكمبيوتر","الديسكتوب"
53
+ ],
54
+ "تسجيل دخول": [
55
+ "تسجيل دخول","تسجيل الدخول","login","signin","رفض تسجيل الدخول","لا يقبل الدخول","اسم المستخدم","كلمة المرور","نسيت كلمة السر","إعادة تعيين"
56
+ ],
57
+ "تفعيل حساب": [
58
+ "تفعيل حساب","تفعيل","activation","activate","رمز التفعيل","كود التفعيل"
59
+ ],
60
+ "تناقل البيانات": [
61
+ "تناقل البيانات","ترحيل البيانات","مزامنة","sync","مزامنه","نقل البيانات","رفع البيانات","sync failed","المزامنة"
62
+ ],
63
+ "صيانة وتحديث الأجهزة": [
64
+ "صيانة","تحديث الأجهزة","تحديث جهاز","ترقية الجهاز","اعطال الجهاز","تصليح","صيانة وتحديث الأجهزة","صيانة الجهاز"
65
+ ],
66
+ };
67
+
68
+ /* ترتيب الأفضلية عند تعدد التطابقات */
69
+ const CLASS_PRIORITY = [
70
+ "صيانة وتحديث الأجهزة",
71
+ "إضافة أجهزة",
72
+ "تسجيل دخول",
73
+ "تفعيل حساب",
74
+ "الاستمارة",
75
+ "التقييم",
76
+ "الخرائط",
77
+ "السوتي",
78
+ "الشبكة",
79
+ "النسخة",
80
+ "النظام المكتبي",
81
+ "تناقل البيانات",
82
+ "استفسار",
83
+ ];
84
+
85
+ /* ================= أساسيات النص ================= */
86
  function normalizeText(s){
87
  if(typeof s!=="string") return "";
88
  return s.replace(/[\u200f\u200e\u202a-\u202e\u2066-\u2069\u00a0]/g," ")
 
102
  }
103
  function normalizeDate(v){
104
  v=(v||"").trim();
 
105
  let m=v.match(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2,4})/);
106
  if(m){
107
  let d=+m[1], mo=+m[2], y=+m[3]; if(y<100) y+=2000;
108
  return `${y.toString().padStart(4,"0")}-${String(mo).padStart(2,"0")}-${String(d).padStart(2,"0")}`;
109
  }
 
110
  m=v.match(/(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})/);
111
  if(m){
112
  let y=+m[1], mo=+m[2], d=+m[3];
113
  return `${y.toString().padStart(4,"0")}-${String(mo).padStart(2,"0")}-${String(d).padStart(2,"0")}`;
114
  }
 
115
  const months = {
116
  "يناير":1,"فبراير":2,"مارس":3,"أبريل":4,"ابريل":4,"مايو":5,"يونيو":6,"يوليو":7,"أغسطس":8,"اغسطس":8,"سبتمبر":9,"أكتوبر":10,"اكتوبر":10,"نوفمبر":11,"ديسمبر":12,
117
  "كانون الثاني":1,"شباط":2,"آذار":3,"نيسان":4,"أيار":5,"حزيران":6,"تموز":7,"آب":8,"أيلول":9,"تشرين الأول":10,"تشرين الثاني":11,"كانون الأول":12
 
125
  }
126
  return v;
127
  }
128
+
129
+ /* ================= تقسيم/استخراج الحقول ================= */
130
  function splitTickets(raw){
131
  raw = normalizeText(raw);
132
  if(!raw) return [];
 
187
  }
188
  return data;
189
  }
 
190
 
191
+ /* ================= التصنيف ================= */
192
+ function classifyTicket(text, fields){
193
+ const hay = normalizeText(`${text}\n${fields?.["نوع المشكلة"]||""}`).toLowerCase();
194
+ // نجرب حسب ترتيب الأفضلية
195
+ for(const label of CLASS_PRIORITY){
196
+ const kws = CLASS_RULES[label] || [];
197
+ for(const kw of kws){
198
+ if(!kw) continue;
199
+ const needle = normalizeText(kw).toLowerCase();
200
+ if(needle && hay.includes(needle)) return label;
201
+ }
202
+ }
203
+ return "استفسار"; // افتراضي لطيف إذا لم يُعرف
204
+ }
205
+
206
+ /* نبني الصفوف مع "التصنيف" */
207
+ function parseTickets(raw){
208
+ return splitTickets(raw||"").map(t => {
209
+ const f = extractFields(t);
210
+ const cls = classifyTicket(t, f);
211
+ return { "التصنيف": cls, ...f };
212
+ });
213
+ }
214
+
215
+ /* ================= بناء الجدول/القراءة ================= */
216
  function buildTable(rows){
217
  const theadRow = document.getElementById("theadRow");
218
  const tbody = document.getElementById("tbody");
 
234
  tbody.appendChild(tr);
235
  });
236
  }
 
 
237
  function readTable(){
238
  const tbody = document.getElementById("tbody");
239
  const rows = [];
 
377
  المنطقة: الشرقية`;
378
 
379
  /* ================= حفظ واسترجاع الحالة ================= */
380
+ const STATE_KEY = "ticketParserState_v2"; // رفعنا النسخة لأننا أضفنا "التصنيف"
381
+ function ensureClassification(rows){
382
+ if(!Array.isArray(rows)) return rows||[];
383
+ return rows.map(r=>{
384
+ if(!r) return r;
385
+ if(!("التصنيف" in r) || !r["التصنيف"]){
386
+ const fakeText = Object.values(r).join("\n");
387
+ const cls = classifyTicket(fakeText, r);
388
+ return { "التصنيف": cls, ...r };
389
+ }
390
+ return r;
391
+ });
392
+ }
393
  function saveState(){
394
  try{
395
  const raw = document.getElementById("raw")?.value || "";
 
403
  try{
404
  const s = localStorage.getItem(STATE_KEY);
405
  if(!s) return false;
406
+ let { raw, fname, rows } = JSON.parse(s);
407
  if(typeof raw === "string"){ const el=document.getElementById("raw"); if(el) el.value = raw; }
408
  if(typeof fname === "string"){ const el=document.getElementById("fname"); if(el) el.value = fname; }
409
+ rows = ensureClassification(rows);
410
  if(Array.isArray(rows) && rows.length){
411
  buildTable(rows);
412
  validateCells();
 
440
  const rawEl = document.getElementById("raw");
441
  const fnameEl = document.getElementById("fname");
442
 
443
+ // استرجاع الحالة المخزنة
444
  loadState();
445
 
446
  parseBtn.addEventListener("click", ()=>{
 
468
  rawEl.addEventListener("input", saveState);
469
  fnameEl.addEventListener("input", saveState);
470
 
 
 
 
471
  // اختصارات لوحة المفاتيح
472
  document.addEventListener("keydown", (e)=>{
473
  const ctrl = e.ctrlKey || e.metaKey;