|
|
@@ -246,15 +246,23 @@ function missingTasks(){
|
|
|
function markTasksRunning(items, running=true){
|
|
|
items.forEach(t=>running?ACTIVE_TASKS.add(taskKey(t.kind,t.id)):ACTIVE_TASKS.delete(taskKey(t.kind,t.id)));
|
|
|
}
|
|
|
+function syncRunningWithLibrary(){
|
|
|
+ for(const key of [...ACTIVE_TASKS]){
|
|
|
+ const [kind,id] = key.split(':');
|
|
|
+ const row = tasksFor(kind).find(t=>t.id===id);
|
|
|
+ if(row && row.status==='done') ACTIVE_TASKS.delete(key);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
// ---------- 拉取默认 manifest & 资源库 ----------
|
|
|
async function loadManifest(){
|
|
|
try{ const t = await (await fetch('/api/manifest')).text(); $('#manifest').value = t; }catch(e){}
|
|
|
}
|
|
|
-async function loadLibrary(game){
|
|
|
+async function loadLibrary(game, opts={}){
|
|
|
const url = '/api/library' + (game?('?game='+encodeURIComponent(game)):'');
|
|
|
const lib = await (await fetch(url)).json();
|
|
|
LIB = lib; ASSET = lib.assetBase || ""; ASSET_VER = Date.now();
|
|
|
+ syncRunningWithLibrary();
|
|
|
const sel = $('#gameSel'); sel.innerHTML='';
|
|
|
const games = [...(lib.games||[])];
|
|
|
const pending = lib.game && !games.includes(lib.game);
|
|
|
@@ -262,16 +270,18 @@ async function loadLibrary(game){
|
|
|
games.forEach(g=>{ const o=document.createElement('option');
|
|
|
o.value=g;o.textContent=g+(pending&&g===lib.game?'(待生成)':''); if(g===lib.game)o.selected=true; sel.appendChild(o); });
|
|
|
if(!games.length){ const o=document.createElement('option');o.textContent='(暂无)';sel.appendChild(o); }
|
|
|
- if(pending) opMsg(`已载入 ${lib.game} 的 manifest,但还没有图片资源;点“开始生成”后才会进入资源库。`, false);
|
|
|
- if(lib.taskSummary && !pending){
|
|
|
- opMsg(`任务 ${lib.taskSummary.done}/${lib.taskSummary.total} 已完成,缺失 ${lib.taskSummary.missing} 个。`, lib.taskSummary.missing===0);
|
|
|
+ if(!opts.silent){
|
|
|
+ if(pending) opMsg(`已载入 ${lib.game} 的 manifest,但还没有图片资源;点“开始生成”后才会进入资源库。`, false);
|
|
|
+ if(lib.taskSummary && !pending){
|
|
|
+ opMsg(`任务 ${lib.taskSummary.done}/${lib.taskSummary.total} 已完成,缺失 ${lib.taskSummary.missing} 个。`, lib.taskSummary.missing===0);
|
|
|
+ }
|
|
|
}
|
|
|
$('#retryMissingBtn').disabled = !lib.taskSummary || !lib.taskSummary.missing || ACTIVE_TASKS.size>0;
|
|
|
const boss = lib.slot_config && lib.slot_config.boss;
|
|
|
if(boss && boss.enabled){
|
|
|
const bossId = boss.id || 'boss_demon_lord';
|
|
|
const hasBoss = (lib.characters||[]).some(c=>c.id===bossId);
|
|
|
- if(!hasBoss) opMsg(`当前资源库缺少关主大魔王 ${bossId},在角色库任务卡片点“补生成 / 重试”即可继续。`, false);
|
|
|
+ if(!hasBoss && !opts.silent) opMsg(`当前资源库缺少关主大魔王 ${bossId},在角色库任务卡片点“补生成 / 重试”即可继续。`, false);
|
|
|
}
|
|
|
render();
|
|
|
}
|
|
|
@@ -778,6 +788,7 @@ $('#startBtn').onclick=async()=>{
|
|
|
|
|
|
async function pollJob(jobId, log, btn, runningItems=[]){
|
|
|
let lastText='';
|
|
|
+ let lastRefresh=0;
|
|
|
while(true){
|
|
|
let d;
|
|
|
try{
|
|
|
@@ -795,6 +806,11 @@ async function pollJob(jobId, log, btn, runningItems=[]){
|
|
|
if((d.logs||[]).length){
|
|
|
opMsg((d.status==='running'?'生成中:':'任务状态:') + d.logs[d.logs.length-1], d.status!=='error');
|
|
|
}
|
|
|
+ const now=Date.now();
|
|
|
+ if(d.status==='running' && d.game && now-lastRefresh>2500){
|
|
|
+ lastRefresh=now;
|
|
|
+ await loadLibrary(d.game, {silent:true});
|
|
|
+ }
|
|
|
if(d.status==='done'){
|
|
|
markTasksRunning(runningItems, false);
|
|
|
ACTIVE_TASKS.clear();
|