/* HQ screens: CoverSheet, Assignment */ // ================= Cover Sheet ================= function groupJobs(jobs, by){ if (by==='none') return [{ key:'all', label:'รายการทั้งหมด', jobs }]; const m = new Map(); jobs.forEach(j=>{ let key, label; if (by==='branch'){ const b=CK.branch(j.branch); key=j.branch; label=`${b?.code} ${b?.name}`; } else if (by==='district'){ key=j.district; label=`อ.${j.district}`; } else { const t=CK.team(j.team); key=j.team||'none'; label=t?t.name:'ยังไม่มอบหมายช่าง'; } if(!m.has(key)) m.set(key,{key,label,jobs:[]}); m.get(key).jobs.push(j); }); return [...m.values()]; } function CoverSheetScreen(){ const { jobs, toast, device } = useCK(); const isMobile = device==='mobile'; const [date,setDate] = React.useState(CK.TODAY); const [by,setBy] = React.useState('district'); const dayJobs = sortQueue(jobs.filter(j=>j.date===date && j.status!=='cancelled')); const groups = groupJobs(dayJobs, by); const s = computeSummary(dayJobs); const byOpts = [['district','อำเภอ'],['branch','สาขา'],['team','ทีมช่าง'],['none','ไม่จัดกลุ่ม']]; return (
{isMobile ?

ใบปะหน้ารายวัน

: toast('กำลังส่งออก Excel (.xlsx)','success')}>Excel toast('กำลังส่งออก PDF','success')}>PDF window.print()}>พิมพ์ }
จัดกลุ่มตาม
{byOpts.map(([k,l])=>( ))}
{/* PRINT AREA */}
); } // ================= Assignment ================= function TeamColumn({ team, jobs, onDrop, onUnassign, dragMethod }){ const [over,setOver] = React.useState(false); const load = Math.round(jobs.reduce((s,j)=>s+CK.jobUnits(j),0)*10)/10; const pct = Math.min(100, Math.round(load/team.capacity*100)); const stat = pct>=100?'full':pct>=80?'almost':'open'; const sc = CK.DAYSTATUS[stat]; return (
{e.preventDefault();setOver(true);}:undefined} onDragLeave={dragMethod?()=>setOver(false):undefined} onDrop={dragMethod?e=>{e.preventDefault();setOver(false);onDrop(e.dataTransfer.getData('id'));}:undefined} className={`rounded-2xl ring-1 transition flex flex-col ${over?'ring-2 ring-brand-500 bg-brand-50/40':'ring-slate-200 bg-white'}`}>
{team.name}
{team.zone}
{load}/{team.capacity}
{jobs.length===0 &&
{dragMethod?'ลากงานมาวางที่นี่':'ยังไม่มีงาน'}
} {jobs.map(j=>(
{j.customer}
อ.{j.district} · {itemsShort(j.items)}
))}
); } function AssignScreen(){ const { jobs, assign, updateJob, tweaks, toast, device } = useCK(); const isMobile = device==='mobile'; const [date,setDate] = React.useState(CK.TODAY); const dragMethod = tweaks.assignMethod==='drag'; const [sel,setSel] = React.useState(null); // selected pool job (select mode) const dayJobs = jobs.filter(j=>j.date===date && j.status!=='cancelled'); const pool = sortQueue(dayJobs.filter(j=>!j.team)); const byTeam = id => dayJobs.filter(j=>j.team===id); function doAssign(jobId, teamId){ assign(jobId, teamId); setSel(null); toast('มอบหมายงานให้ทีมช่างแล้ว','success'); } function unassign(jobId){ updateJob(jobId,{team:null, status:'ready'}); } return (
{isMobile ?

มอบหมายงานช่าง

: } {isMobile && }
{/* Pool */}
งานรอมอบหมาย {pool.length}
{pool.length===0 && } {pool.map(j=>(
e.dataTransfer.setData('id',j.id):undefined} onClick={!dragMethod?()=>setSel(sel===j.id?null:j.id):undefined} className={`rounded-xl p-2.5 ring-1 transition ${dragMethod?'cursor-grab active:cursor-grabbing':'cursor-pointer'} ${sel===j.id?'ring-2 ring-brand-500 bg-brand-50':'ring-slate-200 bg-white hover:ring-brand-300'}`}>
{dragMethod && }
{j.customer}{j.urgency==='urgent'&&}
อ.{j.district} · {CK.jobType(j.jobType)?.th} · {itemsShort(j.items)}
{!dragMethod && sel===j.id && (
{CK.TEAMS.map(t=>( ))}
)}
))}
{/* Teams */}
{CK.TEAMS.map(t=>( doAssign(id,t.id)} onUnassign={unassign} /> ))}
); } Object.assign(window, { CoverSheetScreen, AssignScreen, groupJobs });