const ACCESS_PASSWORDS=["12345","2030"]; const EXPORT_COLUMNS=[ "التصنيف","نوع المشكلة","وقت حدوث المشكلة","اسم صاحب المشكلة", "رقم الهوية","رقم الجهاز","رقم الجوال","المسح","المنطقة","اسم الدعم الفني","الحالة" ]; const DISPLAY_COLUMNS=[ "التصنيف","نوع المشكلة","المنطقة","اسم المسح","اسم المشتغل", "رقم الجوال","رقم الهوية ID","رقم الجهاز","تاريخ اليوم بالميلادي","الحالة","اسم الدعم الفني" ]; const DISPLAY_TO_BASE={ "التصنيف":"التصنيف", "نوع المشكلة":"نوع المشكلة", "المنطقة":"المنطقة", "اسم المسح":"المسح", "اسم المشتغل":"اسم صاحب المشكلة", "رقم الجوال":"رقم الجوال", "رقم الهوية ID":"رقم الهوية", "رقم الجهاز":"رقم الجهاز", "تاريخ اليوم بالميلادي":"تاريخ اليوم بالميلادي", "الحالة":"الحالة", "اسم الدعم الفني":"اسم الدعم الفني" }; const FIELD_ALIASES={ "نوع المشكلة":["نوع المشكله","نوع المشكلة","المشكلة","نوع-المشكلة","نوع المشكلة"], "وقت حدوث المشكلة":["وقت حدوث المشكله","وقت حدوث المشكلة","وقت المشكلة","وقت حدوث","وقت حدوث المشكله:","وقت حدوث المشكله :"], "اسم صاحب المشكلة":["اسم صاحب المشكله","اسم صاحب المشكلة","اسم صاحب البلاغ","الاسم"], "رقم الهوية":["رقم الهويه","رقم الهوية","الهوية","هوية"], "رقم الجهاز":["رقم الجهاز","الجهاز"], "رقم الجوال":["رقم الجوال","الجوال","الهاتف","جوال"], "المسح":["المسح","اسم المسح"], "المنطقة":["المنطقة","المنطقه","اسم المنطقة","المدينة","المحافظة","منطقة"] }; const START_LABELS=Array.from(new Set(Object.values(FIELD_ALIASES).flat())); const CLASS_RULES={ "استفسار":["استفسار","سؤال","استعلام","معلومة","استفسارات"], "إضافة أجهزة":["اضافة جهاز","إضافة أجهزة","اضافة اجهزة","تركيب جهاز","جهاز جديد","تسجيل جهاز","ربط جهاز","اضافة ماسح","إضافة ماسح"], "الاستمارة":["الاستمارة","استمارة","النموذج","نموذج","الفورم","تعليق الاستمارة","لا استطيع اكمال الاستمارة","التعبئة"], "التقييم":["التقييم","تقييم","feedback","survey","رضا","نجوم"], "الخرائط":["الخرائط","خرائط","map","gps","تحديد الموقع","احداثيات","إحداثيات","الموقع الجغرافي"], "السوتي":["السوتي","سوتي","soti","soti assist","mobicontrol","soti mobicontrol"], "الشبكة":["الشبكة","شبكة","نت","انترنت","إنترنت","wifi","واي فاي","4g","5g","ضعف الشبكة","stc","mobily","زين","weak signal","no signal"], "النسخة":["النسخة","نسخة","الإصدار","اصدار","version","build","release","تحديث نسخة","ترقية النسخة"], "النظام المكتبي":["النظام المكتبي","نسخة ويندوز","ويندوز","windows","pc app","برنامج المكتب","التطبيق على الكمبيوتر","الديسكتوب"], "تسجيل دخول":["تسجيل دخول","تسجيل الدخول","login","signin","رفض تسجيل الدخول","لا يقبل الدخول","اسم المستخدم","كلمة المرور","نسيت كلمة السر","إعادة تعيين"], "تفعيل حساب":["تفعيل حساب","تفعيل","activation","activate","رمز التفعيل","كود التفعيل"], "تناقل البيانات":["تناقل البيانات","ترحيل البيانات","مزامنة","sync","مزامنه","نقل البيانات","رفع البيانات","sync failed","المزامنة"], "صيانة وتحديث الأجهزة":["صيانة","تحديث الأجهزة","تحديث جهاز","ترقية الجهاز","اعطال الجهاز","تصليح","صيانة وتحديث الأجهزة","صيانة الجهاز"] }; const CLASS_PRIORITY=[ "صيانة وتحديث الأجهزة","إضافة أجهزة","تسجيل دخول","تفعيل حساب","الاستمارة","التقييم", "الخرائط","السوتي","الشبكة","النسخة","النظام المكتبي","تناقل البيانات","استفسار" ]; const TICKET_SEP=/\n\s*(?:\n{2,}|—+|-{3,}|={3,}|🔴+)\s*\n/; const arabicDigitsMap={"٠":"0","١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9"}; function normalizeText(s){ if(typeof s!=="string")return""; return s.replace(/\r\n/g,"\n") .replace(/[\u200f\u200e\u202a-\u202e\u2066-\u2069\u00a0]/g," ") .replace(/[٠-٩]/g,d=>arabicDigitsMap[d]) .replace(/[ــ]+/g,"") .replace(/[ \t]+\n/g,"\n") .replace(/\n{3,}/g,"\n\n") .trim(); } function lettersOnly(ar){return(ar||"").replace(/[^A-Za-z\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\s]/g,"").replace(/\s{2,}/g," ").trim()} function alnumAr(s){return(s||"").replace(/[^0-9A-Za-z\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\s\-\._/]/g,"").replace(/\s{2,}/g," ").trim()} function digitsOnly(s){return(s||"").replace(/\D+/g,"")} const LABEL_FIXES=[ [/(^|\n)\s*نوع\s*المشكله/gi,"$1نوع المشكلة"], [/(^|\n)\s*وقت\s*حدوث\s*المشكله/gi,"$1وقت حدوث المشكلة"], [/(^|\n)\s*اسم\s*صاحب\s*المشكله/gi,"$1اسم صاحب المشكلة"], [/(^|\n)\s*رقم\s*الهويه/gi,"$1رقم الهوية"], [/(^|\n)\s*المنطقه/gi,"$1المنطقة"], [/(^|\n)\s*اسم\s*المنطقة/gi,"$1المنطقة"], [/(^|\n)\s*اسم\s*المسح/gi,"$1المسح"], [/(^|\n)\s*الهاتف/gi,"$1رقم الجوال"], [/(^|\n)\s*جوال/gi,"$1رقم الجوال"] ]; function fixLabels(s){let t=s;LABEL_FIXES.forEach(([re,rep])=>t=t.replace(re,rep));return t} const H_MONTHS=["محرم","صفر","ربيع الأول","ربيع الاول","ربيع الآخر","ربيع الاخر","جمادى الأولى","جمادى الاولى","جمادى الآخرة","جمادى الاخرة","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو القعده","ذو الحجة","ذو الحجه"]; function monthIndexHijri(name){ const i=H_MONTHS.findIndex(m=>new RegExp("^"+m+"$","i").test(name.trim())); if(i<0)return-1; const map={0:1,1:2,2:3,3:3,4:4,5:4,6:5,7:5,8:6,9:6,10:7,11:8,12:9,13:10,14:11,15:11,16:12,17:12}; return map[i]||-1; } function hijriToGregorian(hy,hm,hd){ const jd=Math.floor((11*hy+3)/30)+354*hy+30*hm-Math.floor((hm-1)/2)+hd+1948440-385; let l=jd+68569; let n=Math.floor(4*l/146097);l=l-Math.floor((146097*n+3)/4); let i=Math.floor(4000*(l+1)/1461001);l=l-Math.floor(1461*i/4)+31; let j=Math.floor(80*l/2447);const d=l-Math.floor(2447*j/80); l=Math.floor(j/11);const m=j+2-12*l;const y=100*(ن-49)+i+l; return[y,m,d]; } function isTimeOnly(t){ const a=/(^|\s)\d{1,2}\s*(?:[:٫\.\-]\d{2})\s*(?:ص|صباح(?:اً|ا)?|am|م|مساء|pm)?($|\s)/i.test(t); const b=/(^|\s)\d{1,2}\s*(?:ص|صباح(?:اً|ا)?|am|م|مساء|pm)($|\s)/i.test(t); const c=/الساعة\s*\d{1,2}(?:[:٫\.\-]\d{2})?/i.test(t); return a||b||c; } function isRelativeDatePhrase(t){ return /(أمس|من\s*أمس|من\s*امس|اليوم|غدًا|غدا|بكرة|بعد\s*بكرة|قبل\s*\d+\s*(?:دقيقة|دقايق|ساع(?:ة|ات)|يوم|أيام)|الآن|الحين|قبل\s*شوي)/i.test(t); } function detectHijriDate(str){ const t=normalizeText(str); let m=t.match(/(\d{1,2})\s+([^\s]+)\s+(\d{3,4})\s*(هـ|ه|هجري)?/i); if(m){const d=+m[1];const hm=monthIndexHijri(m[2]);const y=+m[3];if(hm>=1&&hm<=12)return{hy:y,hm:hm,hd:d}} m=t.match(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{3,4})\s*(هـ|ه|هجري)/i); if(m)return{hy:+m[3],hm:+m[2],hd:+m[1]}; return null; } function normalizeDateOnly(raw){ const t=normalizeText(raw); if(isTimeOnly(t)||isRelativeDatePhrase(t))return""; const hj=detectHijriDate(t); if(hj){const[gy,gm,gd]=hijriToGregorian(hj.hy,hj.hm,hj.hd);return`${String(gy).padStart(4,"0")}-${String(gm).padStart(2,"0")}-${String(gd).padStart(2,"0")}`} const m=t.match(/(\d{1,4})[\/\-](\d{1,2})[\/\-](\d{1,4})/); if(m){ let a=+m[1],b=+m[2],c=+m[3],y,mo,d; if(String(m[1]).length===4){y=a;mo=b;d=c} else if(String(m[3]).length===4){y=c;mo=b;d=a} else if(a>31){y=a;mo=b;d=c} else if(c>31){y=c;mo=b;d=a} else{y=c;mo=b;d=a} if(y<100)y+=2000; if(mo>12&&d<=12){const tmp=mo;mo=d;d=tmp} if(mo<1||mo>12||d<1||d>31)return""; return`${String(y).padStart(4,"0")}-${String(mo).padStart(2,"0")}-${String(d).padStart(2,"0")}` } return""; } function findStartsByLabels(text,labels){ const lblRe=labels.map(l=>l.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')).join("|"); const re=new RegExp(`(^|\\n)\\s*(?:[-–—\\*•]+|\\d+[\\)\\.]\\s*)?\\s*(?:${lblRe})(?:\\s*[::]|\\s+)`,"gi"); const idxs=[];let m;while((m=re.exec(text))){idxs.push(m.index+(m[1]?m[1].length:0))}return idxs; } function findAfterLabel(text,labels){ const hay="\n"+normalizeText(text)+"\n"; for(const rawLbl of labels){ const lbl=rawLbl.replace(/[.*+?^${}()|[\]\\]/g,'\\$&'); let m=hay.match(new RegExp(`(?:^|\\n)\\s*${lbl}\\s*[::]\\s*([^\\n]+)`,"i"));if(m)return m[1].trim(); m=hay.match(new RegExp(`(?:^|\\n)\\s*${lbl}\\s+([^\\n]+)`,"i"));if(m)return m[1].trim(); } return""; } function findBlockAfterLabel(text,labels,allLabels=START_LABELS){ const hay="\n"+normalizeText(text)+"\n"; const esc=s=>s.replace(/[.*+?^${}()|[\]\\]/g,'\\$&'); const lblAlt=labels.map(esc).join("|"); const allAlt=allLabels.map(esc).join("|"); const re=new RegExp(`(?:^|\\n)\\s*(?:${lblAlt})\\s*(?::|:|\\s)\\s*([\\s\\S]*?)(?=\\n\\s*(?:${allAlt})\\s*(?::|:|\\s)|$)`,"i"); const m=hay.match(re); return m?m[1].trim():""; } function splitTickets(raw){ const text=normalizeText(fixLabels(raw)); if(!text)return[]; if(TICKET_SEP.test(text))return text.split(TICKET_SEP).map(p=>p.trim()).filter(Boolean); const niu=findStartsByLabels(text,["نوع المشكلة","نوع المشكله"]).sort((a,b)=>a-b); if(niu.length>=2){ const parts=[]; for(let i=0;i{ const f=extractFields(t); const cls=classifyTicket(t,f); const region=regionChosen?regionChosen:(f["المنطقة"]||""); let survey=f["المسح"]||region; let id=(f["رقم الهوية"]||"").replace(/\D/g,""); let dev=(f["رقم الجهاز"]||"").replace(/\D/g,""); let phone=(f["رقم الجوال"]||"").replace(/\D/g,""); if(!isValidNationalId(id))id=""; if(!isPhoneNumber(phone))phone=""; if(!dev&&isValidNationalId(id))dev=id; if(!id&&isValidNationalId(dev))id=dev; const dateOnly=f["وقت حدوث المشكلة"]||""; return{ "التصنيف":cls, "نوع المشكلة":f["نوع المشكلة"]||"", "وقت حدوث المشكلة":dateOnly, "اسم صاحب المشكلة":f["اسم صاحب المشكلة"]||"", "رقم الهوية":id, "رقم الجهاز":dev, "رقم الجوال":phone, "المسح":survey||region, "المنطقة":region, "اسم الدعم الفني":agentName||"", "الحالة":"تم الحل", "تاريخ اليوم بالميلادي":dateOnly }; }); } function buildTable(rows){ const theadRow=document.getElementById("theadRow"); const tbody=document.getElementById("tbody"); theadRow.innerHTML=""; DISPLAY_COLUMNS.forEach(col=>{const th=document.createElement("th");th.textContent=col;theadRow.appendChild(th)}); tbody.innerHTML=""; rows.forEach(r=>{ const tr=document.createElement("tr"); DISPLAY_COLUMNS.forEach(col=>{ const td=document.createElement("td"); const base=DISPLAY_TO_BASE[col]; td.dataset.base=base; let val=(base?(r[base]||""):""); if(col==="التصنيف"){ const span=document.createElement("span"); span.className=`cat ${catClass(val||"")}`; span.textContent=val||""; td.appendChild(span); }else{ td.contentEditable="true"; td.textContent=val; } tr.appendChild(td); }); tbody.appendChild(tr); }); } function readTable(){ const tbody=document.getElementById("tbody"); const rows=[]; [...tbody.querySelectorAll("tr")].forEach(tr=>{ const obj={}; [...tr.children].forEach(td=>{ const base=td.dataset.base; if(!base)return; if(base==="التصنيف"){obj[base]=(td.querySelector("span")?.textContent||td.textContent||"").trim()} else{obj[base]=(td.textContent||"").trim()} }); obj["وقت حدوث المشكلة"]=obj["تاريخ اليوم بالميلادي"]||""; rows.push(obj); }); return rows; } function updateBadge(n){ const b=document.getElementById("countBadge"); if(!b)return; b.textContent=n; b.hidden=(n===0); } function setButtonsEnabled(hasRows){ document.getElementById("btn-export").disabled=!hasRows; document.getElementById("btn-copy").disabled=!hasRows; } function validateCells(){ const tbody=document.getElementById("tbody"); const required=new Set(["نوع المشكلة","اسم صاحب المشكلة","رقم الهوية","رقم الجهاز","رقم الجوال","المسح","المنطقة"]); let missing=0; [...tbody.rows].forEach(tr=>{ [...tr.children].forEach(td=>{ const base=td.dataset.base||""; const val=(td.textContent||"").trim(); let invalid=false,reason=""; if(required.has(base)&&!val){invalid=true;reason="required";missing++} if(base==="رقم الهوية"){ const digits=val.replace(/\D/g,""); if(val&&!/^[12]\d{9}$/.test(digits)){invalid=true;if(!reason)reason="id"} } if(base==="رقم الجوال"){ const digits=val.replace(/\D/g,""); if(val&&!/^05\d{8}$/.test(digits)){invalid=true;if(!reason)reason="phone"} } if(base==="تاريخ اليوم بالميلادي"){ if(val&&!/^\d{4}-\d{2}-\d{2}$/.test(val)){invalid=true;reason="date"} } //td.classList.toggle("invalid",invalid); if(invalid){ const msg=reason==="required"?"الحقل مطلوب":reason==="id"?"رقم الهوية يجب أن يبدأ بـ 1 أو 2 وطوله 10 خانات":reason==="phone"?"رقم الجوال يجب أن يبدأ بـ 05 وطوله 10 خانات":"أدخل تاريخ بصيغة YYYY-MM-DD"; td.setAttribute("title",msg); td.dataset.reason=reason; }else{ td.removeAttribute("title"); delete td.dataset.reason; } }); }); const warn=document.getElementById("warn"); if(missing>0){warn.hidden=false;warn.textContent=`هناك ${missing} حقول مطلوبة فارغة أو غير صحيحة. يرجى إكمالها.`} else{warn.hidden=true;warn.textContent=""} } document.addEventListener("input",e=>{ if(e.target&&e.target.closest&&e.target.closest("#tbody")){ validateCells(); saveState(); } }); function toast(msg){ const t=document.getElementById("toast"); if(!t)return; t.textContent=msg; t.hidden=false; t.classList.remove("show");void t.offsetWidth;t.classList.add("show"); setTimeout(()=>{t.hidden=true},2000); } async function exportExcel(){ const TEMPLATE_HEADERS=["التصنيف","نوع المشكلة","المنطقة","اسم المسح","اسم المشغل","رقم الجوال","رقم الهوية ID","رقم الجهاز","وقت حدوث المشكلة","الحالة","اسم الدعم الفني"]; const rows=readTable(); if(!rows.length){toast("لا يوجد بيانات لتصديرها.");return} const mapRow=r=>({ "التصنيف":r["التصنيف"]||"", "نوع المشكلة":r["نوع المشكلة"]||"", "المنطقة":r["المنطقة"]||"", "اسم المسح":r["المسح"]||"", "اسم المشغل":r["اسم صاحب المشكلة"]||"", "رقم الجوال":(r["رقم الجوال"]||"").toString(), "رقم الهوية ID":(r["رقم الهوية"]||"").toString(), "رقم الجهاز":(r["رقم الجهاز"]||"").toString(), "وقت حدوث المشكلة":r["وقت حدوث المشكلة"]||"", "الحالة":r["الحالة"]||"تم الحل", "اسم الدعم الفني":r["اسم الدعم الفني"]||"" }); const wb=new ExcelJS.Workbook(); const ws=wb.addWorksheet("التذاكر",{views:[{rightToLeft:true}]}); const colWidths=[16,18,16,18,20,18,18,18,20,14,18]; TEMPLATE_HEADERS.forEach((h,i)=>ws.getColumn(i+1).width=colWidths[i]||18); ws.addRow(TEMPLATE_HEADERS); const headerRow=ws.getRow(1); headerRow.height=24; headerRow.eachCell(cell=>{ cell.font={bold:true,color:{argb:"FFFFFFFF"}}; cell.alignment={horizontal:"center",vertical:"middle"}; cell.fill={type:"pattern",pattern:"solid",fgColor:{argb:"FF4137A8"}}; cell.border={top:{style:"thin",color:{argb:"FFCDD2E1"}},bottom:{style:"thin",color:{argb:"FFCDD2E1"}},left:{style:"thin",color:{argb:"FFE5E7EB"}},right:{style:"thin",color:{argb:"FFE5E7EB"}}}; }); const toTextCols=new Set(["رقم الجوال","رقم الهوية ID","رقم الجهاز"]); rows.forEach((r,idx)=>{ const m=mapRow(r); const vals=TEMPLATE_HEADERS.map(h=>(m[h]??"")); const row=ws.addRow(vals); row.alignment={horizontal:"center",vertical:"middle"}; const even=(idx%2)===1; row.eachCell((cell,colNumber)=>{ cell.border={top:{style:"thin",color:{argb:"FFE5E7EB"}},bottom:{style:"thin",color:{argb:"FFE5E7EB"}},left:{style:"thin",color:{argb:"FFE5E7EB"}},right:{style:"thin",color:{argb:"FFE5E7EB"}}}; if(even)cell.fill={type:"pattern",pattern:"solid",fgColor:{argb:"FFF5F8FF"}}; const header=TEMPLATE_HEADERS[colNumber-1]; if(toTextCols.has(header))cell.value=String(cell.value??""); }); }); const ts=new Date().toISOString().replace(/\D/g,"").slice(0,14); const filename=`Ticket_${ts}.xlsx`; const buffer=await wb.xlsx.writeBuffer(); const blob=new Blob([buffer],{type:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}); const file=new File([blob],filename,{type:blob.type}); if(navigator.canShare&&navigator.canShare({files:[file]})){try{await navigator.share({files:[file],title:"ملف التذاكر"});toast("تمت المشاركة/الحفظ.");return}catch(e){}} const url=URL.createObjectURL(blob); const a=document.createElement("a");a.href=url;a.download=filename;document.body.appendChild(a);a.click();a.remove(); setTimeout(()=>URL.revokeObjectURL(url),1000); toast("تم تنزيل الملف بتنسيق القالب."); } async function copyToClipboardTSV(){ const rows=readTable(); if(!rows.length){toast("لا يوجد بيانات لنسخها.");return} const textCols=new Set(["رقم الهوية ID","رقم الجهاز","رقم الجوال"]); const body=rows.map(r=>DISPLAY_COLUMNS.map(c=>{ const base=DISPLAY_TO_BASE[c]; let v=(base?(r[base]??""):"").toString().replace(/\t/g," "); if(textCols.has(c)&&v&&/^[0-9]+$/.test(v))v="'"+v; return v; }).join("\t")).join("\r\n"); const tsv="\uFEFF"+body; try{await navigator.clipboard.writeText(tsv);toast("تم النسخ — بدون عناوين.")}catch(e){ const ta=document.createElement("textarea");ta.value=tsv;document.body.appendChild(ta);ta.select();document.execCommand("copy");document.body.removeChild(ta);toast("تم النسخ — بدون عناوين.") } } const SAMPLE=`نوع المشكلة: لا استطيع اكمال الاستمارة بسبب تعليق عند الحفظ وقت حدوث المشكلة: 1446/09/10 هـ اسم صاحب المشكلة: نوف الناصر رقم الهوية: 1234567890 رقم الجهاز: 01234 رقم الجوال: 0558174717 المسح: الخبر المنطقة: الشرقية`; function saveState(){ try{ const raw=document.getElementById("raw")?.value||""; const agent=document.getElementById("agentName")?.value||""; const region=document.getElementById("regionDefault")?.value||""; const rows=readTable(); localStorage.setItem("ticketParserState_latest",JSON.stringify({raw,agent,region,rows,theme:document.body.classList.contains('dark')?'dark':'light'})); }catch{} } function loadState(){ try{ const s=localStorage.getItem("ticketParserState_latest"); if(!s)return false; let{raw,agent,region,rows,theme}=JSON.parse(s); const rawEl=document.getElementById("raw");if(typeof raw==="string"&&rawEl)rawEl.value=raw; const agentEl=document.getElementById("agentName");if(typeof agent==="string"&&agentEl)agentEl.value=agent; const regionEl=document.getElementById("regionDefault");if(typeof region==="string"&®ionEl)regionEl.value=region; if(theme==='dark')document.body.classList.add('dark'); updateThemeLabel(); if(Array.isArray(rows)&&rows.length){buildTable(rows);validateCells();updateBadge(rows.length);setButtonsEnabled(true)} return true; }catch{return false} } function clearAll(){ const rawEl=document.getElementById("raw"); const tbody=document.getElementById("tbody"); const agentEl=document.getElementById("agentName"); const regionEl=document.getElementById("regionDefault"); if(rawEl)rawEl.value=""; if(tbody)tbody.innerHTML=""; if(agentEl)agentEl.value=""; if(regionEl)regionEl.value=""; updateBadge(0);setButtonsEnabled(false); document.getElementById("warn").hidden=true; try{localStorage.removeItem("ticketParserState_latest")}catch{} toast("تم مسح كل البيانات والتخزين."); } function mergeDuplicatesRows(rows){ if(!rows.length)return rows; const map=new Map(); rows.forEach(r=>{ const key=[r["رقم الهوية"]||"",r["رقم الجهاز"]||"",r["رقم الجوال"]||"",r["وقت حدوث المشكلة"]||"",(r["نوع المشكلة"]||"").slice(0,40)].join("|"); if(!map.has(key))map.set(key,r); }); return[...map.values()]; } function updateThemeLabel(){ const btn=document.getElementById("btn-theme"); if(!btn)return; btn.textContent=document.body.classList.contains("dark")?"☀️ وضع نهار":"🌙 وضع ليلي"; } function isUnlocked(){try{return localStorage.getItem("ticketParser_unlocked")==="1"}catch{return false}} function markUnlocked(){try{localStorage.setItem("ticketParser_unlocked","1")}catch{}} function getLockBtn(){return document.getElementById("lockBtn")||document.getElementById("unlockBtn")||document.querySelector('[data-action="unlock"]')} function getLockInput(){return document.getElementById("lockPass")||document.querySelector('input[type="password"][name="lock"]')} function showGate(){ if(isUnlocked()){hideGate();return} const ov=document.getElementById("lockOverlay"); if(ov){ov.style.display="flex";setTimeout(()=>{const p=getLockInput();if(p)p.focus()},0)} } function hideGate(){ const ov=document.getElementById("lockOverlay"); if(ov)ov.style.display="none"; } function tryUnlock(){ const inp=getLockInput(); const raw=inp?(inp.value||""):""; const normalized=raw.replace(/[٠-٩]/g,d=>arabicDigitsMap[d]).trim(); if(ACCESS_PASSWORDS.includes(normalized)){markUnlocked();hideGate()} else{ const m=document.getElementById("lockMsg"); if(m){m.hidden=false;setTimeout(()=>m.hidden=true,1500)} } } function wireLock(){ const btn=getLockBtn(); const inp=getLockInput(); if(btn)btn.addEventListener("click",tryUnlock); if(inp)inp.addEventListener("keydown",e=>{if(e.key==="Enter")tryUnlock()}); } function init(){ const parseBtn=document.getElementById("btn-parse"); const exportBtn=document.getElementById("btn-export"); const copyBtn=document.getElementById("btn-copy"); const clearBtn=document.getElementById("btn-clear"); const themeBtn=document.getElementById("btn-theme"); const rawEl=document.getElementById("raw"); const agentEl=document.getElementById("agentName"); const regionEl=document.getElementById("regionDefault"); rawEl.placeholder=SAMPLE; if(!isUnlocked())showGate();else hideGate(); wireLock(); loadState(); parseBtn.addEventListener("click",()=>{ const raw=(rawEl.value||"").trim(); if(!raw){toast("فضلاً الصق/ي تذاكر أولاً.");return} const cleaned=normalizeText(fixLabels(raw)); const agent=agentEl.value||""; const defRegion=regionEl.value||""; let rows=parseTicketsWithExtras(cleaned,agent,defRegion); rows=mergeDuplicatesRows(rows); buildTable(rows);validateCells(); updateBadge(rows.length);setButtonsEnabled(rows.length>0); saveState(); toast(`تم استخراج ${rows.length} تذكرة.`); }); exportBtn.addEventListener("click",exportExcel); copyBtn.addEventListener("click",copyToClipboardTSV); clearBtn.addEventListener("click",clearAll); themeBtn.addEventListener("click",()=>{document.body.classList.toggle("dark");updateThemeLabel();saveState()}); rawEl.addEventListener("input",saveState); agentEl.addEventListener("input",saveState); regionEl.addEventListener("change",saveState); document.addEventListener("keydown",e=>{ const ctrl=e.ctrlKey||e.metaKey; if(ctrl&&e.key==="Enter"){e.preventDefault();parseBtn.click()} else if(ctrl&&e.key.toLowerCase()==="e"){e.preventDefault();exportBtn.click()} else if(ctrl&&e.shiftKey&&e.key.toLowerCase()==="c"){e.preventDefault();copyBtn.click()} else if(e.key==="Escape"){e.preventDefault();clearAll()} }); setButtonsEnabled(!!document.getElementById("tbody")?.children.length); updateThemeLabel(); } init();