349 lines
12 KiB
HTML
349 lines
12 KiB
HTML
<!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>
|