mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 16:44:46 +00:00
feat: GPS прибытие на объект у сборщика (матч по адресу клиента)
This commit is contained in:
parent
cd5d5223b0
commit
64c7d18e2c
@ -447,6 +447,52 @@ function render(id) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── GPS: прибытие на объект сборки ────────────────────────────────────────────
|
||||
var _ASM_GPS_RADIUS = 300; // метров — у клиента адрес уличный, допуск больше чем у салона
|
||||
var _ASM_JOBS = {
|
||||
'А-2847': {addr:'ул. Ленина, 45', lat:59.9548, lng:30.3158},
|
||||
'А-2851': {addr:'пр. Победы, 88', lat:59.8695, lng:30.2867}
|
||||
};
|
||||
window._ASM_GPS = {}; // jobId → null | 'loading' | {ok,dist,forced}
|
||||
window._ASM_GPS_DEMO = 'near'; // 'near' | 'far'
|
||||
|
||||
function _asmGpsDist(la1,lo1,la2,lo2){
|
||||
var R=6371000,dL=(la2-la1)*Math.PI/180,dG=(lo2-lo1)*Math.PI/180;
|
||||
var a=Math.sin(dL/2)*Math.sin(dL/2)+Math.cos(la1*Math.PI/180)*Math.cos(la2*Math.PI/180)*Math.sin(dG/2)*Math.sin(dG/2);
|
||||
return Math.round(R*2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a)));
|
||||
}
|
||||
function _asmFmt(m){ return m<1000?(m+' м'):(m/1000).toFixed(1)+' км'; }
|
||||
function _asmGpsResult(jobId,dist){
|
||||
var ok=dist<=_ASM_GPS_RADIUS;
|
||||
window._ASM_GPS[jobId]={ok:ok,dist:dist};
|
||||
document.getElementById('screen').innerHTML=render('asm_detail');
|
||||
}
|
||||
function _asmGpsRequest(jobId){
|
||||
window._ASM_GPS[jobId]='loading';
|
||||
document.getElementById('screen').innerHTML=render('asm_detail');
|
||||
var job=_ASM_JOBS[jobId];
|
||||
function onGot(lat,lng){ _asmGpsResult(jobId,_asmGpsDist(lat,lng,job.lat,job.lng)); }
|
||||
function onFail(){ _asmGpsResult(jobId, window._ASM_GPS_DEMO==='near'?62:1380); }
|
||||
var tg=window.Telegram&&Telegram.WebApp;
|
||||
if(tg&&tg.LocationManager&&tg.LocationManager.isInited){
|
||||
tg.LocationManager.getLocation(function(r){ r&&r.latitude?onGot(r.latitude,r.longitude):onFail(); });
|
||||
} else if(navigator.geolocation){
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
function(p){ onGot(p.coords.latitude,p.coords.longitude); },
|
||||
onFail,{timeout:8000,maximumAge:15000}
|
||||
);
|
||||
} else { onFail(); }
|
||||
}
|
||||
function _asmGpsForce(jobId){
|
||||
var prev=window._ASM_GPS[jobId];
|
||||
window._ASM_GPS[jobId]={ok:false,dist:prev&&prev.dist||0,forced:true};
|
||||
document.getElementById('screen').innerHTML=render('asm_detail');
|
||||
}
|
||||
function _asmGpsCancelCheck(jobId){
|
||||
window._ASM_GPS[jobId]=null;
|
||||
document.getElementById('screen').innerHTML=render('asm_detail');
|
||||
}
|
||||
|
||||
/* ─── BOTTOM SHEET ─── */
|
||||
function showSheet(d) {
|
||||
const existing = document.getElementById('bottomSheet');
|
||||
@ -650,13 +696,43 @@ function screenAsmDetail() {
|
||||
<div class="header-action"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></div>
|
||||
</div>
|
||||
|
||||
<div style="background:var(--warn);padding:10px 16px;display:flex;align-items:center;gap:8px">
|
||||
<span style="font-size:18px">⏱</span>
|
||||
<div>
|
||||
<div style="font-size:13px;font-weight:700;color:#fff">В процессе · 4 из 7 позиций</div>
|
||||
<div style="font-size:12px;color:rgba(255,255,255,.8)">Начато в 10:15 · прошло 1ч 43мин</div>
|
||||
</div>
|
||||
</div>
|
||||
${(function(){
|
||||
var jobId='А-2847';
|
||||
var gst=window._ASM_GPS[jobId];
|
||||
if(!gst){
|
||||
// Ещё не прибыл
|
||||
return '<div style="background:#F0FDF4;border-bottom:1.5px solid #86EFAC;padding:12px 16px">'
|
||||
+'<div style="font-size:12px;color:#059669;font-weight:700;margin-bottom:8px">📍 Подтвердите прибытие на объект</div>'
|
||||
+'<div style="font-size:12px;color:var(--muted);margin-bottom:10px">ул. Ленина, 45, кв. 12 · Иванов Дмитрий</div>'
|
||||
+'<div style="display:flex;gap:8px;align-items:center">'
|
||||
+'<button onclick="_asmGpsRequest(\'А-2847\')" style="flex:1;padding:10px;border-radius:10px;border:none;background:#16A34A;color:#fff;font-size:13px;font-weight:700;cursor:pointer">📍 Я на месте</button>'
|
||||
+'</div>'
|
||||
+'<div style="margin-top:8px;font-size:10px;color:#94A3B8">Демо: '
|
||||
+'<span onclick="window._ASM_GPS_DEMO=\'near\';document.getElementById(\'screen\').innerHTML=render(\'asm_detail\')" style="cursor:pointer;font-weight:700;color:'+(window._ASM_GPS_DEMO==='near'?'#16A34A':'#94A3B8')+'">Рядом</span> · '
|
||||
+'<span onclick="window._ASM_GPS_DEMO=\'far\';document.getElementById(\'screen\').innerHTML=render(\'asm_detail\')" style="cursor:pointer;font-weight:700;color:'+(window._ASM_GPS_DEMO==='far'?'#DC2626':'#94A3B8')+'">Далеко</span></div>'
|
||||
+'</div>';
|
||||
} else if(gst==='loading'){
|
||||
return '<div style="background:#F8FAFC;border-bottom:1px solid #E2E8F0;padding:14px 16px;text-align:center;font-size:14px;color:var(--muted);font-weight:600">'
|
||||
+'<span style="display:inline-block;animation:spin 1s linear infinite;margin-right:8px">⏱</span>Определяем местоположение…</div>';
|
||||
} else if(gst&&!gst.ok&&!gst.forced){
|
||||
return '<div style="background:rgba(245,158,11,.1);border-bottom:1.5px solid rgba(245,158,11,.4);padding:13px 16px">'
|
||||
+'<div style="font-size:13px;font-weight:700;color:var(--warn);margin-bottom:4px">⚠️ Вы в '+_asmFmt(gst.dist)+' от объекта</div>'
|
||||
+'<div style="font-size:12px;color:var(--muted);margin-bottom:10px">ул. Ленина, 45 · Допустимый радиус: 300 м</div>'
|
||||
+'<div style="display:flex;gap:8px">'
|
||||
+'<button onclick="_asmGpsForce(\'А-2847\')" style="flex:1;padding:9px;border-radius:10px;border:none;background:#F59E0B;color:#fff;font-size:13px;font-weight:700;cursor:pointer">Отметить всё равно</button>'
|
||||
+'<button onclick="_asmGpsCancelCheck(\'А-2847\')" style="padding:9px 14px;border-radius:10px;border:1px solid #E2E8F0;background:transparent;font-size:13px;font-weight:600;color:var(--muted);cursor:pointer">Отмена</button>'
|
||||
+'</div></div>';
|
||||
} else {
|
||||
// Прибыл (ok или forced)
|
||||
var chip = gst.forced
|
||||
? '<span style="font-size:10px;background:rgba(245,158,11,.2);color:#D97706;border-radius:6px;padding:1px 6px;font-weight:700;margin-left:6px">⚡ вручную</span>'
|
||||
: '<span style="font-size:10px;background:rgba(22,163,74,.15);color:#16A34A;border-radius:6px;padding:1px 6px;font-weight:700;margin-left:6px">GPS ✓</span>';
|
||||
return '<div style="background:var(--warn);padding:10px 16px;display:flex;align-items:center;gap:8px">'
|
||||
+'<span style="font-size:18px">⏱</span>'
|
||||
+'<div><div style="font-size:13px;font-weight:700;color:#fff;display:flex;align-items:center">В процессе · 4 из 7 позиций'+chip+'</div>'
|
||||
+'<div style="font-size:12px;color:rgba(255,255,255,.8)">Начато в 10:15 · прошло 1ч 43мин</div></div></div>';
|
||||
}
|
||||
})()}
|
||||
|
||||
<div style="padding:12px 16px 0">
|
||||
<div class="card">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user