feat: 添加 AI 重复物料巡检功能,支持生成人工复核清单和导出 CSV
This commit is contained in:
@@ -101,6 +101,21 @@
|
||||
<summary>查看原始 AI 文本</summary>
|
||||
<pre id="ai-panel-content" class="ai-panel-content"></pre>
|
||||
</details>
|
||||
|
||||
<hr class="ai-divider">
|
||||
|
||||
<div class="ai-panel-head">
|
||||
<h2>AI重复物料巡检</h2>
|
||||
</div>
|
||||
<p class="hint">扫描疑似同料号、同参数、同立创编号记录,生成人工复核清单。</p>
|
||||
<div class="actions">
|
||||
<button class="btn" id="ai-duplicate-btn" type="button">开始巡检</button>
|
||||
<button class="btn btn-light" id="ai-duplicate-export-current-btn" type="button">导出当前显示</button>
|
||||
<button class="btn btn-light" id="ai-duplicate-export-all-btn" type="button">导出全量</button>
|
||||
</div>
|
||||
<p class="hint" id="ai-duplicate-status"></p>
|
||||
<p class="hint" id="ai-duplicate-warning"></p>
|
||||
<div id="ai-duplicate-groups" class="ai-plan-groups"></div>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
@@ -244,6 +259,167 @@
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
(function () {
|
||||
var auditBtn = document.getElementById('ai-duplicate-btn');
|
||||
var exportCurrentBtn = document.getElementById('ai-duplicate-export-current-btn');
|
||||
var exportAllBtn = document.getElementById('ai-duplicate-export-all-btn');
|
||||
var statusNode = document.getElementById('ai-duplicate-status');
|
||||
var warningNode = document.getElementById('ai-duplicate-warning');
|
||||
var groupsWrap = document.getElementById('ai-duplicate-groups');
|
||||
var latestAuditGroups = [];
|
||||
|
||||
if (!auditBtn || !exportCurrentBtn || !exportAllBtn || !statusNode || !groupsWrap) {
|
||||
return;
|
||||
}
|
||||
|
||||
function clearGroups() {
|
||||
latestAuditGroups = [];
|
||||
groupsWrap.innerHTML = '';
|
||||
}
|
||||
|
||||
function renderAuditGroups(groups) {
|
||||
clearGroups();
|
||||
if (!Array.isArray(groups) || !groups.length) {
|
||||
var empty = document.createElement('p');
|
||||
empty.className = 'muted';
|
||||
empty.textContent = '未发现疑似重复物料';
|
||||
groupsWrap.appendChild(empty);
|
||||
return;
|
||||
}
|
||||
|
||||
latestAuditGroups = groups.slice();
|
||||
|
||||
groups.forEach(function (group) {
|
||||
var section = document.createElement('section');
|
||||
section.className = 'ai-plan-group ai-audit-group';
|
||||
|
||||
var title = document.createElement('h3');
|
||||
title.textContent = (group.reason || '疑似重复') + ' | ' + (group.key || '-') + '(' + (group.member_count || 0) + ')';
|
||||
section.appendChild(title);
|
||||
|
||||
var suggestion = document.createElement('p');
|
||||
suggestion.className = 'hint';
|
||||
suggestion.textContent = '建议: ' + (group.suggestion || '请人工复核');
|
||||
section.appendChild(suggestion);
|
||||
|
||||
var list = document.createElement('ul');
|
||||
list.className = 'side-low-stock-list';
|
||||
|
||||
(group.members || []).forEach(function (member) {
|
||||
var li = document.createElement('li');
|
||||
|
||||
var content = document.createElement('div');
|
||||
var strong = document.createElement('strong');
|
||||
strong.textContent = (member.name || '未命名元件') + ' (' + (member.part_no || '-') + ')';
|
||||
content.appendChild(strong);
|
||||
|
||||
var spec = document.createElement('p');
|
||||
spec.className = 'hint';
|
||||
spec.textContent = '规格: ' + (member.specification || '-');
|
||||
content.appendChild(spec);
|
||||
|
||||
var pos = document.createElement('p');
|
||||
pos.className = 'hint';
|
||||
pos.textContent = (member.box_name || '-') + ' / ' + (member.slot_code || '-') + ' | 数量 ' + (member.quantity || 0);
|
||||
content.appendChild(pos);
|
||||
|
||||
if (member.lcsc_code) {
|
||||
var lcsc = document.createElement('p');
|
||||
lcsc.className = 'hint';
|
||||
lcsc.textContent = '立创编号: ' + member.lcsc_code;
|
||||
content.appendChild(lcsc);
|
||||
}
|
||||
|
||||
li.appendChild(content);
|
||||
|
||||
if (member.edit_url) {
|
||||
var editBtn = document.createElement('a');
|
||||
editBtn.className = 'btn btn-light';
|
||||
editBtn.href = member.edit_url;
|
||||
editBtn.textContent = '编辑';
|
||||
li.appendChild(editBtn);
|
||||
}
|
||||
|
||||
list.appendChild(li);
|
||||
});
|
||||
|
||||
section.appendChild(list);
|
||||
groupsWrap.appendChild(section);
|
||||
});
|
||||
}
|
||||
|
||||
auditBtn.addEventListener('click', function () {
|
||||
auditBtn.disabled = true;
|
||||
statusNode.textContent = '正在巡检重复物料,请稍候...';
|
||||
if (warningNode) {
|
||||
warningNode.textContent = '';
|
||||
}
|
||||
clearGroups();
|
||||
|
||||
fetch('{{ url_for('ai_duplicate_audit') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: '{}'
|
||||
})
|
||||
.then(function (resp) {
|
||||
return resp.json().then(function (data) {
|
||||
return { ok: resp.ok, data: data };
|
||||
});
|
||||
})
|
||||
.then(function (result) {
|
||||
var data = result.data || {};
|
||||
if (!result.ok || !data.ok) {
|
||||
statusNode.textContent = '巡检失败';
|
||||
if (warningNode) {
|
||||
warningNode.textContent = data.message || '服务暂时不可用';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
statusNode.textContent = data.summary || '巡检已完成';
|
||||
if (warningNode) {
|
||||
warningNode.textContent = data.parse_warning || '';
|
||||
}
|
||||
renderAuditGroups((data.data && data.data.groups) || []);
|
||||
})
|
||||
.catch(function () {
|
||||
statusNode.textContent = '巡检失败';
|
||||
if (warningNode) {
|
||||
warningNode.textContent = '请求失败,请稍后重试';
|
||||
}
|
||||
})
|
||||
.finally(function () {
|
||||
auditBtn.disabled = false;
|
||||
});
|
||||
});
|
||||
|
||||
exportCurrentBtn.addEventListener('click', function () {
|
||||
if (!latestAuditGroups.length) {
|
||||
statusNode.textContent = '请先运行巡检,再导出当前显示结果';
|
||||
if (warningNode) {
|
||||
warningNode.textContent = '';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var params = new URLSearchParams();
|
||||
params.set('limit', String(latestAuditGroups.length));
|
||||
latestAuditGroups.forEach(function (group) {
|
||||
params.append('group_id', (group.type || '') + '::' + (group.key || ''));
|
||||
});
|
||||
|
||||
var downloadUrl = '{{ url_for('export_duplicate_audit_csv') }}?' + params.toString();
|
||||
window.location.href = downloadUrl;
|
||||
});
|
||||
|
||||
exportAllBtn.addEventListener('click', function () {
|
||||
var downloadUrl = '{{ url_for('export_duplicate_audit_csv') }}?limit=1000';
|
||||
window.location.href = downloadUrl;
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user