mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 17:04:46 +00:00
feat: GPS прибытие на объект + документы (бриф/планировка) у замерщика
This commit is contained in:
parent
b9783adc82
commit
f415f9df03
@ -277,6 +277,51 @@ function render(id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── GPS: прибытие на объект замера ────────────────────────────────────────────
|
||||||
|
var _MSR_GPS_RADIUS = 300; // метров
|
||||||
|
var _MSR_JOBS = {
|
||||||
|
'З-1042': {addr:'ул. Рубинштейна, 7, кв. 18', lat:59.9295, lng:30.3426}
|
||||||
|
};
|
||||||
|
window._MSR_GPS = {};
|
||||||
|
window._MSR_GPS_DEMO = 'near';
|
||||||
|
|
||||||
|
function _msrGpsDist(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 _msrFmt(m){ return m<1000?(m+' м'):(m/1000).toFixed(1)+' км'; }
|
||||||
|
function _msrGpsResult(jobId,dist){
|
||||||
|
var ok=dist<=_MSR_GPS_RADIUS;
|
||||||
|
window._MSR_GPS[jobId]={ok:ok,dist:dist};
|
||||||
|
document.getElementById('screen').innerHTML=render('order_detail');
|
||||||
|
}
|
||||||
|
function _msrGpsRequest(jobId){
|
||||||
|
window._MSR_GPS[jobId]='loading';
|
||||||
|
document.getElementById('screen').innerHTML=render('order_detail');
|
||||||
|
var job=_MSR_JOBS[jobId];
|
||||||
|
function onGot(lat,lng){ _msrGpsResult(jobId,_msrGpsDist(lat,lng,job.lat,job.lng)); }
|
||||||
|
function onFail(){ _msrGpsResult(jobId, window._MSR_GPS_DEMO==='near'?54:1510); }
|
||||||
|
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 _msrGpsForce(jobId){
|
||||||
|
var prev=window._MSR_GPS[jobId];
|
||||||
|
window._MSR_GPS[jobId]={ok:false,dist:prev&&prev.dist||0,forced:true};
|
||||||
|
document.getElementById('screen').innerHTML=render('order_detail');
|
||||||
|
}
|
||||||
|
function _msrGpsCancelCheck(jobId){
|
||||||
|
window._MSR_GPS[jobId]=null;
|
||||||
|
document.getElementById('screen').innerHTML=render('order_detail');
|
||||||
|
}
|
||||||
|
|
||||||
/* ─── HOME ─── */
|
/* ─── HOME ─── */
|
||||||
function screenHome() {
|
function screenHome() {
|
||||||
return `<div class="page">
|
return `<div class="page">
|
||||||
@ -415,13 +460,39 @@ function screenOrderDetail() {
|
|||||||
</div>
|
</div>
|
||||||
${stepBar('order_detail')}
|
${stepBar('order_detail')}
|
||||||
|
|
||||||
<div style="background:var(--warn);padding:10px 16px;display:flex;align-items:center;gap:8px">
|
${(function(){
|
||||||
<span style="font-size:18px">⏱</span>
|
var jobId='З-1042';
|
||||||
<div>
|
var gst=window._MSR_GPS[jobId];
|
||||||
<div style="font-size:13px;font-weight:700;color:#fff">В процессе · начато в 10:35</div>
|
if(!gst){
|
||||||
<div style="font-size:12px;color:rgba(255,255,255,.8)">Прошло 47 минут</div>
|
return '<div style="background:#F0FDF4;border-bottom:1.5px solid #86EFAC;padding:12px 16px">'
|
||||||
</div>
|
+'<div style="font-size:12px;color:#059669;font-weight:700;margin-bottom:6px">📍 Подтвердите прибытие на объект</div>'
|
||||||
</div>
|
+'<div style="font-size:12px;color:var(--muted);margin-bottom:10px">ул. Рубинштейна, 7, кв. 18 · Смирнова Ольга</div>'
|
||||||
|
+'<button onclick="_msrGpsRequest(\'З-1042\')" style="width:100%;padding:10px;border-radius:10px;border:none;background:#16A34A;color:#fff;font-size:13px;font-weight:700;cursor:pointer">📍 Я на месте</button>'
|
||||||
|
+'<div style="margin-top:7px;font-size:10px;color:#94A3B8">Демо: '
|
||||||
|
+'<span onclick="window._MSR_GPS_DEMO=\'near\';document.getElementById(\'screen\').innerHTML=render(\'order_detail\')" style="cursor:pointer;font-weight:700;color:'+(window._MSR_GPS_DEMO==='near'?'#16A34A':'#94A3B8')+'">Рядом</span> · '
|
||||||
|
+'<span onclick="window._MSR_GPS_DEMO=\'far\';document.getElementById(\'screen\').innerHTML=render(\'order_detail\')" style="cursor:pointer;font-weight:700;color:'+(window._MSR_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">⚠️ Вы в '+_msrFmt(gst.dist)+' от объекта</div>'
|
||||||
|
+'<div style="font-size:12px;color:var(--muted);margin-bottom:10px">ул. Рубинштейна, 7 · Допустимый радиус: 300 м</div>'
|
||||||
|
+'<div style="display:flex;gap:8px">'
|
||||||
|
+'<button onclick="_msrGpsForce(\'З-1042\')" 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="_msrGpsCancelCheck(\'З-1042\')" 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 {
|
||||||
|
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">В процессе · начато в 10:35'+chip+'</div>'
|
||||||
|
+'<div style="font-size:12px;color:rgba(255,255,255,.8)">Прошло 47 минут</div></div></div>';
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
|
||||||
<div style="padding:12px 16px 0">
|
<div style="padding:12px 16px 0">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@ -442,6 +513,21 @@ function screenOrderDetail() {
|
|||||||
<div class="info-row"><span class="info-label">Состояние</span><span class="info-val">После ремонта</span></div>
|
<div class="info-row"><span class="info-label">Состояние</span><span class="info-val">После ремонта</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Документы к заявке -->
|
||||||
|
<div class="card">
|
||||||
|
<div style="font-size:13px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:10px">Документы</div>
|
||||||
|
<div style="display:flex;gap:7px">
|
||||||
|
<a href="#" onclick="event.preventDefault();alert('📋 Бриф клиента…\\nВ продакшне — открытие из облака')" style="flex:1;display:flex;align-items:center;gap:6px;padding:9px 10px;background:#EFF6FF;border:1px solid #BFDBFE;border-radius:10px;text-decoration:none">
|
||||||
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#1D4ED8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="9" y1="13" x2="15" y2="13"/><line x1="9" y1="17" x2="13" y2="17"/></svg>
|
||||||
|
<div><div style="font-size:11px;font-weight:700;color:#1D4ED8">Бриф клиента</div><div style="font-size:10px;color:#93C5FD">PDF · 0.8 МБ</div></div>
|
||||||
|
</a>
|
||||||
|
<a href="#" onclick="event.preventDefault();alert('📐 Планировка квартиры…\\nВ продакшне — открытие из облака')" style="flex:1;display:flex;align-items:center;gap:6px;padding:9px 10px;background:#F0FDF4;border:1px solid #BBF7D0;border-radius:10px;text-decoration:none">
|
||||||
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#15803D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="3" y1="9" x2="21" y2="9"/></svg>
|
||||||
|
<div><div style="font-size:11px;font-weight:700;color:#15803D">Планировка</div><div style="font-size:10px;color:#86EFAC">PDF · 3 листа</div></div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card" style="background:var(--bg)">
|
<div class="card" style="background:var(--bg)">
|
||||||
<div style="font-size:13px;color:var(--muted);margin-bottom:4px;font-weight:600">Примечание менеджера</div>
|
<div style="font-size:13px;color:var(--muted);margin-bottom:4px;font-weight:600">Примечание менеджера</div>
|
||||||
<div style="font-size:14px;color:var(--ink);line-height:1.5">Клиент хочет угловую кухню 2,8×3,8 м. Уточнить расположение розеток и вентиляции. Есть ниша под холодильник — обязательно замерить.</div>
|
<div style="font-size:14px;color:var(--ink);line-height:1.5">Клиент хочет угловую кухню 2,8×3,8 м. Уточнить расположение розеток и вентиляции. Есть ниша под холодильник — обязательно замерить.</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user