66 lines
4.9 KiB
JavaScript
66 lines
4.9 KiB
JavaScript
/* Real multipart upload progress; registration remains authoritative on the server. */
|
|
(() => {
|
|
'use strict';
|
|
const number=new Intl.NumberFormat('fa-IR',{maximumFractionDigits:1});
|
|
function bytes(value){return value>=1048576?number.format(value/1048576)+' مگابایت':number.format(value/1024)+' کیلوبایت';}
|
|
function duration(seconds){return seconds>=60?number.format(Math.ceil(seconds/60))+' دقیقه':number.format(Math.max(1,Math.ceil(seconds)))+' ثانیه';}
|
|
function send(form){
|
|
const payload=new FormData(form),panel=document.querySelector('#receipt-upload');
|
|
const title=document.querySelector('#receipt-upload-title'),meter=document.querySelector('#receipt-upload-progress');
|
|
const percent=document.querySelector('#receipt-upload-percent'),amount=document.querySelector('#receipt-upload-bytes'),time=document.querySelector('#receipt-upload-time');
|
|
const button=document.querySelector('#submit-receipt');
|
|
const controls=[...form.querySelectorAll('input,select,textarea,button')].map(control=>[control,control.disabled]);
|
|
controls.forEach(([control])=>{control.disabled=true;});form.classList.add('is-uploading');button.setAttribute('aria-busy','true');
|
|
panel.hidden=false;title.textContent='در حال ارسال فیش…';button.textContent='در حال ارسال…';
|
|
meter.value=0;percent.textContent='۰٪';amount.textContent='در انتظار شروع ارسال';
|
|
const started=performance.now();let loaded=0,total=0,lastProgress=started,processing=false;
|
|
function updateTime(){
|
|
if(processing)return;
|
|
const elapsed=(performance.now()-started)/1000;
|
|
const estimate=loaded>0 && elapsed>=1 && total>loaded;
|
|
time.textContent='زمان سپریشده: '+number.format(Math.floor(elapsed))+' ثانیه'+(performance.now()-lastProgress>5000?' · منتظر ادامه ارسال؛ سرعت اتصال تغییر کرده است.':estimate?' · حدود '+duration((total-loaded)*elapsed/loaded)+' دیگر برای ارسال':' · در حال محاسبه زمان باقیمانده…');
|
|
}
|
|
function process(){
|
|
processing=true;meter.value=100;percent.textContent='۱۰۰٪';
|
|
title.textContent='ارسال کامل شد؛ در حال بررسی و ثبت فیش…';button.textContent='در حال ثبت…';
|
|
time.textContent='منتظر تأیید ثبت از سرور؛ زمان این مرحله به سرعت پردازش بستگی دارد.';
|
|
}
|
|
updateTime();panel.scrollIntoView({block:'nearest'});
|
|
return new Promise((resolve,reject)=>{
|
|
const xhr=new XMLHttpRequest(),timer=setInterval(updateTime,1000);let settled=false;
|
|
function finish(error,result){
|
|
if(settled)return;settled=true;clearInterval(timer);
|
|
if(!result?.redirect_url){
|
|
controls.forEach(([control,disabled])=>{control.disabled=disabled;});form.classList.remove('is-uploading');button.removeAttribute('aria-busy');
|
|
title.textContent='ثبت فیش انجام نشد';time.textContent='اطلاعات و تصویر حفظ شدهاند؛ پس از رفع مشکل دوباره ارسال کنید.';
|
|
}
|
|
if(error)reject(error);else resolve(result);
|
|
}
|
|
xhr.upload.addEventListener('progress',event=>{
|
|
loaded=event.loaded;total=event.lengthComputable?event.total:0;lastProgress=performance.now();
|
|
amount.textContent='ارسالشده: '+bytes(loaded)+(total?' از '+bytes(total):'');
|
|
if(total){const value=Math.min(100,Math.floor(loaded/total*100));meter.value=value;percent.textContent=number.format(value)+'٪';}
|
|
else{meter.removeAttribute('value');percent.textContent='در حال ارسال';}
|
|
updateTime();
|
|
});
|
|
xhr.upload.addEventListener('load',process);
|
|
xhr.addEventListener('load',()=>{
|
|
const result=xhr.response;
|
|
if(xhr.status>=200 && xhr.status<300 && result?.redirect_url){finish(null,result);return;}
|
|
if(xhr.status===422 && result?.errors){finish(null,result);return;}
|
|
const message=[401,403,410].includes(xhr.status)?'دسترسی یا نشست شما معتبر نیست؛ صفحه را دوباره باز کنید.':xhr.status===413?'حجم تصویر بیش از حد مجاز سرور است؛ تصویر کوچکتری انتخاب کنید.':'ثبت فیش تأیید نشد؛ دوباره تلاش کنید. در صورت تکرار، وضعیت فیشهای خود را بررسی کنید.';
|
|
finish(new Error(message));
|
|
});
|
|
xhr.addEventListener('error',()=>finish(new Error('ارتباط با سرور قطع شد؛ اتصال اینترنت را بررسی و دوباره ارسال کنید.')));
|
|
xhr.addEventListener('abort',()=>finish(new Error('ارسال متوقف شد؛ دوباره تلاش کنید.')));
|
|
try{
|
|
xhr.open('POST',form.action || location.href);xhr.responseType='json';
|
|
xhr.setRequestHeader('Accept','application/json');
|
|
xhr.setRequestHeader('X-CSRFToken',payload.get('csrfmiddlewaretoken'));
|
|
xhr.send(payload);
|
|
}catch(error){finish(error);}
|
|
});
|
|
}
|
|
window.ReceiptUpload=Object.freeze({send});
|
|
})();
|