汇总近期业务改动:催缴菜单与后端、样本信息快捷登记与进度、运费关联、客户档案扩展、协议优惠/期次与押金划转,并同步 SQL 迁移与管理端页面收敛。 Co-authored-by: Cursor <cursoragent@cursor.com>
515 lines
15 KiB
HTML
515 lines
15 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>采集协议单 · 胶囊 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>
|