حاسبة الترقية في الدرجات والأقدمية | www.flsafa.com :root{--bg:#f1f6fb;--cd:#fff;--tx:#14304a;--mu:#5b6f84;--bd:#d6e2ee;--in:#fff;--ac:#0f766e;box-sizing:border-box;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)} @media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--bg:#0b1722;--cd:#13273a;--tx:#e6f0f8;--mu:#9bb0c4;--bd:#294358;--in:#0b1722;--ac:#2dd4bf}} :root[data-theme="dark"]{--bg:#0b1722;--cd:#13273a;--tx:#e6f0f8;--mu:#9bb0c4;--bd:#294358;--in:#0b1722;--ac:#2dd4bf} html{scroll-padding-top:env(safe-area-inset-top,0px)} *{box-sizing:border-box} body{margin:0;background:var(--bg);color:var(--tx);font:16px/1.8 Tajawal,Tahoma,sans-serif} #app{max-width:680px;margin:0 auto;padding:10px} .hd{background:linear-gradient(135deg,#0c2f4d,#0f5a6b 60%,#0f766e);color:#fff;border-radius:0 0 30px 30px;padding:18px 18px 24px;margin:-10px -10px 14px} .hd .row{display:flex;justify-content:space-between;align-items:center} .lg{border:1px solid rgba(255,255,255,.5);background:rgba(255,255,255,.12);color:#fff;font:inherit;font-weight:700;border-radius:12px;padding:2px 16px;cursor:pointer} .hd h1{margin:14px 0 4px;font-size:28px;font-weight:800;line-height:1.5} .hd p{margin:0;color:#d4e6f2} .cd{background:var(--cd);border-radius:22px;padding:18px;margin-bottom:14px;box-shadow:0 6px 20px rgba(12,47,77,.10)} .cd h2{margin:0 0 10px;font-size:20px;font-weight:800;border-inline-start:6px solid var(--ac);padding-inline-start:10px} label{display:block;font-weight:700;font-size:14px;margin-top:10px} input,select{width:100%;font:inherit;font-size:16px;color:var(--tx);background:var(--in);border:1px solid var(--bd);border-radius:14px;padding:6px 12px;margin-top:4px} .g3{display:grid;grid-template-columns:repeat(3,1fr);gap:8px} small{color:var(--mu)} .b{width:100%;border:0;background:linear-gradient(135deg,#0f766e,#0e8f80);color:#fff;font:inherit;font-weight:800;font-size:18px;border-radius:16px;padding:10px;cursor:pointer;margin-top:16px} .rs{border:2px solid var(--ac)} .big{font-size:28px;font-weight:800;color:var(--ac);margin:4px 0} .er{color:#c0392b;font-weight:700} table{width:100%;border-collapse:collapse;margin-top:8px} td,th{padding:4px 8px;border-top:1px solid var(--bd);text-align:start} .ft{text-align:center;margin:8px 0 18px;color:var(--mu)} .ft a{color:var(--ac);font-weight:800;text-decoration:none} var $=function(s){return document.querySelector(s)}; var E=function(s){return String(s).replace(/[&<>"]/g,function(c){return{'&':'&','<':'<','>':'>','"':'"'}[c]})}; var L={ar:{ti:'حاسبة الترقية في الدرجات والأقدمية',su:'نموذج أولي لحساب تاريخ الترقية إلى الدرجة المقبلة.',d1:'بيانات الموظف',cad:'الإطار أو السلك (اختياري)',pace:'وتيرة الترقية المطلوبة',pn:['الوتيرة الدنيا','الوتيرة المتوسطة','الوتيرة القصوى'],gr:'الدرجة الحالية',dt:'تاريخ سريان الدرجة الحالية',rt:'الأقدمية المحتفظ بها (سنوات / أشهر / أيام)',ex:'خبرة إضافية معترف بها قانونا (اختياري)',y:'سنوات',m:'أشهر',d:'أيام',d2:'مدد الترقية (قابلة للتعديل)',mo:'شهرا',ng:'عدد الدرجات',note:'القيم الافتراضية للتجربة فقط. عدّلها حسب النصوص القانونية الجارية في قطاعك.',go:'احسب تاريخ الدرجة المقبلة تلقائيا',nd:'أدخل تاريخ سريان الدرجة الحالية.',nx:'تاريخ الترقية إلى الدرجة',due:'مستحقة منذ ذلك التاريخ',left:'متبقي حوالي',day:'يوم',last:'الموظف في آخر درجة.',pl:'توقعات الدرجات اللاحقة بنفس الوتيرة',dis:'النتيجة استرشادية. تحقق من انطباق المدة على الرتبة وفق النصوص القانونية السارية.',gn:'الدرجة'}, fr:{ti:"Calcul d'avancement d'échelon et d'ancienneté",su:"Modèle préliminaire pour calculer la date de passage à l'échelon suivant.",d1:"Données de l'agent",cad:'Corps ou cadre (facultatif)',pace:"Rythme d'avancement souhaité",pn:['Rythme minimal','Rythme moyen','Rythme maximal'],gr:'Échelon actuel',dt:"Date d'effet de l'échelon actuel",rt:'Ancienneté conservée (ans / mois / jours)',ex:'Expérience supplémentaire reconnue (facultatif)',y:'Ans',m:'Mois',d:'Jours',d2:"Durées d'avancement (modifiables)",mo:'mois',ng:"Nombre d'échelons",note:'Valeurs par défaut pour essai seulement. Adaptez-les aux textes en vigueur dans votre secteur.',go:"Calculer la date de l'échelon suivant",nd:"Saisissez la date d'effet de l'échelon actuel.",nx:"Date de passage à l'échelon",due:'dû depuis cette date',left:'il reste environ',day:'jours',last:"L'agent est au dernier échelon.",pl:'Projection des échelons suivants au même rythme',dis:"Résultat indicatif. Vérifiez la durée requise selon les textes en vigueur.",gn:'Échelon'}}; var S={lang:'ar',p:[30,36,42],g:12}; try{var r0=JSON.parse(localStorage.getItem('flsafa-promo'));if(r0&&r0.p)S=r0}catch(e){} var V={cad:'',pace:0,grade:1,date:'',r:[0,0,0],x:[0,0,0]},R=''; function sv(){try{localStorage.setItem('flsafa-promo',JSON.stringify(S))}catch(e){}} function am(d,n){var x=new Date(d.getFullYear(),d.getMonth()+n,1),l=new Date(x.getFullYear(),x.getMonth()+1,0).getDate();x.setDate(Math.min(d.getDate(),l));return x} function fd(d){return String(d.getDate()).padStart(2,'0')+'/'+String(d.getMonth()+1).padStart(2,'0')+'/'+d.getFullYear()} function tri(k,a,s){return '<div class="g3">'+[0,1,2].map(function(i){return '<div><input type="number" min="0" inputmode="numeric" placeholder="'+[s.y,s.m,s.d][i]+'" value="'+(V[k][i]||'')+'" oninput="V.'+k+'['+i+']=+this.value||0"></div>'}).join('')+'</div>'} function calc(){ var s=L[S.lang]; if(!V.date){R='<div class="cd rs"><p class="er">'+s.nd+'</p></div>';render();return} if(V.grade>=S.g){R='<div class="cd rs"><p class="er">'+s.last+'</p></div>';render();return} var e=new Date(V.date+'T00:00:00'),pm=S.p[V.pace],cm=V.r[0]*12+V.r[1]+V.x[0]*12+V.x[1],cd=V.r[2]+V.x[2]; var d=am(e,pm-cm);d.setDate(d.getDate()-cd); var today=new Date();today.setHours(0,0,0,0); var df=Math.ceil((d-today)/864e5); var st=df<=0?s.due:s.left+' '+df+' '+s.day; var rows='';for(var k=0;k<4&&V.grade+1+k<=S.g;k++){rows+='<tr><td>'+s.gn+' '+(V.grade+1+k)+'</td><td>'+fd(am(d,k*pm))+'</td></tr>'} R='<div class="cd rs"><h2>'+s.nx+' '+(V.grade+1)+'</h2><div class="big">'+fd(d)+'</div><p>'+st+'</p><h2 style="font-size:17px">'+s.pl+'</h2><table>'+rows+'</table><p><small>'+s.dis+'</small></p></div>'; render();$('#rs').scrollIntoView({behavior:'smooth'})} function render(){ var s=L[S.lang]; document.documentElement.lang=S.lang;document.documentElement.dir=S.lang=='ar'?'rtl':'ltr'; var gs='';for(var i=1;i<=S.g;i++)gs+='<option value="'+i+'"'+(i==V.grade?' selected':'')+'>'+s.gn+' '+i+'</option>'; var ps=s.pn.map(function(n,i){return '<option value="'+i+'"'+(i==V.pace?' selected':'')+'>'+n+' ('+S.p[i]+' '+s.mo+')</option>'}).join(''); $('#app').innerHTML='<div class="hd"><div class="row"><button class="lg" onclick="S.lang=S.lang==\'ar\'?\'fr\':\'ar\';sv();render()">'+(S.lang=='ar'?'Français':'العربية')+'</button><span style="font-size:34px">📘</span></div><h1>'+s.ti+'</h1><p>'+s.su+'</p></div>' +'<div class="cd"><h2>'+s.d1+'</h2><label>'+s.cad+'</label><input value="'+E(V.cad)+'" oninput="V.cad=this.value"><label>'+s.pace+'</label><select onchange="V.pace=+this.value">'+ps+'</select><label>'+s.gr+'</label><select onchange="V.grade=+this.value">'+gs+'</select><label>'+s.dt+'</label><input type="date" value="'+V.date+'" onchange="V.date=this.value"><label>'+s.rt+'</label>'+tri('r',0,s)+'<label>'+s.ex+'</label>'+tri('x',0,s)+'</div>' +'<div class="cd"><h2>'+s.d2+'</h2><div class="g3">'+S.p.map(function(v,i){return '<div><label>'+s.pn[i]+'</label><input type="number" min="1" value="'+v+'" onchange="S.p['+i+']=Math.max(1,+this.value||1);sv();render()"></div>'}).join('')+'</div><label>'+s.ng+'</label><input type="number" min="2" max="30" value="'+S.g+'" onchange="S.g=Math.max(2,+this.value||12);if(V.grade>S.g)V.grade=S.g;sv();render()"><p><small>'+s.note+'</small></p><button class="b" onclick="calc()">'+s.go+'</button></div>' +'<div id="rs">'+R+'</div><div class="ft">🏠 <a href="https://www.flsafa.com/">www.flsafa.com</a></div>'} render();