feat:增强框类型管理和搜索功能
- 引入基于 JSON 的框类型覆盖,允许动态更新标签、描述和前缀。 - 增加了一种可调节容量的定制盒型。 - 实现了应用和保存盒子类型覆盖的函数。 - 更新仪表盘,显示按箱型分组的库存低库存商品。 - 创建了一个新的搜索页面,方便快速访问具有增强搜索功能的组件。 - 用搜索页面取代扫描页面,将出站功能直接集成到搜索结果中。 - 改进的界面元素,提升导航和用户体验,包括新增按钮和样式。 - 移除过时的 scanner.js 文件并将其功能集成到搜索页面。 - 更新了各种模板,以反映新的搜索和框类型管理功能。
This commit is contained in:
@@ -13,17 +13,16 @@
|
||||
<p>{% if separate_mode %}当前为独立分类界面,减少长列表翻找成本{% else %}极简中性灰布局,聚焦数量/分类/变动核心信息{% endif %}</p>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<a class="btn btn-light" href="{{ url_for('types_page') }}">分类总览</a>
|
||||
<a class="btn btn-light" href="{{ url_for('types_page') }}">仓库概览</a>
|
||||
<a class="btn btn-light" href="{{ url_for('search_page') }}">快速搜索</a>
|
||||
<a class="btn btn-light" href="#quick-add">新增库存</a>
|
||||
<a class="btn btn-light" href="{{ url_for('stats_page') }}">统计页</a>
|
||||
<a class="btn" href="{{ url_for('scan_page') }}">扫码/搜索</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<div class="layout-shell">
|
||||
<aside class="catalog-sidebar">
|
||||
<button class="sidebar-toggle btn btn-light" type="button" aria-expanded="false" aria-controls="side-low-stock">低库存面板</button>
|
||||
<section class="panel" id="sidebar-nav-panel">
|
||||
<h2>容器导航</h2>
|
||||
<div class="card-actions icon-links" aria-label="快捷功能">
|
||||
@@ -36,9 +35,6 @@
|
||||
<a class="icon-link" href="#quick-add" title="跳转新增库存" aria-label="跳转新增库存">
|
||||
<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8"/><path d="M12 8v8"/><path d="M8 12h8"/></svg>
|
||||
</a>
|
||||
<a class="icon-link" href="#side-low-stock" title="跳转低库存面板" aria-label="跳转低库存面板">
|
||||
<svg class="icon" viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="5" width="6" height="6" rx="2"/><rect x="13" y="5" width="6" height="6" rx="2"/><rect x="5" y="13" width="6" height="6" rx="2"/><rect x="13" y="13" width="6" height="6" rx="2"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
<nav class="catalog-nav" id="catalog-nav-links">
|
||||
{% for key, meta in box_types.items() %}
|
||||
@@ -46,45 +42,6 @@
|
||||
{% endfor %}
|
||||
</nav>
|
||||
</section>
|
||||
|
||||
<section class="panel side-metrics">
|
||||
<h2>关键指标</h2>
|
||||
<div class="side-metrics-grid">
|
||||
<article class="metric-card">
|
||||
<p class="metric-title">容器总数</p>
|
||||
<p class="metric-value">{{ stats.box_count }}</p>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<p class="metric-title">启用元件</p>
|
||||
<p class="metric-value">{{ stats.active_items }}</p>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<p class="metric-title">近7天净变动</p>
|
||||
<p class="metric-value">{% if stats.period_net_change_7d > 0 %}+{% endif %}{{ stats.period_net_change_7d }}</p>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<p class="metric-title">待补货元件</p>
|
||||
<p class="metric-value">{{ stats.low_stock_count }}</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel side-low-stock" id="side-low-stock">
|
||||
<h2>低库存元器件</h2>
|
||||
<ul class="side-low-stock-list">
|
||||
{% for item in low_stock_items %}
|
||||
<li>
|
||||
<div>
|
||||
<strong>{{ item.name }}</strong>
|
||||
<p class="hint">{{ item.part_no }} | {{ item.box_name }} / {{ item.slot_code }} | 数量 {{ item.quantity }}</p>
|
||||
</div>
|
||||
<a class="btn btn-light" href="{{ item.edit_url }}">编辑</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="muted">当前没有低库存元器件。</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
<section class="catalog-content">
|
||||
@@ -109,6 +66,9 @@
|
||||
{% if separate_mode %}<input type="hidden" name="return_to_type" value="{{ current_box_type }}">{% endif %}
|
||||
<input type="text" name="name" placeholder="基础名称(自动拼范围)" required aria-label="基础名称">
|
||||
<input type="text" name="slot_prefix" placeholder="前缀(如A/B/C)">
|
||||
{% if key == 'custom' %}
|
||||
<input type="number" name="slot_capacity" min="1" value="{{ meta.default_capacity }}" placeholder="格数" required>
|
||||
{% endif %}
|
||||
<input type="number" name="start_number" min="0" value="1" placeholder="起始序号">
|
||||
<input type="text" name="description" placeholder="备注(可选)">
|
||||
<button class="btn btn-light suggest-start-btn" type="button" data-box-type="{{ key }}">建议起始号</button>
|
||||
@@ -127,6 +87,9 @@
|
||||
{% if item.box.box_type == 'bag' %}
|
||||
<p>编号前缀: {{ item.box.slot_prefix }} | 袋装清单不使用范围</p>
|
||||
<p>已记录: {{ item.used_count }} 项</p>
|
||||
{% elif item.box.box_type == 'custom' %}
|
||||
<p>格数: {{ item.box.slot_capacity }} | 编号前缀: {{ item.box.slot_prefix }} | 范围: {{ item.slot_range }}</p>
|
||||
<p>已启用: {{ item.used_count }}/{{ item.box.slot_capacity }}</p>
|
||||
{% else %}
|
||||
<p>编号前缀: {{ item.box.slot_prefix }} | 范围: {{ item.slot_range }}</p>
|
||||
<p>已启用: {{ item.used_count }}/{{ item.box.slot_capacity }}</p>
|
||||
@@ -162,6 +125,9 @@
|
||||
{% if separate_mode %}<input type="hidden" name="return_to_type" value="{{ current_box_type }}">{% endif %}
|
||||
<input type="text" name="name" value="{{ item.base_name }}" required>
|
||||
<input type="text" name="slot_prefix" value="{{ item.box.slot_prefix }}" required>
|
||||
{% if item.box.box_type == 'custom' %}
|
||||
<input type="number" name="slot_capacity" min="1" value="{{ item.box.slot_capacity }}" required>
|
||||
{% endif %}
|
||||
<input type="number" name="start_number" min="0" value="{{ item.box.start_number }}" required>
|
||||
<input type="text" name="description" value="{{ item.box.description or '' }}">
|
||||
<button class="btn btn-light suggest-start-btn" type="button" data-box-id="{{ item.box.id }}" data-box-type="{{ item.box.box_type }}">建议起始号</button>
|
||||
@@ -182,53 +148,6 @@
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
function bindSidebarCompactMode() {
|
||||
var sidebar = document.querySelector('.catalog-sidebar');
|
||||
var toggleBtn = document.querySelector('.sidebar-toggle');
|
||||
if (!sidebar) {
|
||||
return;
|
||||
}
|
||||
var storageKey = 'inventorySidebarManualExpand';
|
||||
var manualExpand = false;
|
||||
|
||||
try {
|
||||
manualExpand = localStorage.getItem(storageKey) === '1';
|
||||
} catch (e) {
|
||||
manualExpand = false;
|
||||
}
|
||||
|
||||
function updateToggleState() {
|
||||
if (!toggleBtn) {
|
||||
return;
|
||||
}
|
||||
toggleBtn.setAttribute('aria-expanded', manualExpand ? 'true' : 'false');
|
||||
toggleBtn.textContent = manualExpand ? '收起低库存面板' : '展开低库存面板';
|
||||
}
|
||||
|
||||
function syncCompactState() {
|
||||
var shouldCompact = window.innerWidth > 980 && window.scrollY > 220;
|
||||
sidebar.classList.toggle('compact', shouldCompact);
|
||||
sidebar.classList.toggle('manual-expand', shouldCompact && manualExpand);
|
||||
updateToggleState();
|
||||
}
|
||||
|
||||
if (toggleBtn) {
|
||||
toggleBtn.addEventListener('click', function () {
|
||||
manualExpand = !manualExpand;
|
||||
try {
|
||||
localStorage.setItem(storageKey, manualExpand ? '1' : '0');
|
||||
} catch (e) {
|
||||
// ignore storage errors
|
||||
}
|
||||
syncCompactState();
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', syncCompactState, { passive: true });
|
||||
window.addEventListener('resize', syncCompactState);
|
||||
syncCompactState();
|
||||
}
|
||||
|
||||
function showToast(message) {
|
||||
var stack = document.querySelector('.toast-stack');
|
||||
if (!stack) {
|
||||
@@ -273,6 +192,8 @@
|
||||
var boxType = btn.dataset.boxType || 'small_28';
|
||||
var boxId = btn.dataset.boxId || '';
|
||||
var prefix = prefixInput ? prefixInput.value.trim() : '';
|
||||
var slotCapacityInput = form.querySelector('input[name="slot_capacity"]');
|
||||
var slotCapacity = slotCapacityInput ? slotCapacityInput.value.trim() : '';
|
||||
|
||||
var params = new URLSearchParams();
|
||||
params.set('box_type', boxType);
|
||||
@@ -282,6 +203,9 @@
|
||||
if (boxId) {
|
||||
params.set('box_id', boxId);
|
||||
}
|
||||
if (slotCapacity) {
|
||||
params.set('slot_capacity', slotCapacity);
|
||||
}
|
||||
|
||||
fetch('{{ url_for('suggest_start') }}?' + params.toString())
|
||||
.then(function (resp) { return resp.json(); })
|
||||
@@ -297,8 +221,6 @@
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
bindSidebarCompactMode();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user