290 lines
11 KiB
HTML
290 lines
11 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>03 折叠摘要行 · 登记未用完 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>
|
||
.accordion-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
max-height: 520px;
|
||
overflow-y: auto;
|
||
padding-right: 2px;
|
||
}
|
||
|
||
.acc-item {
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-sm);
|
||
background: var(--surface);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.acc-item.is-expanded {
|
||
border-color: #a7f3d0;
|
||
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.08);
|
||
}
|
||
|
||
.acc-summary {
|
||
display: grid;
|
||
grid-template-columns: 32px 1fr auto auto auto 72px 32px;
|
||
gap: 12px;
|
||
align-items: center;
|
||
padding: 10px 12px;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
}
|
||
|
||
.acc-summary:hover {
|
||
background: #fafafa;
|
||
}
|
||
|
||
.acc-item.is-expanded .acc-summary {
|
||
background: var(--primary-bg);
|
||
border-bottom: 1px solid #d1fae5;
|
||
}
|
||
|
||
.acc-chevron {
|
||
width: 20px;
|
||
height: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--text-muted);
|
||
transition: transform 0.2s;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.acc-item.is-expanded .acc-chevron {
|
||
transform: rotate(90deg);
|
||
color: var(--primary-dark);
|
||
}
|
||
|
||
.acc-name {
|
||
font-weight: 600;
|
||
font-size: 13px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.acc-meta {
|
||
font-size: 12px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.acc-inline-qty {
|
||
width: 72px;
|
||
}
|
||
|
||
.acc-body {
|
||
display: none;
|
||
padding: 12px 14px 14px;
|
||
background: #fafafa;
|
||
}
|
||
|
||
.acc-item.is-expanded .acc-body {
|
||
display: block;
|
||
}
|
||
|
||
.acc-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
gap: 10px 14px;
|
||
}
|
||
|
||
.acc-col-span-2 {
|
||
grid-column: span 2;
|
||
}
|
||
|
||
.acc-col-span-4 {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
.bulk-bar {
|
||
display: flex;
|
||
gap: 8px;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.bulk-bar .input {
|
||
width: 140px;
|
||
}
|
||
|
||
@media (max-width: 960px) {
|
||
.acc-summary {
|
||
grid-template-columns: 28px 1fr auto 72px 28px;
|
||
}
|
||
.acc-summary .acc-meta:nth-child(4),
|
||
.acc-summary .acc-meta:nth-child(5) {
|
||
display: none;
|
||
}
|
||
.acc-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header class="demo-banner">
|
||
<div>
|
||
<h1><span class="demo-badge">03 折叠摘要行</span> 登记未用完物料</h1>
|
||
<p>默认一行摘要 + 行内改数量 · 点击展开完整字段</p>
|
||
</div>
|
||
<div class="demo-banner__actions">
|
||
<a href="index.html">← 选型索引</a>
|
||
<a href="01-inline-table.html">01 表格</a>
|
||
<a class="is-current" href="03-collapsible.html">03 折叠</a>
|
||
<a href="04-quick-add.html">04 检索</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="section-head">
|
||
<div class="section-head__left">
|
||
<div class="section-title">未用完明细</div>
|
||
<div class="section-hint">折叠态可快速改数量;需改批次或手工字段时再展开。支持全部展开/收起。</div>
|
||
</div>
|
||
<div class="section-tools">
|
||
<span class="stat-pill">共 <strong id="line-count">0</strong> 项</span>
|
||
<button type="button" class="btn btn-sm" id="expand-all">全部展开</button>
|
||
<button type="button" class="btn btn-sm" id="collapse-all">全部收起</button>
|
||
<button type="button" class="btn btn-sm">+ 新增一行</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bulk-bar">
|
||
<span style="font-size: 12px; color: var(--text-muted)">批量填充持有人:</span>
|
||
<input type="text" class="input" id="bulk-holder" placeholder="输入姓名" />
|
||
<button type="button" class="btn btn-sm" id="apply-holder">应用到全部</button>
|
||
<input type="search" class="input" style="width: 200px; margin-left: auto" placeholder="过滤…" id="filter" />
|
||
</div>
|
||
|
||
<div class="accordion-list" id="accordion"></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>
|
||
|
||
<p class="style-note">
|
||
<strong>适用场景:</strong>多数行只需改数量/持有人,少数行需展开核对批次。
|
||
<ul>
|
||
<li>比现状卡片省约 70% 纵向空间,10 条折叠态一屏可见</li>
|
||
<li>摘要行右侧 inline 数量框,无需展开即可改</li>
|
||
<li>展开区 4 列栅格,比现状 5~6 列略疏,控件 32px</li>
|
||
</ul>
|
||
</p>
|
||
</div>
|
||
|
||
<script src="_demo-data.js"></script>
|
||
<script>
|
||
let rows = [...DEMO_UNUSED_LINES]
|
||
const expanded = new Set([rows[0]?.id])
|
||
const accordion = document.getElementById('accordion')
|
||
|
||
function render() {
|
||
const kw = (document.getElementById('filter').value || '').trim().toLowerCase()
|
||
const filtered = rows.filter((r) => !kw || materialSummary(r).toLowerCase().includes(kw))
|
||
|
||
accordion.innerHTML = filtered
|
||
.map((row, i) => {
|
||
const isExp = expanded.has(row.id)
|
||
const amt = formatMoney(calcAmount(row.unitPrice, row.unusedQty))
|
||
return `<div class="acc-item ${isExp ? 'is-expanded' : ''}" data-id="${row.id}">
|
||
<div class="acc-summary" data-toggle="${row.id}">
|
||
<span class="acc-chevron">▸</span>
|
||
<span class="row-index">${rows.indexOf(row) + 1}</span>
|
||
<span class="acc-name" title="${row.materialName}">${row.materialName}</span>
|
||
<span class="acc-meta">${row.batchNo || '—'}</span>
|
||
<span class="acc-meta">${row.holder || '—'}</span>
|
||
<span class="acc-meta money">${amt} 元</span>
|
||
<input class="input acc-inline-qty qty-inline" type="number" min="0.01" step="0.01" value="${row.unusedQty}" data-id="${row.id}" onclick="event.stopPropagation()" />
|
||
<button type="button" class="btn btn-danger-link btn-sm del-btn" data-id="${row.id}" onclick="event.stopPropagation()">×</button>
|
||
</div>
|
||
<div class="acc-body">
|
||
<div class="acc-grid">
|
||
<div class="acc-col-span-2">
|
||
<label class="field-label">批次检索</label>
|
||
<select class="select" ${row.fromBatch ? 'disabled' : ''}><option>${row.fromBatch ? row.stockInNo + ' · ' + row.materialName : '检索或手工'}</option></select>
|
||
</div>
|
||
<div><label class="field-label">入库编号</label><input class="input input--readonly" readonly value="${row.stockInNo || ''}" /></div>
|
||
<div><label class="field-label">批号</label><input class="input input--readonly" readonly value="${row.batchNo || ''}" /></div>
|
||
<div><label class="field-label">物料编码</label><input class="input input--readonly" readonly value="${row.materialCode || ''}" /></div>
|
||
<div><label class="field-label">货号</label><input class="input input--readonly" readonly value="${row.catalogNo || ''}" /></div>
|
||
<div><label class="field-label">规格</label><input class="input input--readonly" readonly value="${row.specModel || ''}" /></div>
|
||
<div><label class="field-label">单位</label><input class="input input--readonly" readonly value="${row.unit || ''}" /></div>
|
||
<div><label class="field-label">厂家</label><input class="input input--readonly" readonly value="${row.manufacturer || ''}" /></div>
|
||
<div><label class="field-label">单价</label><input class="input input--readonly" readonly value="${formatMoney(row.unitPrice)}" /></div>
|
||
<div><label class="field-label">持有人</label><input class="input holder-field" data-id="${row.id}" value="${row.holder || ''}" /></div>
|
||
<div class="acc-col-span-4"><label class="field-label">备注</label><input class="input remark-field" data-id="${row.id}" value="${row.remark || ''}" /></div>
|
||
</div>
|
||
</div>
|
||
</div>`
|
||
})
|
||
.join('')
|
||
|
||
document.getElementById('line-count').textContent = rows.length
|
||
}
|
||
|
||
accordion.addEventListener('click', (e) => {
|
||
if (e.target.classList.contains('del-btn')) {
|
||
const id = Number(e.target.dataset.id)
|
||
rows = rows.filter((r) => r.id !== id)
|
||
expanded.delete(id)
|
||
render()
|
||
return
|
||
}
|
||
const toggle = e.target.closest('[data-toggle]')
|
||
if (toggle && !e.target.classList.contains('qty-inline')) {
|
||
const id = Number(toggle.dataset.toggle)
|
||
if (expanded.has(id)) expanded.delete(id)
|
||
else expanded.add(id)
|
||
render()
|
||
}
|
||
})
|
||
|
||
accordion.addEventListener('input', (e) => {
|
||
const id = Number(e.target.dataset.id)
|
||
const row = rows.find((r) => r.id === id)
|
||
if (!row) return
|
||
if (e.target.classList.contains('qty-inline')) row.unusedQty = Number(e.target.value) || 0
|
||
if (e.target.classList.contains('holder-field')) row.holder = e.target.value
|
||
if (e.target.classList.contains('remark-field')) row.remark = e.target.value
|
||
if (e.target.classList.contains('qty-inline')) render()
|
||
})
|
||
|
||
document.getElementById('expand-all').addEventListener('click', () => {
|
||
rows.forEach((r) => expanded.add(r.id))
|
||
render()
|
||
})
|
||
document.getElementById('collapse-all').addEventListener('click', () => {
|
||
expanded.clear()
|
||
render()
|
||
})
|
||
document.getElementById('apply-holder').addEventListener('click', () => {
|
||
const v = document.getElementById('bulk-holder').value.trim()
|
||
if (!v) return
|
||
rows.forEach((r) => (r.holder = v))
|
||
render()
|
||
})
|
||
document.getElementById('filter').addEventListener('input', render)
|
||
render()
|
||
</script>
|
||
</body>
|
||
</html>
|