更新后端新增内容
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
app/assets/delete-brand-D1WtGorm.css
Normal file
1
app/assets/delete-brand-D1WtGorm.css
Normal file
File diff suppressed because one or more lines are too long
1
app/assets/delete-brand.js
Normal file
1
app/assets/delete-brand.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
app/brand_output/357/1_鲍丽明.xlsx
Normal file
BIN
app/brand_output/357/1_鲍丽明.xlsx
Normal file
Binary file not shown.
BIN
app/brand_output/357/1_鲍丽明_result.xlsx
Normal file
BIN
app/brand_output/357/1_鲍丽明_result.xlsx
Normal file
Binary file not shown.
@@ -5,8 +5,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>格式转换 - 数富AI</title>
|
||||
<script type="module" crossorigin src="/assets/convert.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/pywebview-BRrok0pS.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/pywebview-IqgMfeBe.css">
|
||||
<link rel="modulepreload" crossorigin href="/assets/pywebview-Bl6M97uH.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/pywebview-8G_9KMXd.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/convert-Cfr3mUjs.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>数据去重 - 数富AI</title>
|
||||
<script type="module" crossorigin src="/assets/dedupe.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/pywebview-BRrok0pS.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/pywebview-IqgMfeBe.css">
|
||||
<link rel="modulepreload" crossorigin href="/assets/pywebview-Bl6M97uH.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/pywebview-8G_9KMXd.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/dedupe-CS18ls2z.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
15
app/new_web_source/delete-brand.html
Normal file
15
app/new_web_source/delete-brand.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!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>
|
||||
<script type="module" crossorigin src="/assets/delete-brand.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/pywebview-Bl6M97uH.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/pywebview-8G_9KMXd.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/delete-brand-D1WtGorm.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,8 +5,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>数据拆分 - 数富AI</title>
|
||||
<script type="module" crossorigin src="/assets/split.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/pywebview-BRrok0pS.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/pywebview-IqgMfeBe.css">
|
||||
<link rel="modulepreload" crossorigin href="/assets/pywebview-Bl6M97uH.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/pywebview-8G_9KMXd.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/split-mwLUJT1K.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<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 {
|
||||
@@ -186,7 +186,7 @@
|
||||
</head>
|
||||
<body data-user-id="{{ user_id or '' }}">
|
||||
<header class="header">
|
||||
<span class="header-title">南日AI</span>
|
||||
<span class="header-title">数富AI</span>
|
||||
<div class="header-right">
|
||||
{% if is_admin %}
|
||||
<!-- <a href="/admin" class="admin-link">用户管理</a>-->
|
||||
@@ -219,6 +219,7 @@
|
||||
<script>
|
||||
// 权限校验:根据 column-permissions 接口按 column_key 显示入口
|
||||
(function() {
|
||||
localStorage.setItem("uid",{{ user_id }})
|
||||
var uid = document.body.getAttribute('data-user-id');
|
||||
if (!uid) return;
|
||||
var baseUrl = window.location.origin;
|
||||
|
||||
Reference in New Issue
Block a user