Files
zkxw/docs/unused-material-demos/04-quick-add.html
T
2026-06-14 17:20:52 +08:00

349 lines
12 KiB
HTML
Raw 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>04 检索优先 · 登记未用完 Demo</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="_shared.css" />
<style>
.add-zone {
padding: 14px 16px;
background: linear-gradient(135deg, var(--primary-bg) 0%, #f0fdf4 100%);
border: 1px solid #a7f3d0;
border-radius: var(--radius-sm);
margin-bottom: 16px;
}
.add-zone__title {
font-size: 13px;
font-weight: 600;
color: var(--primary-dark);
margin-bottom: 10px;
}
.add-row {
display: grid;
grid-template-columns: 1fr auto auto;
gap: 10px;
align-items: end;
}
.batch-search-wrap {
position: relative;
}
.batch-search-wrap .input {
height: var(--control-h);
padding-left: 36px;
font-size: 14px;
}
.search-icon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
pointer-events: none;
}
.recent-chips {
display: flex;
gap: 6px;
flex-wrap: wrap;
margin-top: 10px;
}
.chip {
padding: 4px 10px;
border-radius: 999px;
font-size: 12px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text-muted);
cursor: pointer;
}
.chip:hover {
border-color: var(--primary);
color: var(--primary-dark);
background: var(--primary-bg);
}
.compact-table .data-table th,
.compact-table .data-table td {
padding: 6px 8px;
}
.compact-table .input {
height: 28px;
font-size: 12px;
padding: 0 8px;
}
.material-cell {
text-align: left !important;
max-width: 200px;
}
.material-cell__name {
font-weight: 600;
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.material-cell__sub {
font-size: 11px;
color: var(--text-muted);
margin-top: 2px;
}
.drawer-hint {
font-size: 11px;
color: var(--primary-dark);
cursor: pointer;
text-decoration: underline;
text-underline-offset: 2px;
}
/* 模拟侧滑层 */
.side-drawer {
display: none;
position: fixed;
inset: 0;
z-index: 400;
}
.side-drawer.is-open {
display: block;
}
.side-drawer__mask {
position: absolute;
inset: 0;
background: rgba(15, 23, 42, 0.35);
}
.side-drawer__panel {
position: absolute;
top: 0;
right: 0;
width: min(420px, 100%);
height: 100%;
background: var(--surface);
box-shadow: -8px 0 32px rgba(15, 23, 42, 0.12);
display: flex;
flex-direction: column;
}
.side-drawer__head {
padding: 16px 18px;
border-bottom: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: center;
}
.side-drawer__body {
flex: 1;
overflow-y: auto;
padding: 16px 18px;
}
.side-drawer__foot {
padding: 12px 18px;
border-top: 1px solid var(--border);
display: flex;
justify-content: flex-end;
gap: 8px;
}
.drawer-form {
display: flex;
flex-direction: column;
gap: 12px;
}
</style>
</head>
<body>
<header class="demo-banner">
<div>
<h1><span class="demo-badge">04 检索优先</span> 登记未用完物料</h1>
<p>顶部批次检索添加入口 · 精简 7 列表格 · 手工登记走侧滑</p>
</div>
<div class="demo-banner__actions">
<a href="index.html">← 选型索引</a>
<a href="03-collapsible.html">03 折叠</a>
<a class="is-current" href="04-quick-add.html">04 检索</a>
<a href="05-current-baseline.html">05 现状</a>
</div>
</header>
<div class="page-wrap">
<div class="dialog-backdrop">
<div class="dialog dialog--wide" role="dialog">
<div class="dialog__head">
<h2 class="dialog__title">登记未用完物料</h2>
<button type="button" class="dialog__close">×</button>
</div>
<div class="dialog__body">
<div class="add-zone">
<div class="add-zone__title">从库存批次添加</div>
<div class="add-row">
<div class="batch-search-wrap">
<span class="search-icon">🔍</span>
<input type="search" class="input" id="batch-search" placeholder="输入入库编号、物料名称、批号、货号检索…" />
</div>
<button type="button" class="btn btn-primary" id="mock-add">添加选中批次</button>
<button type="button" class="btn" id="open-drawer">手工登记</button>
</div>
<div class="recent-chips">
<span style="font-size: 11px; color: var(--text-muted); align-self: center">最近:</span>
<button type="button" class="chip">RK202506001 · 胎牛血清</button>
<button type="button" class="chip">RK202506008 · DMEM</button>
<button type="button" class="chip">RK202506015 · 双抗</button>
</div>
</div>
<div class="section-head">
<div class="section-head__left">
<div class="section-title">已登记明细 <span class="stat-pill" style="margin-left: 8px">共 <strong id="line-count">0</strong> 项</span></div>
<div class="section-hint">表格仅保留登记所需核心列;完整批次信息点击「详情」查看。</div>
</div>
</div>
<div class="table-scroll compact-table">
<table class="data-table">
<thead>
<tr>
<th style="min-width: 40px">#</th>
<th class="material-cell" style="min-width: 180px">物料</th>
<th style="min-width: 88px">未用完数量</th>
<th style="min-width: 72px">单位</th>
<th style="min-width: 96px">剩余金额</th>
<th style="min-width: 88px">持有人</th>
<th style="min-width: 100px">备注</th>
<th style="min-width: 72px">详情</th>
<th style="min-width: 44px">删</th>
</tr>
</thead>
<tbody id="tbody"></tbody>
</table>
</div>
</div>
<div class="dialog__foot">
<button type="button" class="btn btn-ghost">取消</button>
<button type="button" class="btn btn-primary">保存</button>
</div>
</div>
</div>
<div class="side-drawer" id="drawer">
<div class="side-drawer__mask" id="drawer-close"></div>
<div class="side-drawer__panel">
<div class="side-drawer__head">
<strong>手工登记</strong>
<button type="button" class="dialog__close" id="drawer-x">×</button>
</div>
<div class="side-drawer__body">
<div class="drawer-form">
<div><label class="field-label">物料名称 <span style="color: var(--danger)">*</span></label><input class="input" placeholder="必填" /></div>
<div><label class="field-label">批号</label><input class="input" placeholder="可选" /></div>
<div><label class="field-label">规格型号</label><input class="input" /></div>
<div><label class="field-label">单位</label><input class="input" /></div>
<div><label class="field-label">单价(元)</label><input class="input input-num" type="number" /></div>
<div><label class="field-label">未用完数量 <span style="color: var(--danger)">*</span></label><input class="input input-num" type="number" value="1" /></div>
<div><label class="field-label">持有人</label><input class="input" /></div>
<div><label class="field-label">备注</label><input class="input" /></div>
</div>
</div>
<div class="side-drawer__foot">
<button type="button" class="btn btn-ghost" id="drawer-cancel">取消</button>
<button type="button" class="btn btn-primary">加入列表</button>
</div>
</div>
</div>
<p class="style-note">
<strong>适用场景:</strong>绝大多数行来自批次检索,手工登记是少数。
<ul>
<li>检索区视觉权重最高,减少「先点新增再找批次」的步骤</li>
<li>表格 7 列 + 操作,20 条仍可在 520px 高度内滚动浏览</li>
<li>手工登记字段多,放侧滑不打断主列表节奏(Demo 可点「手工登记」体验)</li>
</ul>
</p>
</div>
<script src="_demo-data.js"></script>
<script>
let rows = [...DEMO_UNUSED_LINES]
const tbody = document.getElementById('tbody')
const drawer = document.getElementById('drawer')
function openDrawer() {
drawer.classList.add('is-open')
}
function closeDrawer() {
drawer.classList.remove('is-open')
}
document.getElementById('open-drawer').addEventListener('click', openDrawer)
document.getElementById('drawer-close').addEventListener('click', closeDrawer)
document.getElementById('drawer-x').addEventListener('click', closeDrawer)
document.getElementById('drawer-cancel').addEventListener('click', closeDrawer)
document.getElementById('mock-add').addEventListener('click', () => {
alert('Demo:选中批次后会插入表格首行,并自动聚焦「未用完数量」')
})
function render() {
tbody.innerHTML = rows
.map((row, i) => {
const amt = formatMoney(calcAmount(row.unitPrice, row.unusedQty))
return `<tr>
<td><span class="row-index">${i + 1}</span></td>
<td class="material-cell">
<div class="material-cell__name">${row.materialName}</div>
<div class="material-cell__sub">${row.stockInNo || '手工'} · ${row.batchNo || '—'} · ${row.manufacturer || '—'}</div>
</td>
<td><input class="input input-num qty" data-id="${row.id}" type="number" value="${row.unusedQty}" min="0.01" step="0.01" /></td>
<td>${row.unit || '—'}</td>
<td class="money">${amt}</td>
<td><input class="input holder" data-id="${row.id}" value="${row.holder || ''}" placeholder="持有人" /></td>
<td><input class="input remark" data-id="${row.id}" value="${row.remark || ''}" placeholder="可选" /></td>
<td><span class="drawer-hint detail-link" data-id="${row.id}">查看</span></td>
<td><button type="button" class="btn btn-danger-link btn-sm del" data-id="${row.id}">×</button></td>
</tr>`
})
.join('')
document.getElementById('line-count').textContent = rows.length
}
tbody.addEventListener('input', (e) => {
const row = rows.find((r) => r.id === Number(e.target.dataset.id))
if (!row) return
if (e.target.classList.contains('qty')) {
row.unusedQty = Number(e.target.value) || 0
render()
} else if (e.target.classList.contains('holder')) row.holder = e.target.value
else if (e.target.classList.contains('remark')) row.remark = e.target.value
})
tbody.addEventListener('click', (e) => {
if (e.target.classList.contains('del')) {
rows = rows.filter((r) => r.id !== Number(e.target.dataset.id))
render()
}
if (e.target.classList.contains('detail-link')) {
alert('Demo:打开只读详情 Popover / Drawer,展示完整批次字段')
}
})
render()
</script>
</body>
</html>