עודכן בהודעה הראשונה קובץ שמכין את כל ה"מערכת" הזאת קומפלט עם כל הקבצים השקטים - לא לשים / אני לא יודע מה הוא יעשה עם זה!.
call2all_setup.zip
או
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Call2All – יצירת שלוחה</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&family=Heebo:wght@300;400;600;700&display=swap');
:root {
--bg:#0b0e13;--surface:#131720;--surface2:#1a1f2e;--border:#252c3f;
--accent:#3b82f6;--accent-glow:rgba(59,130,246,0.18);
--green:#22c55e;--red:#ef4444;--yellow:#f59e0b;
--text:#dde3f0;--muted:#4a5478;--label:#8892b0;
}
*{box-sizing:border-box;margin:0;padding:0;}
body{background:var(--bg);color:var(--text);font-family:'Heebo',sans-serif;min-height:100vh;display:flex;flex-direction:column;align-items:center;padding:2.5rem 1rem 4rem;background-image:radial-gradient(ellipse at 60% 0%,rgba(59,130,246,0.07) 0%,transparent 60%);}
header{text-align:center;margin-bottom:2.5rem;}
header h1{font-size:1.5rem;font-weight:700;color:#fff;}
header p{font-size:0.82rem;color:var(--muted);margin-top:0.4rem;font-family:'IBM Plex Mono',monospace;}
.card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:1.75rem;width:100%;max-width:580px;margin-bottom:1rem;}
.card-title{font-size:0.7rem;font-family:'IBM Plex Mono',monospace;letter-spacing:0.12em;text-transform:uppercase;color:var(--muted);margin-bottom:1.25rem;display:flex;align-items:center;gap:0.5rem;}
.card-title::before{content:'';display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--accent);box-shadow:0 0 6px var(--accent);}
.field-group{margin-bottom:1.1rem;}
label{display:block;font-size:0.78rem;color:var(--label);margin-bottom:0.35rem;}
input[type="text"],input[type="password"]{width:100%;background:var(--bg);border:1px solid var(--border);color:var(--text);font-family:'IBM Plex Mono',monospace;font-size:0.88rem;padding:0.6rem 0.85rem;border-radius:7px;outline:none;transition:border-color 0.2s,box-shadow 0.2s;direction:ltr;}
input:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-glow);}
.hint{font-size:0.72rem;color:var(--muted);margin-top:0.3rem;font-family:'IBM Plex Mono',monospace;}
.run-btn{width:100%;padding:0.8rem;background:var(--accent);color:#fff;border:none;border-radius:8px;font-family:'Heebo',sans-serif;font-size:0.95rem;font-weight:600;cursor:pointer;transition:all 0.2s;margin-top:0.5rem;}
.run-btn:hover{filter:brightness(1.12);transform:translateY(-1px);}
.run-btn:disabled{opacity:0.4;cursor:default;transform:none;}
.steps{width:100%;max-width:580px;display:flex;flex-direction:column;gap:0.5rem;}
.step{background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:0.85rem 1rem;display:flex;align-items:center;gap:0.75rem;font-size:0.82rem;transition:border-color 0.3s;}
.step.running{border-color:var(--accent);}
.step.done{border-color:rgba(34,197,94,0.4);}
.step.error{border-color:rgba(239,68,68,0.4);}
.step-icon{width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:0.75rem;font-family:'IBM Plex Mono',monospace;flex-shrink:0;background:var(--surface2);border:1px solid var(--border);color:var(--muted);transition:all 0.3s;}
.step.running .step-icon{border-color:var(--accent);color:var(--accent);animation:spin 1s linear infinite;}
.step.done .step-icon{background:rgba(34,197,94,0.1);border-color:var(--green);color:var(--green);}
.step.error .step-icon{background:rgba(239,68,68,0.1);border-color:var(--red);color:var(--red);}
.step-label{flex:1;color:var(--label);}
.step.running .step-label,.step.done .step-label{color:var(--text);}
.step.error .step-label{color:var(--red);}
.step-status{font-family:'IBM Plex Mono',monospace;font-size:0.7rem;color:var(--muted);}
.log-wrap{width:100%;max-width:580px;margin-top:0.5rem;}
#log{background:#070a0f;border:1px solid var(--border);border-radius:8px;padding:0.9rem 1rem;height:220px;overflow-y:auto;font-family:'IBM Plex Mono',monospace;font-size:0.75rem;line-height:1.8;direction:ltr;}
#log::-webkit-scrollbar{width:3px;}
#log::-webkit-scrollbar-thumb{background:var(--border);border-radius:2px;}
.log-line{display:flex;gap:0.5rem;}
.log-ts{color:var(--muted);flex-shrink:0;}
.log-ok{color:var(--green);}
.log-err{color:var(--red);}
.log-info{color:var(--accent);}
.log-warn{color:var(--yellow);}
@keyframes spin{to{transform:rotate(360deg);}}
</style>
</head>
<body>
<header>
<h1>⚙ Call2All — יצירת שלוחה</h1>
<p>// automated extension setup</p>
</header>
<div class="card">
<div class="card-title">פרטי חיבור</div>
<div class="field-group">
<label>מספר שלוחה </label>
<input type="text" id="ext" />
</div>
<div class="field-group">
<label>טוקן</label>
<input type="password" id="token" placeholder="הכנס טוקן..." />
</div>
<button class="run-btn" id="runBtn" onclick="startAll()">▶ הפעל תהליך</button>
</div>
<div class="steps" id="stepsWrap" style="display:none"></div>
<div class="log-wrap" id="logWrap" style="display:none">
<div id="log"></div>
</div>
<script>
const WAV_B64="UklGRtQBAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YbABAAAAAAAAAAAAAAEA/v8CAP7/AQAAAAEA/f8DAP7/AQAAAP//AQAAAAAAAAAAAP//AgD+/wMA/f8CAP7/AgD+/wIA/////wMA/P8DAP//AAAAAAEA/v8CAP7/AgD//wAAAAD//wIA/v8CAP7/AQABAP7/AgD+/wIA/v8DAPz/BAD9/wEAAQD+/wIA//8AAAAAAQD+/wMA/f8CAP//AQD//wAAAQD//wEA//8AAAEA//8BAP//AQD+/wIAAAD+/wMA/P8EAP3/AgD//wAAAQD+/wMA/f8CAP//AQD//wAAAQD//wEA//8AAAEA//8BAP//AQD//wEA/v8DAP3/AgAAAP7/AwD9/wMA/f8DAP3/AgAAAP//AAAAAAEA//8BAP7/AQABAAAA//8BAP3/BQD8/wMA/v8AAAEAAAD//wEAAAD//wIA/f8DAP7/AgD+/wEAAAAAAAAAAAAAAP//AgD+/wIA///+/wQA+/8GAPr/BQD9/wEAAQD9/wMA/////wIA/v8AAAIA/f8EAPz/AwD+/wEAAQD9/wQA/P8EAPz/AwD9/wQA/P8EAPz/AwD9/wQA/P8=";
function ts(){return new Date().toLocaleTimeString('he-IL',{hour12:false});}
let logEl;
function log(msg,cls='log-info'){
const line=document.createElement('div');
line.className='log-line';
line.innerHTML=`<span class="log-ts">[${ts()}]</span><span class="${cls}">${msg}</span>`;
logEl.appendChild(line);
logEl.scrollTop=logEl.scrollHeight;
}
function b64toBlob(b64,mime){
const bin=atob(b64),buf=new Uint8Array(bin.length);
for(let i=0;i<bin.length;i++)buf[i]=bin.charCodeAt(i);
return new Blob([buf],{type:mime});
}
const STEP_DEFS=[
{id:'ext1', label:'יצירת שלוחה – שלב 1 (הקשת מספר)'},
{id:'ext2', label:'יצירת שלוחה – שלב 2 (API link)'},
{id:'ext3', label:'יצירת שלוחה – שלב 3 (routing queue)'},
{id:'wav_root', label:'העלאת קובץ שמע → M3411.wav'},
{id:'wav_sub', label:'העלאת קובץ שמע → 1/M1607.wav'},
];
const stepEls={};
function buildSteps(exts){
const wrap=document.getElementById('stepsWrap');
wrap.innerHTML='';
exts.forEach(ext=>{
STEP_DEFS.forEach(def=>{
const id=`${ext}_${def.id}`;
const div=document.createElement('div');
div.className='step';div.id=id;
div.innerHTML=`<div class="step-icon">○</div><div class="step-label">[${ext}] ${def.label}</div><div class="step-status"></div>`;
wrap.appendChild(div);stepEls[id]=div;
});
});
}
function setStep(id,state,statusText=''){
const el=stepEls[id];if(!el)return;
el.className=`step ${state}`;
el.querySelector('.step-icon').textContent=state==='running'?'↻':state==='done'?'✓':'✗';
el.querySelector('.step-status').textContent=statusText;
}
const BASE='https://www.call2all.co.il/ym/api/';
async function callUpdate(token,params){
const url=BASE+'UpdateExtension?'+new URLSearchParams({token,...params});
log(`→ UpdateExtension path=${params.path}`);
const res=await fetch(url);
const json=await res.json().catch(()=>({responseStatus:'ERROR',message:'parse error'}));
if(json.responseStatus==='OK'){log('← OK','log-ok');}
else{log(`← ERROR: ${json.message||JSON.stringify(json)}`,'log-err');throw new Error(json.message||'API error');}
}
async function uploadWav(token,path){
log(`→ UploadFile path=${path}`);
const blob=b64toBlob(WAV_B64,'audio/wav');
const fd=new FormData();
fd.append('token',token);fd.append('path',path);
fd.append('file',blob,path.split('/').pop());
const res=await fetch(BASE+'UploadFile',{method:'POST',body:fd});
const json=await res.json().catch(()=>({responseStatus:'ERROR',message:'parse error'}));
if(json.responseStatus==='OK'){log(`← OK (${json.size} bytes)`,'log-ok');}
else{log(`← ERROR: ${json.message||JSON.stringify(json)}`,'log-err');throw new Error(json.message||'Upload error');}
}
async function processExt(ext,token){
const e=ext.trim();
setStep(`${e}_ext1`,'running');
try{
await callUpdate(token,{path:`ivr2:${e}`,type:'add_id_to_list',title:'הקשת מספר לחיוג',
add_id_to_list_location_list:`/${e}/1/ext`,add_id_to_list_key:'api_add_2',
add_id_to_list_value_first:'contents=announce-position=no%0Aannounce-frequency=0%0Aperiodic-announce-frequency=0%0Aringuse=yes%0Amusicclass=ztomao%0A',
add_id_to_list_value_type:'digits',add_id_to_list_value_change:'yes',add_id_to_list_end_goto:'1'});
setStep(`${e}_ext1`,'done','200 OK');
}catch(err){setStep(`${e}_ext1`,'error',err.message);throw err;}
setStep(`${e}_ext2`,'running');
try{
await callUpdate(token,{path:`ivr2:${e}/1`,type:'api',title:'שינוי המספר לחיוג בפועל',
api_link:'https://www.call2all.co.il/ym/api/UploadTextFile',
api_add_0:`token=${token}`,api_add_1:`what=ivr2:/${e}/2/queue.ini`,
api_hangup_send:'no',api_end_goto:'../2'});
setStep(`${e}_ext2`,'done','200 OK');
}catch(err){setStep(`${e}_ext2`,'error',err.message);throw err;}
setStep(`${e}_ext3`,'running');
try{
await callUpdate(token,{path:`ivr2:${e}/2`,type:'routing_queue',title:'שיחות יוצאות',
queue_caller_id:'customer_did',queue_end_continue_goto:'hangup'});
setStep(`${e}_ext3`,'done','200 OK');
}catch(err){setStep(`${e}_ext3`,'error',err.message);throw err;}
setStep(`${e}_wav_root`,'running');
try{await uploadWav(token,`ivr2:${e}/M3411.wav`);setStep(`${e}_wav_root`,'done','uploaded');}
catch(err){setStep(`${e}_wav_root`,'error',err.message);throw err;}
setStep(`${e}_wav_sub`,'running');
try{await uploadWav(token,`ivr2:${e}/1/M1607.wav`);setStep(`${e}_wav_sub`,'done','uploaded');}
catch(err){setStep(`${e}_wav_sub`,'error',err.message);throw err;}
}
async function startAll(){
const extVal=document.getElementById('ext').value.trim();
const tokenVal=document.getElementById('token').value.trim();
if(!extVal||!tokenVal){alert('נא למלא מספר שלוחה וטוקן');return;}
if(!/^[\d/]+$/.test(extVal)){alert('מספר שלוחה יכול להכיל רק ספרות ו-/');return;}
const exts=extVal.split('/').map(s=>s.trim()).filter(Boolean);
document.getElementById('stepsWrap').style.display='flex';
document.getElementById('logWrap').style.display='block';
logEl=document.getElementById('log');logEl.innerHTML='';
buildSteps(exts);
const btn=document.getElementById('runBtn');btn.disabled=true;
log(`מתחיל עבור ${exts.length} שלוח${exts.length>1?'ות':'ה'}: ${exts.join(', ')}`,'log-info');
let ok=true;
for(const ext of exts){
log(`── שלוחה ${ext} ──`,'log-warn');
try{await processExt(ext,tokenVal);log(`✓ שלוחה ${ext} הושלמה`,'log-ok');}
catch(e){log(`✗ שלוחה ${ext} נכשלה: ${e.message}`,'log-err');ok=false;}
}
log(ok?'✓ הכל הושלם בהצלחה!':'⚠ חלק מהשלוחות נכשלו — בדוק את הלוג',ok?'log-ok':'log-err');
btn.disabled=false;
}
</script>
</body>
</html>
ולשמור כPDF