public/dev_tools.js
分割 10 / 10 · 元ファイル 1638〜1712行付近
listEl.appendChild(row);
});
});
}
function pick(){
return bbAll().then(function(l){
const any=Object.keys(sel).some(function(k){ return sel[k]; });
return any ? l.filter(function(r){ return sel[r.id]; }) : l;
});
}
function out(list, how){
if(!list.length){ toast('選ばれていません'); return; }
const txt=JSON.stringify({bundleVersion:1, at:new Date().toISOString(), reports:list});
const kb=Math.round(txt.length/102.4)/10;
if(how==='copy'){
if(navigator.clipboard && navigator.clipboard.writeText)
navigator.clipboard.writeText(txt).then(function(){ toast('コピーした('+kb+'KB)'); })
.catch(function(){ manualCopy(txt); });
else manualCopy(txt);
} else if(how==='share' && navigator.share){
const f=new File([txt], 'hzg_bug.json', {type:'application/json'});
const p=(navigator.canShare && navigator.canShare({files:[f]}))
? navigator.share({files:[f], title:'平成ゾンビ学園 バグ報告'})
: navigator.share({title:'平成ゾンビ学園 バグ報告', text:txt.slice(0,60000)});
p.catch(function(){ manualCopy(txt); });
} else {
const a=document.createElement('a');
a.href=URL.createObjectURL(new Blob([txt],{type:'application/json'}));
a.download='hzg_bug_'+new Date().toISOString().replace(/[:.]/g,'-').slice(0,19)+'.json';
document.body.appendChild(a); a.click();
setTimeout(function(){ URL.revokeObjectURL(a.href); a.remove(); }, 1000);
toast('保存した('+kb+'KB)');
}
}
function mkBtn(label, fn, bg){
const b=document.createElement('button'); b.textContent=label;
b.style.cssText='flex:1; min-width:86px; padding:9px 6px; border:0; border-radius:9px; font-weight:bold;'
+'background:'+(bg||'#28533f')+'; color:#f7f0dd;';
b.onclick=fn; foot.appendChild(b); return b;
}
/* サーバーへ送る(2026-08-28 K1指示。テスターの報告が端末に溜まるだけだったのを、
押した先でK1が読めるようにする)。宛先は同じCloudflareの /api/bug 。
成功したら「送った」と出す。圏外などで失敗しても端末の箱には残るので、後でもう一度送れる */
mkBtn('サーバーへ送る', function(){
pick().then(function(l){
if(!l.length){ toast('選ばれていません'); return; }
var ok=0, ng=0, done=0;
l.forEach(function(rep){
var body=JSON.stringify(Object.assign({}, rep, {
note:rep.memo||'', who:(function(){ try{ return localStorage.getItem('hzg_tester')||''; }catch(e){ return ''; } })(),
ua:navigator.userAgent
}));
fetch('/api/bug', {method:'POST', headers:{'content-type':'application/json'}, body:body})
.then(function(r){ if(r.ok) ok++; else ng++; })
.catch(function(){ ng++; })
.then(function(){ done++;
if(done===l.length) toast(ok+'件 送った'+(ng?(' / '+ng+'件 失敗'):''));
});
});
});
}, '#3d6ab4');
mkBtn('コピー', function(){ pick().then(function(l){ out(l,'copy'); }); });
mkBtn('ファイル保存', function(){ pick().then(function(l){ out(l,'file'); }); }, '#8a6d1c');
if(navigator.share) mkBtn('共有', function(){ pick().then(function(l){ out(l,'share'); }); }, '#3d6ab4');
mkBtn('全部消す', function(){
if(!confirm('全部消していい?')) return;
bbAll().then(function(l){ return Promise.all(l.map(function(r){ return bbDel(r.id); })); })
.then(function(){ bbRefresh(); draw(); });
}, '#7a2f23');
draw();
}
/* 起動時にボタンを出す(開発ツールが止まっていればここまで来ない) */
setTimeout(bbBuildBtn, 800);
})();