Files
inventory/templates/edit.html

290 lines
11 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>编辑元件</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<header class="hero slim">
<div>
<h1>{{ box.name }} - 编号 {{ slot_code }}</h1>
<p>步骤: 填写核心字段 -> 检查数量 -> 保存</p>
</div>
<div class="hero-actions">
<a class="btn btn-light" href="{{ url_for('search_page', q=search_query) if search_query else url_for('search_page') }}">返回快速搜索</a>
<a class="btn btn-light" href="{{ url_for('stats_page') }}">统计页</a>
<a class="btn btn-light" href="{{ url_for('view_box', box_id=box.id) }}">返回宫格</a>
{% include '_account_menu.html' %}
</div>
</header>
<main class="container">
{% if error %}
<p class="alert">{{ error }}</p>
{% endif %}
{% if notice %}
<p class="notice">{{ notice }}</p>
{% endif %}
{% if lock_storage_mode %}
<p class="notice">当前为锁仓模式: 禁止删除位置绑定,禁止替换当前位置料号。</p>
{% endif %}
<div class="edit-stack">
<section class="panel quick-inbound-panel lcsc-import-panel">
<h2>立创编号入库</h2>
<p class="hint">当前编辑位置: {{ slot_code }}。仅支持粘贴立创商品详情页链接,系统会自动提取 itemId 并查询。</p>
<form class="form-grid lcsc-inline-form" method="post" action="{{ url_for('lcsc_import_to_edit_slot', box_id=box.id, slot=slot) }}">
<label>
立创商品详情页链接
<input type="text" name="lcsc_product_id" required placeholder="如 https://item.szlcsc.com/23913.html">
</label>
<label>
数量
<input type="number" name="quantity" min="0" value="0">
</label>
<label class="full">
<input type="checkbox" name="confirm_merge" value="1">
人工确认后合并: 若检测到同料号或同参数物料,将合并到已存在位置
</label>
<label class="full">
<input type="checkbox" name="confirm_position_change" value="1">
我确认替换当前位物料(会改变该位置原有绑定)
</label>
<div class="actions full">
<button class="btn" type="submit">拉取并写入当前位</button>
<a class="btn btn-light" href="{{ url_for('ai_settings_page') }}">接口参数</a>
</div>
</form>
</section>
<section class="panel quick-inbound-panel">
<div class="group-title-row">
<h2>AI 标签与备注标准化</h2>
<button class="btn btn-light" type="button" id="toggle-standardize-panel" aria-expanded="false">展开</button>
</div>
<div id="standardize-card-body" hidden>
<p class="hint">生成更适合标签打印的短名称,并自动补全统一搜索关键词。确认后再回填到表单。</p>
<p class="hint" id="standardize-status" aria-live="polite"></p>
<section class="ai-standardize-preview" id="standardize-preview" hidden>
<div class="standardize-grid">
<div>
<strong>短标签</strong>
<p id="standardize-short-label">-</p>
</div>
<div>
<strong>建议名称</strong>
<p id="standardize-name">-</p>
</div>
<div>
<strong>建议规格</strong>
<p id="standardize-specification">-</p>
</div>
<div class="full">
<strong>建议备注</strong>
<p id="standardize-note">-</p>
</div>
<div class="full">
<strong>搜索关键词</strong>
<div class="match-tags" id="standardize-keywords"></div>
</div>
</div>
<div class="actions">
<button class="btn" type="button" id="apply-standardization-btn">应用到表单</button>
</div>
</section>
<div class="actions">
<button class="btn btn-light" type="button" id="generate-standardization-btn">生成标准化建议</button>
</div>
</div>
</section>
<section class="edit-form-panel">
<form class="panel form-grid" method="post">
<input type="hidden" name="q" value="{{ search_query or '' }}">
<label>
料号 *
<input id="part-no-input" type="text" name="part_no" required value="{{ component.part_no if component else '' }}" aria-label="料号" placeholder="如 STM32F103C8T6">
</label>
<label>
名称 *
<input id="name-input" type="text" name="name" required value="{{ component.name if component else '' }}" aria-label="名称" placeholder="如 MCU STM32F103C8T6">
</label>
<label>
规格
<input id="specification-input" type="text" name="specification" value="{{ component.specification if component else '' }}" placeholder="如 Cortex-M3 / LQFP-48">
</label>
<label>
数量
<input type="number" name="quantity" min="0" value="{{ component.quantity if component else 0 }}">
</label>
<label class="full">
备注
<textarea id="note-input" name="note" rows="3" placeholder="如 LCSC item 9243">{{ component.note if component else '' }}</textarea>
</label>
<label class="full">
<input type="checkbox" name="confirm_merge" value="1">
人工确认后合并: 若检测到同料号或同参数物料,保存时将数量合并到已存在位置
</label>
<label class="full">
<input type="checkbox" name="confirm_position_change" value="1">
我确认替换当前位物料(会改变该位置原有绑定)
</label>
<div class="actions full">
<button class="btn" type="submit" name="action" value="save">保存</button>
{% if component %}
{% if component.is_enabled %}
<button class="btn btn-light" type="submit" name="action" value="toggle_disable">停用</button>
{% else %}
<button class="btn btn-light" type="submit" name="action" value="toggle_enable">启用</button>
{% endif %}
<label class="full">
删除确认(输入当前位置编号 {{ slot_code }}
<input type="text" name="delete_confirm_slot" placeholder="请输入 {{ slot_code }}">
</label>
<button class="btn btn-danger" type="submit" name="action" value="delete" onclick="return confirm('确认删除这个元件记录吗?')">删除</button>
{% endif %}
</div>
</form>
</section>
<section class="panel entry-guide edit-guide-panel">
<h2>轻量入库规范</h2>
<p class="hint">先保证可检索,再补充关键参数,不追求一次填很全。</p>
<ul class="guide-list">
<li>必填: 料号(part_no) + 名称(name) + 数量(quantity)</li>
<li>建议: 规格(specification)写 2-4 个关键参数</li>
<li>备注(note): 来源编号或链接,如 LCSC item 9243</li>
</ul>
<pre class="guide-code">料号: STM32F103C8T6
名称: MCU STM32F103C8T6
规格: Cortex-M3 / 64KB Flash / LQFP-48
数量: 10
备注: LCSC item 9243</pre>
</section>
</div>
</main>
<script>
(function () {
var partNoInput = document.getElementById('part-no-input');
var nameInput = document.getElementById('name-input');
var specificationInput = document.getElementById('specification-input');
var noteInput = document.getElementById('note-input');
var toggleStandardizeBtn = document.getElementById('toggle-standardize-panel');
var standardizeCardBody = document.getElementById('standardize-card-body');
var generateBtn = document.getElementById('generate-standardization-btn');
var applyBtn = document.getElementById('apply-standardization-btn');
var status = document.getElementById('standardize-status');
var preview = document.getElementById('standardize-preview');
var shortLabelNode = document.getElementById('standardize-short-label');
var nameNode = document.getElementById('standardize-name');
var specificationNode = document.getElementById('standardize-specification');
var noteNode = document.getElementById('standardize-note');
var keywordNode = document.getElementById('standardize-keywords');
var latestSuggestion = null;
if (!partNoInput || !nameInput || !specificationInput || !noteInput || !generateBtn || !applyBtn || !status || !preview) {
return;
}
function setStandardizePanelExpanded(expanded) {
if (!toggleStandardizeBtn || !standardizeCardBody) {
return;
}
standardizeCardBody.hidden = !expanded;
toggleStandardizeBtn.setAttribute('aria-expanded', expanded ? 'true' : 'false');
toggleStandardizeBtn.textContent = expanded ? '收起' : '展开';
}
setStandardizePanelExpanded(false);
if (toggleStandardizeBtn) {
toggleStandardizeBtn.addEventListener('click', function () {
setStandardizePanelExpanded(standardizeCardBody.hidden);
});
}
function escapeHtml(text) {
return String(text || '')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function renderSuggestion(suggestion) {
latestSuggestion = suggestion;
preview.hidden = false;
shortLabelNode.textContent = suggestion.short_label || '-';
nameNode.textContent = suggestion.name || '-';
specificationNode.textContent = suggestion.specification || '-';
noteNode.textContent = suggestion.note || '-';
keywordNode.innerHTML = (suggestion.keywords || []).map(function (keyword) {
return '<span class="tag">' + escapeHtml(keyword) + '</span>';
}).join('') || '<span class="tag">-</span>';
}
generateBtn.addEventListener('click', function () {
setStandardizePanelExpanded(true);
if (!partNoInput.value.trim() && !nameInput.value.trim()) {
status.textContent = '请先填写料号或名称';
return;
}
generateBtn.disabled = true;
status.textContent = '正在生成标准化建议...';
var payload = new URLSearchParams();
payload.set('part_no', partNoInput.value || '');
payload.set('name', nameInput.value || '');
payload.set('specification', specificationInput.value || '');
payload.set('note', noteInput.value || '');
fetch('{{ url_for('ai_component_standardize') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
body: payload.toString()
}).then(function (resp) {
return resp.json().then(function (data) {
if (!resp.ok || !data.ok) {
throw new Error(data.message || '生成失败');
}
return data;
});
}).then(function (data) {
renderSuggestion(data.suggestion || {});
status.textContent = data.parse_notice || '标准化建议已生成,可先预览再应用';
}).catch(function (error) {
status.textContent = '生成失败: ' + error.message;
}).finally(function () {
generateBtn.disabled = false;
});
});
applyBtn.addEventListener('click', function () {
if (!latestSuggestion) {
status.textContent = '请先生成标准化建议';
return;
}
if (latestSuggestion.name) {
nameInput.value = latestSuggestion.name;
}
if (latestSuggestion.specification) {
specificationInput.value = latestSuggestion.specification;
}
if (latestSuggestion.note) {
noteInput.value = latestSuggestion.note;
}
status.textContent = '建议已回填到表单,确认无误后再保存';
});
})();
</script>
</body>
</html>