feat(nav): reorganize targets = picked crates sorted (editable) + per-crate landing summary
Sources stay the pick-ordered crates; targets default to those same real crate IDs sorted ascending (4,3,2,1 → pour A–Z into 1,2,3,4), shown in an editable field so you can consolidate/spread. Plan now shows where items land per crate. Drops the Start+Count inputs (which could target non-existent crate IDs and orphan items). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
c4b544373d
commit
6b679152bc
@ -408,10 +408,9 @@ function toolReorg(){ return `<div class="panel">
|
||||
<div class="muted">🎯 Filters</div>
|
||||
<div class="bar" style="flex-wrap:wrap;margin-top:4px"><span class="muted">Price ≤</span><input id="roPmax" type="number" style="width:70px">
|
||||
<span class="muted">Year</span><input id="roYmin" type="number" placeholder="min" style="width:60px"><input id="roYmax" type="number" placeholder="max" style="width:60px"></div>
|
||||
<div class="muted" style="margin-top:10px">📦 Distribution Target</div>
|
||||
<div class="bar" style="flex-wrap:wrap;margin-top:4px"><span class="muted">Start</span><input id="roStart" type="number" style="width:72px">
|
||||
<span class="muted">Count</span><input id="roCount" type="number" value="1" style="width:52px">
|
||||
<span class="muted">Slots</span><input id="roSlots" type="number" value="50" style="width:52px">
|
||||
<div class="muted" style="margin-top:10px">📦 Distribution Target <span class="muted">— sorted A–Z, poured into these crates in order</span></div>
|
||||
<div class="bar" style="flex-wrap:wrap;margin-top:4px"><span class="muted">Target crates</span><input id="roTargets" placeholder="auto from picks — e.g. 1, 2, 3, 4" style="flex:1;min-width:130px">
|
||||
<span class="muted">Slots/crate</span><input id="roSlots" type="number" value="50" style="width:56px">
|
||||
<select id="roSort"><option value="artist">Artist A–Z</option><option value="title">Title A–Z</option><option value="year_asc">Year ↑</option><option value="year_desc">Year ↓</option><option value="price_asc">Price ↑</option><option value="price_desc">Price ↓</option></select>
|
||||
<button class="ghost" onclick="reorgPlan()">Plan</button></div>
|
||||
<div id="roPlanOut" style="margin-top:8px;max-height:40vh;overflow:auto"></div>
|
||||
@ -432,7 +431,8 @@ async function reorgScan(){
|
||||
ST.pick=ids; renderPick();
|
||||
const d=await post('/nav/reorg/scan',{crate_ids:ids}); roItems=d.items||[];
|
||||
$('#roScanOut').innerHTML=`<b>${d.count}</b> items · ${ids.length} crate(s)`;
|
||||
$('#roStart').value=ids[0]; $('#roCount').value=ids.length; $('#roPlanArea').style.display='block';
|
||||
// targets default to the picked crates sorted ascending (4,3,2,1 → fill 1,2,3,4) — editable
|
||||
$('#roTargets').value=[...new Set(ids)].sort((a,b)=>a-b).join(', '); $('#roPlanArea').style.display='block';
|
||||
}
|
||||
function roCmp(m){ return (a,b)=>{
|
||||
if(m==='title') return (a.title||'').localeCompare(b.title||'');
|
||||
@ -445,15 +445,19 @@ function reorgPlan(){
|
||||
const pmax=parseFloat($('#roPmax').value)||null, ymin=parseInt($('#roYmin').value)||null, ymax=parseInt($('#roYmax').value)||null;
|
||||
let items=roItems.filter(i=> (pmax==null||(i.price!=null&&i.price<=pmax)) && (ymin==null||(i.year&&i.year>=ymin)) && (ymax==null||(i.year&&i.year<=ymax)) );
|
||||
items.sort(roCmp($('#roSort').value));
|
||||
const start=parseInt($('#roStart').value), count=parseInt($('#roCount').value)||1, slots=parseInt($('#roSlots').value)||50;
|
||||
const targets=[]; for(let i=0;i<count;i++) targets.push(start+i); // distribute into start..start+count-1
|
||||
const slots=parseInt($('#roSlots').value)||50;
|
||||
const targets=($('#roTargets').value.match(/\d+/g)||[]).map(Number); // real crate IDs (default = sorted picks)
|
||||
if(!targets.length){ $('#roPlanOut').innerHTML='<div class="oos">set at least one target crate</div>'; return; }
|
||||
roMoves=[]; roLeftovers=[]; let ti=0, slot=1;
|
||||
for(const it of items){
|
||||
if(ti>=targets.length){ roLeftovers.push(it); continue; }
|
||||
roMoves.push({sku:it.sku, new_crate_id:targets[ti], new_slot:slot, title:it.title, artist:it.artist, from:`${it.crate_id||'—'}/${it.slot||'—'}`});
|
||||
slot++; if(slot>slots){ slot=1; ti++; }
|
||||
}
|
||||
$('#roPlanOut').innerHTML=`<div class="bar" style="justify-content:space-between"><b>${roMoves.length} → crates ${targets.join(', ')}${roLeftovers.length?' · '+roLeftovers.length+' leftover':''}</b><button class="prim" onclick="reorgApply()">Apply</button></div>`
|
||||
const perT={}; roMoves.forEach(m=>perT[m.new_crate_id]=(perT[m.new_crate_id]||0)+1);
|
||||
const summary=targets.map(t=>`<b class="pink">${t}</b>: ${perT[t]||0}`).join(' · ');
|
||||
$('#roPlanOut').innerHTML=`<div class="bar" style="justify-content:space-between"><b>${roMoves.length} items${roLeftovers.length?' · '+roLeftovers.length+' leftover (need more crates)':''}</b><button class="prim" onclick="reorgApply()">Apply</button></div>`
|
||||
+`<div class="muted" style="margin:4px 0">into → ${summary}</div>`
|
||||
+'<table style="margin-top:6px"><thead><tr><th>→ Crate/Slot</th><th>Title</th><th>Artist</th><th>From</th></tr></thead><tbody>'
|
||||
+roMoves.slice(0,300).map(m=>`<tr><td class="pink">${m.new_crate_id} / ${m.new_slot}</td><td>${esc(m.title||m.sku)}</td><td class="muted">${esc(m.artist||'')}</td><td class="muted">${esc(m.from)}</td></tr>`).join('')
|
||||
+(roMoves.length>300?`<tr><td colspan=4 class=muted>…+${roMoves.length-300} more</td></tr>`:'')+'</tbody></table>';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user