Files
zkxw/docs/protocol-audit-tab-height-demos/index.html
T
zlwuandCursor db31990ebe feat: 细胞存储缴费催缴、统一样本信息与协议支付能力增强
汇总近期业务改动:催缴菜单与后端、样本信息快捷登记与进度、运费关联、客户档案扩展、协议优惠/期次与押金划转,并同步 SQL 迁移与管理端页面收敛。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-10 21:20:37 +08:00

515 lines
15 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>采集协议单 · 胶囊 Tab 高度对比 Demo</title>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
rel="stylesheet"
/>
<style>
:root {
--primary: #10b981;
--primary-dark: #059669;
--primary-bg: #ecfdf5;
--mint-text: #0f172a;
--mint-text-muted: #64748b;
--border: #e2e8f0;
--surface: #fff;
--page-bg: #f1f5f9;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family:
Inter,
system-ui,
-apple-system,
'Segoe UI',
sans-serif;
font-size: 14px;
line-height: 1.5;
color: var(--mint-text);
background: var(--page-bg);
}
.banner {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
padding: 20px 28px;
background: linear-gradient(180deg, #ecfdf5 0%, #fff 100%);
border-bottom: 1px solid #d1fae5;
}
.banner h1 {
margin: 0 0 6px;
font-size: 18px;
font-weight: 600;
}
.banner p {
margin: 0;
color: var(--mint-text-muted);
font-size: 13px;
}
.banner code {
padding: 1px 6px;
border-radius: 4px;
background: #f1f5f9;
font-size: 12px;
}
.page {
max-width: 960px;
margin: 0 auto;
padding: 24px;
display: flex;
flex-direction: column;
gap: 20px;
}
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.card__head {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 14px 20px;
border-bottom: 1px solid var(--border);
background: #fafafa;
}
.card__head h2 {
margin: 0;
font-size: 15px;
font-weight: 600;
}
.meta {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--mint-text-muted);
}
.tag {
display: inline-flex;
align-items: center;
height: 22px;
padding: 0 8px;
border-radius: 999px;
font-size: 11px;
font-weight: 600;
}
.tag--current {
background: #fef3c7;
color: #b45309;
}
.tag--rec {
background: #ecfdf5;
color: #047857;
}
.tag--alt {
background: #eff6ff;
color: #1d4ed8;
}
.panel-top {
padding: 16px 24px 0;
}
.panel-top h3 {
position: relative;
margin: 0;
padding-left: 12px;
font-size: 16px;
font-weight: 600;
}
.panel-top h3::before {
content: '';
position: absolute;
left: 0;
top: 3px;
bottom: 3px;
width: 3px;
border-radius: 2px;
background: var(--primary);
}
/* —— 与 web-admin app.scss panel-pill-tabs 对齐 —— */
.panel-pill-tabs {
display: flex;
justify-content: center;
margin: 12px 24px 4px;
}
.panel-pill-tabs__track {
display: inline-flex;
gap: 4px;
padding: 4px;
background: linear-gradient(180deg, var(--primary-bg) 0%, #fff 100%);
border: 1px solid #d1fae5;
border-radius: 8px;
}
.panel-pill-tabs__btn {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 108px;
padding: 8px 20px;
border: none;
border-radius: 6px;
background: transparent;
font: inherit;
font-size: 13px;
font-weight: 500;
line-height: 1.4;
color: var(--mint-text-muted);
cursor: pointer;
white-space: nowrap;
transition:
background 0.15s,
color 0.15s,
box-shadow 0.15s;
}
.panel-pill-tabs__btn:hover:not(.is-active) {
color: #065f46;
}
.panel-pill-tabs__btn.is-active {
background: var(--primary);
color: #fff;
box-shadow: 0 1px 3px rgba(16, 185, 129, 0.28);
}
/* A:现状 --lg */
.panel-pill-tabs--lg {
margin: 16px 24px 8px;
}
.panel-pill-tabs--lg .panel-pill-tabs__track {
gap: 6px;
padding: 5px;
border-radius: 10px;
}
.panel-pill-tabs--lg .panel-pill-tabs__btn {
min-width: 140px;
padding: 10px 28px;
border-radius: 8px;
font-size: 14px;
}
/* C:中间档 --md(提案) */
.panel-pill-tabs--md {
margin: 12px 24px 6px;
}
.panel-pill-tabs--md .panel-pill-tabs__track {
gap: 5px;
padding: 4px;
border-radius: 9px;
}
.panel-pill-tabs--md .panel-pill-tabs__btn {
min-width: 124px;
padding: 8px 24px;
border-radius: 7px;
font-size: 14px;
}
.list-placeholder {
margin: 12px 24px 20px;
padding: 28px 16px;
border: 1px dashed #cbd5e1;
border-radius: 8px;
text-align: center;
color: var(--mint-text-muted);
font-size: 13px;
background: #f8fafc;
}
.measure {
display: flex;
justify-content: center;
margin: 0 24px 12px;
}
.measure__bar {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 4px 10px;
border-radius: 6px;
background: #f1f5f9;
color: var(--mint-text-muted);
font-size: 12px;
font-variant-numeric: tabular-nums;
}
.measure__bar strong {
color: var(--mint-text);
font-weight: 600;
}
.card__note {
padding: 12px 20px 16px;
border-top: 1px solid var(--border);
font-size: 13px;
color: var(--mint-text-muted);
}
.card__note strong {
color: var(--mint-text);
font-weight: 600;
}
.stack-compare {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
padding: 16px 20px 20px;
}
@media (min-width: 720px) {
.stack-compare {
grid-template-columns: repeat(3, 1fr);
align-items: end;
}
}
.mini {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 12px;
border: 1px solid var(--border);
border-radius: 8px;
background: #fafafa;
}
.mini__label {
font-size: 12px;
font-weight: 600;
color: var(--mint-text);
}
.mini .panel-pill-tabs {
margin: 0;
}
.ruler {
width: 100%;
height: 4px;
border-radius: 2px;
background: repeating-linear-gradient(
90deg,
#94a3b8 0,
#94a3b8 1px,
transparent 1px,
transparent 8px
);
opacity: 0.45;
}
</style>
</head>
<body>
<header class="banner">
<div>
<h1>采集协议单 · 胶囊 Tab 高度对比</h1>
<p>
对照线上 <code>panel-pill-tabs</code> / <code>--lg</code>,评估压缩高度后的观感。点击 Tab
可切换选中态。
</p>
</div>
</header>
<div class="page">
<!-- 并排尺子 -->
<section class="card">
<div class="card__head">
<h2>一屏并排(便于比高度)</h2>
<span class="meta">对齐底边,看垂直占用</span>
</div>
<div class="stack-compare" id="side-by-side">
<div class="mini" data-variant="lg">
<span class="mini__label">A · 现状 --lg</span>
<div class="panel-pill-tabs panel-pill-tabs--lg">
<div class="panel-pill-tabs__track" role="tablist">
<button type="button" class="panel-pill-tabs__btn is-active">细胞存储</button>
<button type="button" class="panel-pill-tabs__btn">科研捐赠</button>
</div>
</div>
<div class="ruler"></div>
<span class="meta measure-h">—</span>
</div>
<div class="mini" data-variant="default">
<span class="mini__label">B · 默认(推荐)</span>
<div class="panel-pill-tabs">
<div class="panel-pill-tabs__track" role="tablist">
<button type="button" class="panel-pill-tabs__btn is-active">细胞存储</button>
<button type="button" class="panel-pill-tabs__btn">科研捐赠</button>
</div>
</div>
<div class="ruler"></div>
<span class="meta measure-h">—</span>
</div>
<div class="mini" data-variant="md">
<span class="mini__label">C · 中间档 --md</span>
<div class="panel-pill-tabs panel-pill-tabs--md">
<div class="panel-pill-tabs__track" role="tablist">
<button type="button" class="panel-pill-tabs__btn is-active">细胞存储</button>
<button type="button" class="panel-pill-tabs__btn">科研捐赠</button>
</div>
</div>
<div class="ruler"></div>
<span class="meta measure-h">—</span>
</div>
</div>
</section>
<!-- A -->
<section class="card" data-panel>
<div class="card__head">
<h2>A · 现状 panel-pill-tabs--lg</h2>
<span class="tag tag--current">当前线上</span>
</div>
<div class="panel-top"><h3>采集协议单</h3></div>
<div class="panel-pill-tabs panel-pill-tabs--lg" data-tabs>
<div class="panel-pill-tabs__track" role="tablist" aria-label="协议来源">
<button type="button" class="panel-pill-tabs__btn is-active">细胞存储</button>
<button type="button" class="panel-pill-tabs__btn">科研捐赠</button>
</div>
</div>
<div class="measure">
<span class="measure__bar">Tab 区域高度(含上下 margin)≈ <strong data-h>—</strong></span>
</div>
<div class="list-placeholder">下方列表区占位(筛选 / 表格…)</div>
<div class="card__note">
<strong>尺寸:</strong>margin 16/8 · track padding 5 · btn padding 10×28 · 字号 14 ·
min-width 140
</div>
</section>
<!-- B -->
<section class="card" data-panel>
<div class="card__head">
<h2>B · 默认 panel-pill-tabs(去掉 --lg)</h2>
<span class="tag tag--rec">方案 1 推荐</span>
</div>
<div class="panel-top"><h3>采集协议单</h3></div>
<div class="panel-pill-tabs" data-tabs>
<div class="panel-pill-tabs__track" role="tablist" aria-label="协议来源">
<button type="button" class="panel-pill-tabs__btn is-active">细胞存储</button>
<button type="button" class="panel-pill-tabs__btn">科研捐赠</button>
</div>
</div>
<div class="measure">
<span class="measure__bar">Tab 区域高度(含上下 margin)≈ <strong data-h>—</strong></span>
</div>
<div class="list-placeholder">下方列表区占位(筛选 / 表格…)</div>
<div class="card__note">
<strong>尺寸:</strong>margin 12/4 · track padding 4 · btn padding 8×20 · 字号 13 ·
min-width 108 · 仅改本页 class,全站 --lg 不变
</div>
</section>
<!-- C -->
<section class="card" data-panel>
<div class="card__head">
<h2>C · 中间档 panel-pill-tabs--md(提案)</h2>
<span class="tag tag--alt">方案 3</span>
</div>
<div class="panel-top"><h3>采集协议单</h3></div>
<div class="panel-pill-tabs panel-pill-tabs--md" data-tabs>
<div class="panel-pill-tabs__track" role="tablist" aria-label="协议来源">
<button type="button" class="panel-pill-tabs__btn is-active">细胞存储</button>
<button type="button" class="panel-pill-tabs__btn">科研捐赠</button>
</div>
</div>
<div class="measure">
<span class="measure__bar">Tab 区域高度(含上下 margin)≈ <strong data-h>—</strong></span>
</div>
<div class="list-placeholder">下方列表区占位(筛选 / 表格…)</div>
<div class="card__note">
<strong>尺寸:</strong>margin 12/6 · track padding 4 · btn padding 8×24 · 字号 14 ·
min-width 124 · 需新增全局修饰类
</div>
</section>
</div>
<script>
function bindTabs(root) {
const track = root.querySelector('.panel-pill-tabs__track')
if (!track) return
track.addEventListener('click', (e) => {
const btn = e.target.closest('.panel-pill-tabs__btn')
if (!btn || !track.contains(btn)) return
track.querySelectorAll('.panel-pill-tabs__btn').forEach((b) => b.classList.remove('is-active'))
btn.classList.add('is-active')
})
}
function measureOuter(el) {
const style = getComputedStyle(el)
const mt = parseFloat(style.marginTop) || 0
const mb = parseFloat(style.marginBottom) || 0
return Math.round(el.getBoundingClientRect().height + mt + mb)
}
function measureTrack(el) {
const track = el.querySelector('.panel-pill-tabs__track')
return track ? Math.round(track.getBoundingClientRect().height) : 0
}
document.querySelectorAll('[data-tabs]').forEach(bindTabs)
document.querySelectorAll('#side-by-side .mini .panel-pill-tabs').forEach(bindTabs)
function refreshMeasures() {
document.querySelectorAll('[data-panel]').forEach((panel) => {
const tabs = panel.querySelector('[data-tabs]')
const label = panel.querySelector('[data-h]')
if (!tabs || !label) return
label.textContent = measureOuter(tabs) + 'px(轨道 ' + measureTrack(tabs) + 'px)'
})
document.querySelectorAll('#side-by-side .mini').forEach((mini) => {
const tabs = mini.querySelector('.panel-pill-tabs')
const label = mini.querySelector('.measure-h')
if (!tabs || !label) return
label.textContent =
'外高 ' + measureOuter(tabs) + 'px · 轨道 ' + measureTrack(tabs) + 'px'
})
}
refreshMeasures()
window.addEventListener('resize', refreshMeasures)
</script>
</body>
</html>