|
|
@@ -232,11 +232,12 @@
|
|
|
|
|
|
<script>
|
|
|
const $ = s => document.querySelector(s);
|
|
|
-let LIB = {characters:[],vfx:[],ui:[]}, ASSET="", TAB="chars";
|
|
|
+let LIB = {characters:[],vfx:[],ui:[]}, ASSET="", ASSET_VER=Date.now(), TAB="chars";
|
|
|
const animTargets = []; // {el, anim, start}
|
|
|
const ACTIVE_TASKS = new Set();
|
|
|
const esc = s => String(s ?? '').replace(/[&<>"']/g, m => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[m]));
|
|
|
const tasksFor = kind => ((LIB.tasks&&LIB.tasks[kind]) || []);
|
|
|
+const assetUrl = path => ASSET + path + (path.includes('?')?'&':'?') + 'v=' + ASSET_VER;
|
|
|
const taskKey = (kind,id) => `${kind}:${id}`;
|
|
|
function missingTasks(){
|
|
|
return ['characters','ui_art','vfx','ui'].flatMap(kind => tasksFor(kind)
|
|
|
@@ -253,7 +254,7 @@ async function loadManifest(){
|
|
|
async function loadLibrary(game){
|
|
|
const url = '/api/library' + (game?('?game='+encodeURIComponent(game)):'');
|
|
|
const lib = await (await fetch(url)).json();
|
|
|
- LIB = lib; ASSET = lib.assetBase || "";
|
|
|
+ LIB = lib; ASSET = lib.assetBase || ""; ASSET_VER = Date.now();
|
|
|
const sel = $('#gameSel'); sel.innerHTML='';
|
|
|
const games = [...(lib.games||[])];
|
|
|
const pending = lib.game && !games.includes(lib.game);
|
|
|
@@ -322,7 +323,7 @@ function renderChars(v){
|
|
|
const anims=Object.keys(animMap);
|
|
|
const card=document.createElement('div'); card.className='card '+(done?'':'missing')+(running?' running':'');
|
|
|
card.innerHTML=`
|
|
|
- <div class="stage">${done?`<img src="${ASSET+c.png}" alt="${esc(t.id)}">`:`<div class="placeholder">${running?'生成中…':'待生成'}<br>${esc(t.chineseName)}</div>`}</div>
|
|
|
+ <div class="stage">${done?`<img src="${assetUrl(c.png)}" alt="${esc(t.id)}">`:`<div class="placeholder">${running?'生成中…':'待生成'}<br>${esc(t.chineseName)}</div>`}</div>
|
|
|
<div class="task-head"><div><div class="name">${esc(t.chineseName)}</div><div class="meta">${esc(t.englishName)}</div></div>
|
|
|
<span class="task-status ${done?'done':(running?'running':'missing')}">${done?'已生成':(running?'生成中':'缺失')}</span></div>
|
|
|
${done&&anims.length?`<div class="row"><select>${anims.map(a=>`<option>${esc(a)}</option>`).join('')}</select></div>`:''}
|
|
|
@@ -351,7 +352,7 @@ function renderArt(v){
|
|
|
const running=ACTIVE_TASKS.has(taskKey('ui_art',t.id));
|
|
|
const card=document.createElement('div'); card.className='card '+(done?'':'missing')+(running?' running':'');
|
|
|
card.innerHTML=`
|
|
|
- <div class="stage">${done?`<img class="art-img" src="${ASSET+a.file}" alt="${esc(t.id)}">`:`<div class="placeholder">${running?'生成中…':'待生成'}<br>${esc(t.chineseName)}</div>`}</div>
|
|
|
+ <div class="stage">${done?`<img class="art-img" src="${assetUrl(a.file)}" alt="${esc(t.id)}">`:`<div class="placeholder">${running?'生成中…':'待生成'}<br>${esc(t.chineseName)}</div>`}</div>
|
|
|
<div class="task-head"><div><div class="name">${esc(t.chineseName)}</div><div class="meta">${esc(t.englishName)}</div></div>
|
|
|
<span class="task-status ${done?'done':(running?'running':'missing')}">${done?'已生成':(running?'生成中':'缺失')}</span></div>
|
|
|
<div class="meta">${done?`${a.w}×${a.h}px · ${a.transparent?'透明素材':'整图背景'}`:`${esc(t.size||'')} · ${t.transparent?'透明素材':'整图背景'}`}<br>
|
|
|
@@ -804,7 +805,8 @@ async function pollJob(jobId, log, btn, runningItems=[]){
|
|
|
if(d.status==='error'){
|
|
|
markTasksRunning(runningItems, false);
|
|
|
ACTIVE_TASKS.clear();
|
|
|
- render();
|
|
|
+ await loadLibrary(d.game || $('#gameSel').value);
|
|
|
+ opMsg('任务结束但有错误,已自动刷新资源库;成功的素材已经显示。', false);
|
|
|
if(btn) btn.disabled=false;
|
|
|
$('#retryMissingBtn').disabled=false;
|
|
|
return;
|