更新后端新增内容

This commit is contained in:
super
2026-03-26 16:42:25 +08:00
parent 21c6f41c69
commit 32a9494dd6
63 changed files with 1943 additions and 415 deletions

View File

@@ -1,9 +1,9 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>亚马逊 - 南日AI</title>
<title>浜氶┈閫?- 鍗楁棩AI</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
@@ -38,7 +38,7 @@
}
.btn-home:hover { color: #fff; background: #2a2a2a; }
/* 顶部栏目导航(容器化,便于后续增加栏目) */
/* 椤堕儴鏍忕洰瀵艰埅锛堝鍣ㄥ寲锛屼究浜庡悗缁鍔犳爮鐩級 */
.nav-tabs {
display: flex;
align-items: center;
@@ -87,7 +87,7 @@
display: flex;
height: calc(100vh - 56px);
}
/* 栏目内容容器:每个栏目一个 .tab-panel,通过 data-panel 与导航对应 */
/* 鏍忕洰鍐呭瀹瑰櫒锛氭瘡涓爮鐩竴涓?.tab-panel锛岄€氳繃 data-panel 涓庡鑸搴?*/
.tab-panel {
display: none;
flex: 1;
@@ -338,87 +338,87 @@
<body>
<header class="top-bar">
<div class="logo-area">
<span class="app-name">南日AI-亚马逊</span>
<a href="/home" class="btn-home">返回首页</a>
<span class="app-name">鍗楁棩AI-浜氶┈閫?/span>
<a href="/home" class="btn-home">杩斿洖棣栭〉</a>
</div>
<nav class="nav-tabs">
<span class="nav-tab-group">
<button type="button" class="nav-tab active" data-panel="brandCheck">品牌检测</button>
<button type="button" class="nav-tab" onclick="window.location='/new_web_source/dedupe.html'">总数据去重</button>
<button type="button" class="nav-tab" onclick="window.location='/new_web_source/convert.html'">格式转换</button>
<button type="button" class="nav-tab" onclick="window.location='/new_web_source/split.html'">表格拆分</button>
<!-- 后续增加栏目时在此添加,例如:<button type="button" class="nav-tab" data-panel="other">其他栏目</button> -->
<button type="button" class="nav-tab active" data-panel="brandCheck">鍝佺墝妫€娴?/button>
<button type="button" class="nav-tab" onclick="window.location='/new_web_source/dedupe.html'">鎬绘暟鎹幓閲?/button>
<button type="button" class="nav-tab" onclick="window.location='/new_web_source/convert.html'">鏍煎紡杞崲</button>
<button type="button" class="nav-tab" onclick="window.location='/new_web_source/split.html'">琛ㄦ牸鎷嗗垎</button>
<!-- 鍚庣画澧炲姞鏍忕洰鏃跺湪姝ゆ坊鍔狅紝渚嬪锛?button type="button" class="nav-tab" data-panel="other">鍏朵粬鏍忕洰</button> -->
</span>
<!-- 多组栏目时可用分隔符:<span class="nav-tab-sep" aria-hidden="true"></span> -->
<!-- 澶氱粍鏍忕洰鏃跺彲鐢ㄥ垎闅旂锛?span class="nav-tab-sep" aria-hidden="true"></span> -->
</nav>
<div class="top-right"></div>
</header>
<div class="main-content">
<!-- 品牌检测栏目容器;后续增加栏目时复制此结构,改 data-panel 与 id并去掉 .active -->
<!-- 鍝佺墝妫€娴嬫爮鐩鍣紱鍚庣画澧炲姞鏍忕洰鏃跺鍒舵缁撴瀯锛屾敼 data-panel 涓?id锛屽苟鍘绘帀 .active -->
<div class="tab-panel active" data-panel="brandCheck" id="panel-brandCheck">
<aside class="left-panel">
<div class="section-title">选择文件</div>
<div class="section-title">閫夋嫨鏂囦欢</div>
<div class="upload-zone" id="uploadZone">
<div class="hint">选择 .xlsx 文件或文件夹(将读取该文件夹下所有 xlsx</div>
<div class="hint">閫夋嫨 .xlsx 鏂囦欢鎴栨枃浠跺す锛堝皢璇诲彇璇ユ枃浠跺す涓嬫墍鏈?xlsx锛?/div>
<div class="btns">
<button type="button" class="opt-btn" id="btnSelectFiles">选择 Excel 文件</button>
<button type="button" class="opt-btn" id="btnSelectFolder">选择文件夹</button>
<button type="button" class="opt-btn" id="btnSelectFiles">閫夋嫨 Excel 鏂囦欢</button>
<button type="button" class="opt-btn" id="btnSelectFolder">閫夋嫨鏂囦欢澶?/button>
</div>
<div class="selected-files" id="selectedFiles"></div>
</div>
<div class="section-title">运行方式</div>
<div class="section-title">杩愯鏂瑰紡</div>
<div class="option-group">
<label class="radio-item">
<input type="radio" name="runMode" value="immediate" checked>
<div>
<span class="label">立即运行</span>
<div class="desc">立刻执行,执行完成后可下载结果</div>
<span class="label">绔嬪嵆杩愯</span>
<div class="desc">绔嬪埢鎵ц锛屾墽琛屽畬鎴愬悗鍙笅杞界粨鏋?/div>
</div>
</label>
<label class="radio-item">
<input type="radio" name="runMode" value="task">
<div>
<span class="label">添加任务</span>
<div class="desc">数量较多时建议添加任务,后台执行,可在右侧任务队列查看状态与下载结果</div>
<span class="label">娣诲姞浠诲姟</span>
<div class="desc">鏁伴噺杈冨鏃跺缓璁坊鍔犱换鍔★紝鍚庡彴鎵ц锛屽彲鍦ㄥ彸渚т换鍔¢槦鍒楁煡鐪嬬姸鎬佷笌涓嬭浇缁撴灉</div>
</div>
</label>
</div>
<div class="section-title">匹配方式</div>
<div class="section-title">鍖归厤鏂瑰紡</div>
<div class="option-group">
<label class="radio-item">
<input type="radio" name="matchStrategy" value="Terms" checked>
<div>
<span class="label">精确匹配表达式</span>
<div class="desc">使用精确匹配,适合严格匹配品牌名称</div>
<span class="label">绮剧‘鍖归厤琛ㄨ揪寮?/span>
<div class="desc">浣跨敤绮剧‘鍖归厤锛岄€傚悎涓ユ牸鍖归厤鍝佺墝鍚嶇О</div>
</div>
</label>
<label class="radio-item">
<input type="radio" name="matchStrategy" value="Simple">
<div>
<span class="label">嵌入(结果包含输入的词语)</span>
<div class="desc">使用嵌入策略,结果中包含输入的品牌词语</div>
<span class="label">宓屽叆锛堢粨鏋滃寘鍚緭鍏ョ殑璇嶈锛?/span>
<div class="desc">浣跨敤宓屽叆绛栫暐锛岀粨鏋滀腑鍖呭惈杈撳叆鐨勫搧鐗岃瘝璇?/div>
</div>
</label>
</div>
<div class="run-row" id="runRow">
<div style="display:flex;align-items:center;flex-wrap:wrap;gap:10px;">
<button type="button" class="btn-run" id="btnRun">立即运行</button>
<span class="loading-msg" id="loadingMsg" style="display:none;">生成中,请稍候…</span>
<button type="button" class="btn-run" id="btnRun">绔嬪嵆杩愯</button>
<span class="loading-msg" id="loadingMsg" style="display:none;">鐢熸垚涓紝璇风◢鍊欌€?/span>
<div class="progress-wrap" id="runProgressWrap" style="display:none;">
<div class="progress-bar-bg"><div class="progress-bar-fill" id="runProgressFill" style="width:0%;"></div></div>
<span class="hint" style="font-size:12px;color:#888;" id="runProgressText">0 / 0</span>
</div>
<!-- 当前文件行级进度(不经数据库中转,只读内存接口) -->
<!-- 褰撳墠鏂囦欢琛岀骇杩涘害锛堜笉缁忔暟鎹簱涓浆锛屽彧璇诲唴瀛樻帴鍙o級 -->
<div class="progress-wrap" id="runLineProgressWrap" style="display:none;">
<div class="progress-bar-bg"><div class="progress-bar-fill" id="runLineProgressFill" style="width:0%;"></div></div>
<span class="hint" style="font-size:12px;color:#888;" id="runLineProgressText">0 / 0</span>
</div>
<button type="button" class="btn-cancel-run" id="btnCancelRun" style="display:none;">取消生成</button>
<button type="button" class="btn-cancel-run" id="btnCancelRun" style="display:none;">鍙栨秷鐢熸垚</button>
</div>
</div>
<div class="template-download-row" id="templateDownloadRow" role="button" tabindex="0" title="下载品牌文档格式模板(选择保存位置)">
<div class="template-download-row" id="templateDownloadRow" role="button" tabindex="0" title="涓嬭浇鍝佺墝鏂囨。鏍煎紡妯℃澘锛堥€夋嫨淇濆瓨浣嶇疆锛?>
<span class="template-download-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z" stroke="rgba(255,255,255,0.9)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
@@ -427,11 +427,11 @@
</svg>
</span>
<span class="template-download-text">
<span class="title">模板下载</span>
<span class="hint">品牌文档格式_模板.xlsx · 点击选择保存位置</span>
<span class="title">妯℃澘涓嬭浇</span>
<span class="hint">鍝佺墝鏂囨。鏍煎紡_妯℃澘.xlsx 路 鐐瑰嚮閫夋嫨淇濆瓨浣嶇疆</span>
</span>
</div>
<div class="template-download-row" id="templateDownloadRow2" role="button" tabindex="0" title="下载模板2以文件夹方式上传">
<div class="template-download-row" id="templateDownloadRow2" role="button" tabindex="0" title="涓嬭浇妯℃澘2锛堜互鏂囦欢澶规柟寮忎笂浼狅級">
<span class="template-download-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z" stroke="rgba(255,255,255,0.9)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
@@ -440,20 +440,20 @@
</svg>
</span>
<span class="template-download-text">
<span class="title">模板2下载</span>
<span class="hint">以文件夹方式上传.zip · 点击下载</span>
<span class="title">妯℃澘2涓嬭浇</span>
<span class="hint">浠ユ枃浠跺す鏂瑰紡涓婁紶.zip 路 鐐瑰嚮涓嬭浇</span>
</span>
</div>
</aside>
<div class="right-panel">
<div class="panel-header">
<span class="panel-header-title">任务队列</span>
<button type="button" class="btn-refresh-tasks" id="btnRefreshTasks">刷新任务状态</button>
<span class="panel-header-title">浠诲姟闃熷垪</span>
<button type="button" class="btn-refresh-tasks" id="btnRefreshTasks">鍒锋柊浠诲姟鐘舵€?/button>
</div>
<div class="task-list-wrap">
<ul class="task-list" id="taskList"></ul>
<div class="empty-tasks" id="emptyTasks">暂无任务</div>
<div class="empty-tasks" id="emptyTasks">鏆傛棤浠诲姟</div>
</div>
</div>
</div>
@@ -467,7 +467,7 @@
var cachedTasks = [];
var api = window.pywebview && window.pywebview.api;
// 顶部栏目切换:点击 nav-tab 时显示对应 data-panel tab-panel
// 椤堕儴鏍忕洰鍒囨崲锛氱偣鍑?nav-tab 鏃舵樉绀哄搴?data-panel 鐨?tab-panel
document.querySelectorAll('.nav-tab').forEach(function(tab) {
tab.addEventListener('click', function() {
var panelId = this.getAttribute('data-panel');
@@ -493,18 +493,18 @@
el.innerHTML = '';
return;
}
el.innerHTML = '已选 <b>' + selectedPaths.length + '</b> 个文件:<br>' +
el.innerHTML = '宸查€?<b>' + selectedPaths.length + '</b> 涓枃浠讹細<br>' +
selectedPaths.slice(0, 20).map(function(p) {
var name = p.split(/[/\\]/).pop();
return '<span title="' + p + '">' + name + '</span>';
}).join('') +
(selectedPaths.length > 20 ? '<span>… 等 ' + selectedPaths.length + ' 个</span>' : '');
(selectedPaths.length > 20 ? '<span>鈥?绛?' + selectedPaths.length + ' 涓?/span>' : '');
}
document.getElementById('btnSelectFiles').onclick = async function(e) {
e.stopPropagation();
if (!api || !api.select_brand_xlsx_files) {
showToast('当前环境不支持文件选择,请在本机客户端中打开');
showToast('褰撳墠鐜涓嶆敮鎸佹枃浠堕€夋嫨锛岃鍦ㄦ湰鏈哄鎴风涓墦寮€');
return;
}
try {
@@ -512,10 +512,10 @@
if (paths && paths.length) {
selectedPaths = paths;
renderSelected();
showToast('已选择 ' + paths.length + ' 个文件');
showToast('宸查€夋嫨 ' + paths.length + ' 涓枃浠?);
}
} catch (err) {
showToast('选择失败:' + (err.message || err));
showToast('閫夋嫨澶辫触锛? + (err.message || err));
}
};
@@ -525,16 +525,16 @@
try {
var res = await api.save_template_xlsx();
if (res && res.success) {
showToast('模板已保存至:' + (res.path || ''));
showToast('妯℃澘宸蹭繚瀛樿嚦锛? + (res.path || ''));
} else {
showToast(res && res.error ? res.error : '保存失败');
showToast(res && res.error ? res.error : '淇濆瓨澶辫触');
}
} catch (err) {
showToast('下载失败:' + (err.message || err));
showToast('涓嬭浇澶辫触锛? + (err.message || err));
}
return;
}
window.location.href = '/static/品牌文档格式_模板.xlsx';
window.location.href = '/static/鍝佺墝鏂囨。鏍煎紡_妯℃澘.xlsx';
};
document.getElementById('templateDownloadRow').onkeydown = function(e) {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); this.click(); }
@@ -546,16 +546,16 @@
try {
var res = await api.save_template_zip();
if (res && res.success) {
showToast('模板已保存至:' + (res.path || ''));
showToast('妯℃澘宸蹭繚瀛樿嚦锛? + (res.path || ''));
} else {
showToast(res && res.error ? res.error : '保存失败');
showToast(res && res.error ? res.error : '淇濆瓨澶辫触');
}
} catch (err) {
showToast('下载失败:' + (err.message || err));
showToast('涓嬭浇澶辫触锛? + (err.message || err));
}
return;
}
window.location.href = '/static/模板2-以文件夹方式上传.zip';
window.location.href = '/static/妯℃澘2-浠ユ枃浠跺す鏂瑰紡涓婁紶.zip';
};
document.getElementById('templateDownloadRow2').onkeydown = function(e) {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); this.click(); }
@@ -564,7 +564,7 @@
document.getElementById('btnSelectFolder').onclick =async function(e) {
e.stopPropagation();
if (!api || !api.select_brand_folder) {
showToast('当前环境不支持文件夹选择,请在本机客户端中打开');
showToast('褰撳墠鐜涓嶆敮鎸佹枃浠跺す閫夋嫨锛岃鍦ㄦ湰鏈哄鎴风涓墦寮€');
return;
}
try {
@@ -581,14 +581,14 @@
if (res.success && res.paths && res.paths.length) {
selectedPaths = res.paths;
renderSelected();
showToast('已选择文件夹内 ' + res.paths.length + ' xlsx 文件');
showToast('宸查€夋嫨鏂囦欢澶瑰唴 ' + res.paths.length + ' 涓?xlsx 鏂囦欢');
} else {
showToast(res.error || '该文件夹下没有 xlsx 文件');
showToast(res.error || '璇ユ枃浠跺す涓嬫病鏈?xlsx 鏂囦欢');
}
})
.catch(function() { showToast('请求失败'); });
.catch(function() { showToast('璇锋眰澶辫触'); });
} catch (err) {
showToast('选择失败:' + (err.message || err));
showToast('閫夋嫨澶辫触锛? + (err.message || err));
}
};
@@ -628,9 +628,9 @@
function onRunTaskFinished(status) {
stopPollAndResetRunUI();
loadTasks();
if (status === 'success') showToast('生成完成,可下载结果');
else if (status === 'failed') showToast('生成失败');
else if (status === 'cancelled') showToast('已取消');
if (status === 'success') showToast('鐢熸垚瀹屾垚锛屽彲涓嬭浇缁撴灉');
else if (status === 'failed') showToast('鐢熸垚澶辫触');
else if (status === 'cancelled') showToast('宸插彇娑?);
}
function pollRunTask(taskId) {
@@ -649,11 +649,11 @@
.then(function(r) { return r.json(); })
.then(function(res) {
if (res.success) onRunTaskFinished('cancelled');
else showToast(res.error || '取消失败');
else showToast(res.error || '鍙栨秷澶辫触');
});
};
// 通过 SSE 订阅任务完成事件,完成后由后端主动推送,前端收到后立即隐藏进度条和取消按钮
// 閫氳繃 SSE 璁㈤槄浠诲姟瀹屾垚浜嬩欢锛屽畬鎴愬悗鐢卞悗绔富鍔ㄦ帹閫侊紝鍓嶇鏀跺埌鍚庣珛鍗抽殣钘忚繘搴︽潯鍜屽彇娑堟寜閽?
var eventsUrl = '/api/brand/tasks/' + taskId + '/events';
runTaskEventSource = new EventSource(eventsUrl);
runTaskEventSource.onmessage = function(e) {
@@ -685,18 +685,18 @@
if (runProgressText) {
var st = (t.status || '').toLowerCase();
if (st === 'running') {
runProgressText.textContent = total ? (cur + ' / ' + total) : '生成中…';
runProgressText.textContent = total ? (cur + ' / ' + total) : '鐢熸垚涓€?;
} else if (st === 'success') {
runProgressText.textContent = '已完成';
runProgressText.textContent = '宸插畬鎴?;
} else if (st === 'failed') {
runProgressText.textContent = '失败';
runProgressText.textContent = '澶辫触';
} else if (st === 'cancelled') {
runProgressText.textContent = '已取消';
runProgressText.textContent = '宸插彇娑?;
} else {
runProgressText.textContent = '执行中…';
runProgressText.textContent = '鎵ц?;
}
}
// 行级进度:从内存接口 /api/brand/tasks/<id>/line-progress 拉取
// 琛岀骇杩涘害锛氫粠鍐呭瓨鎺ュ彛 /api/brand/tasks/<id>/line-progress 鎷夊彇
if (runLineProgressWrap && runLineProgressFill && runLineProgressText) {
var st2 = (t.status || '').toLowerCase();
if (st2 === 'running') {
@@ -715,14 +715,17 @@
var curLine = info.current_line || 0;
runLineProgressWrap.style.display = 'block';
runLineProgressFill.style.width = totalLines ? (100 * curLine / totalLines) + '%' : '0%';
runLineProgressText.textContent = totalLines ? (curLine + ' / ' + totalLines) : '当前文件处理中…';
runLineProgressText.textContent = totalLines ? (curLine + ' / ' + totalLines) : '褰撳墠鏂囦欢澶勭悊涓€?;
})
.catch(function() {});
.catch(function(err) {
console.error('loadTasks failed:', err);
showToast('浠诲姟鍒楄鍒锋柊澶辫触');
});
} else {
runLineProgressWrap.style.display = 'none';
}
}
// 终态也通过轮询兜底,确保 UI 一定被重置SSE 可能因网络未收到)
// 缁堟€佷篃閫氳繃杞鍏滃簳锛岀‘淇?UI 涓€瀹氳閲嶇疆锛圫SE 鍙兘鍥犵綉缁滄湭鏀跺埌锛?
var st = (t.status || '').toLowerCase();
if (st === 'success' || st === 'failed' || st === 'cancelled') {
onRunTaskFinished(st);
@@ -735,7 +738,7 @@
document.getElementById('btnRun').onclick = function() {
if (selectedPaths.length === 0) {
showToast('请先选择 Excel 文件或文件夹');
showToast('璇峰厛閫夋嫨 Excel 鏂囦欢鎴栨枃浠跺す');
return;
}
var mode = getRunMode();
@@ -755,16 +758,17 @@
.then(function(r) { return r.json(); })
.then(function(res) {
if (res.success && res.task_id) {
loadTasks();
loadingMsg.style.display = 'none';
pollRunTask(res.task_id);
} else {
stopPollAndResetRunUI();
showToast(res.error || '运行失败');
showToast(res.error || '杩愯澶辫触');
}
})
.catch(function() {
stopPollAndResetRunUI();
showToast('请求失败或超时');
showToast('璇锋眰澶辫触鎴栬秴鏃?);
});
} else {
fetch('/api/brand/tasks', {
@@ -776,13 +780,13 @@
.then(function(r) { return r.json(); })
.then(function(res) {
if (res.success) {
showToast('任务已添加,请在任务队列查看');
showToast('浠诲姟宸叉坊鍔狅紝璇峰湪浠诲姟闃熷垪鏌ョ湅');
loadTasks();
} else {
showToast(res.error || '添加失败');
showToast(res.error || '娣诲姞澶辫触');
}
})
.catch(function() { showToast('请求失败'); });
.catch(function() { showToast('璇锋眰澶辫触'); });
}
};
@@ -801,8 +805,8 @@
cachedTasks = res.items;
list.innerHTML = res.items.map(function(t) {
var statusClass = (t.status || 'pending').toLowerCase();
var statusText = { pending: '等待中', running: '执行中', success: '已完成', failed: '失败', cancelled: '已取消' }[t.status] || t.status;
var filesDesc = (t.file_paths && t.file_paths.length) ? t.file_paths.length + ' 个文件' : '';
var statusText = { pending: '绛夊緟涓?, running: '鎵ц?, success: '宸插畬鎴?, failed: '澶辫触', cancelled: '宸插彇娑? }[t.status] || t.status;
var filesDesc = (t.file_paths && t.file_paths.length) ? t.file_paths.length + ' 涓枃浠? : '';
var total = t.progress_total || 0;
var cur = t.progress_current || 0;
var pct = total ? Math.min(100, (100 * cur / total)) : 0;
@@ -811,13 +815,13 @@
: '';
var hasZipUrl = t.result_paths && t.result_paths.zip_url;
var downloadHtml = hasZipUrl
? '<a class="download js-save-zip" href="#" data-task-id="' + t.id + '">下载结果</a>'
? '<a class="download js-save-zip" href="#" data-task-id="' + t.id + '">涓嬭浇缁撴灉</a>'
: '<span class="download hide"></span>';
var cancelBtn = statusClass === 'running'
? '<button type="button" class="btn-cancel js-cancel-task" data-task-id="' + t.id + '">取消</button>'
? '<button type="button" class="btn-cancel js-cancel-task" data-task-id="' + t.id + '">鍙栨秷</button>'
: '';
var deleteBtn = '<button type="button" class="btn-delete js-delete-task" data-task-id="' + t.id + '">删除</button>';
var titleDesc = (t.desc && String(t.desc).trim()) ? String(t.desc).trim() : ('任务 #' + t.id);
var deleteBtn = '<button type="button" class="btn-delete js-delete-task" data-task-id="' + t.id + '">鍒犻櫎</button>';
var titleDesc = (t.desc && String(t.desc).trim()) ? String(t.desc).trim() : ('浠诲姟 #' + t.id);
var displayDesc = titleDesc.length > 20 ? titleDesc.substring(0, 20) + '....' : titleDesc;
return '<li class="task-item">' +
'<div class="left">' +
@@ -834,15 +838,18 @@
'</div></li>';
}).join('');
})
.catch(function() {});
.catch(function(err) {
console.error('loadTasks failed:', err);
showToast('浠诲姟鍒楄〃鍒锋柊澶辫触');
});
}
// 手动刷新任务状态按钮
// 鎵嬪姩鍒锋柊浠诲姟鐘舵€佹寜閽?
var btnRefreshTasks = document.getElementById('btnRefreshTasks');
if (btnRefreshTasks) {
btnRefreshTasks.onclick = function () {
loadTasks();
showToast('任务状态已刷新');
showToast('浠诲姟鐘舵€佸凡鍒锋柊');
};
}
@@ -857,7 +864,7 @@
fetch('/api/brand/tasks/' + taskId + '/cancel', { method: 'POST', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest' } })
.then(function(r) { return r.json(); })
.then(function(res) {
if (res.success) { showToast('已取消'); loadTasks(); } else { showToast(res.error || '取消失败'); }
if (res.success) { showToast('宸插彇娑?); loadTasks(); } else { showToast(res.error || '鍙栨秷澶辫触'); }
});
return;
}
@@ -867,7 +874,7 @@
fetch('/api/brand/tasks/' + taskId, { method: 'DELETE', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest' } })
.then(function(r) { return r.json(); })
.then(function(res) {
if (res.success) { showToast('已删除'); loadTasks(); } else { showToast(res.error || '删除失败'); }
if (res.success) { showToast('宸插垹闄?); loadTasks(); } else { showToast(res.error || '鍒犻櫎澶辫触'); }
});
return;
}
@@ -875,7 +882,7 @@
if (!a || !a.classList || !a.classList.contains('js-save-zip')) return;
var task = cachedTasks.filter(function(t) { return String(t.id) === String(taskId); })[0];
if (!task || !task.result_paths || !task.result_paths.zip_url) {
showToast('无法获取下载地址');
showToast('鏃犳硶鑾峰彇涓嬭浇鍦板潃');
return;
}
var zipUrl = task.result_paths.zip_url;
@@ -884,21 +891,21 @@
a.style.pointerEvents = 'none';
var done = function(ret) {
if (ret && ret.success) {
showToast('已保存:' + (ret.path || filename));
} else if (ret && ret.error && ret.error !== '用户取消') {
showToast('保存失败:' + ret.error);
showToast('宸蹭繚瀛橈細' + (ret.path || filename));
} else if (ret && ret.error && ret.error !== '鐢ㄦ埛鍙栨秷') {
showToast('淇濆瓨澶辫触锛? + ret.error);
}
a.style.pointerEvents = '';
};
try {
var ret = api.save_file_from_url(zipUrl, filename);
if (ret && typeof ret.then === 'function') {
ret.then(done).catch(function(err) { showToast('保存失败:' + (err && err.message || err)); a.style.pointerEvents = ''; });
ret.then(done).catch(function(err) { showToast('淇濆瓨澶辫触锛? + (err && err.message || err)); a.style.pointerEvents = ''; });
} else {
done(ret);
}
} catch (err) {
showToast('保存失败:' + (err.message || err));
showToast('淇濆瓨澶辫触锛? + (err.message || err));
a.style.pointerEvents = '';
}
} else {
@@ -907,7 +914,7 @@
});
loadTasks();
// setInterval(loadTasks, 10000);
setInterval(loadTasks, 5000);
if (window.addEventListener) {
window.addEventListener('pywebviewready', function() {
@@ -919,3 +926,4 @@
</script>
</body>
</html>