| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- <!doctype html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>运输计划列表 · 三区列(基础 / 装货 / 送货)合并 Demo</title>
- <link rel="preconnect" href="https://fonts.googleapis.com" />
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
- <style>
- :root {
- --primary: #10b981;
- --primary-dark: #059669;
- --primary-bg: #ecfdf5;
- --text: #1e293b;
- --muted: #64748b;
- --border: #d9e8e2;
- --head: #f8fafc;
- --page: #eef2f6;
- --panel: #fff;
- --warn: #d97706;
- --danger: #dc2626;
- --alt: #fafafa;
- --load-bg: #ecfdf5;
- --delivery-bg: #f0f9ff;
- --base-bg: #f8fafc;
- --load-border: #a7f3d0;
- --delivery-border: #bae6fd;
- --base-border: #cbd5e1;
- }
- * { box-sizing: border-box; }
- body {
- margin: 0;
- padding: 24px 20px 80px;
- font-family: Inter, "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
- font-size: 14px;
- line-height: 1.5;
- color: var(--text);
- background: var(--page);
- }
- .page { max-width: 1680px; margin: 0 auto; }
- .hero {
- background: linear-gradient(135deg, #ecfdf5 0%, #fff 55%, #f0f9ff 100%);
- border: 1px solid var(--border);
- border-radius: 10px;
- padding: 20px 22px;
- margin-bottom: 16px;
- }
- .hero h1 { margin: 0 0 8px; font-size: 22px; font-weight: 700; }
- .hero h1 em { font-style: normal; color: var(--primary-dark); }
- .hero p { margin: 0; color: var(--muted); max-width: 1100px; }
- .pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
- .pill {
- font-size: 12px; font-weight: 600; padding: 4px 10px; border-radius: 999px;
- background: var(--primary-bg); color: var(--primary-dark); border: 1px solid #a7f3d0;
- }
- .pill.muted { background: #f1f5f9; color: var(--muted); border-color: #e2e8f0; }
- .pill.warn { background: #fffbeb; color: var(--warn); border-color: #fde68a; }
- .pill.base { background: #f1f5f9; color: #334155; border-color: #cbd5e1; }
- .pill.load { background: var(--load-bg); color: var(--primary-dark); border-color: var(--load-border); }
- .pill.need { background: var(--delivery-bg); color: #0369a1; border-color: var(--delivery-border); }
- .tabs {
- display: flex; flex-wrap: wrap; gap: 6px;
- background: var(--panel); border: 1px solid var(--border);
- border-radius: 10px 10px 0 0; padding: 8px 10px 0;
- }
- .tab {
- border: none; background: transparent; cursor: pointer; font-family: inherit;
- padding: 10px 14px; font-size: 13px; font-weight: 600; color: var(--muted);
- border-bottom: 2px solid transparent;
- }
- .tab:hover { color: var(--primary-dark); }
- .tab.active { color: var(--primary-dark); border-bottom-color: var(--primary); }
- .tab .rec {
- margin-left: 6px; font-size: 10px; padding: 1px 6px; border-radius: 999px;
- background: var(--primary-bg); color: var(--primary-dark); border: 1px solid #a7f3d0;
- }
- .panel {
- display: none;
- background: var(--panel);
- border: 1px solid var(--border);
- border-top: none;
- border-radius: 0 0 10px 10px;
- padding: 16px 18px 22px;
- }
- .panel.active { display: block; }
- .desc {
- margin: 0 0 12px; padding: 12px 14px; border-radius: 8px;
- background: #f0f9ff; border: 1px solid #bae6fd; color: #0369a1; font-size: 13px;
- }
- .desc strong { color: var(--text); }
- .ok {
- margin: 0 0 14px; padding: 10px 12px; border-radius: 8px;
- background: #ecfdf5; border: 1px solid #a7f3d0; color: #065f46; font-size: 12.5px;
- }
- .pain {
- margin: 0 0 14px; padding: 10px 12px; border-radius: 8px;
- background: #fef2f2; border: 1px solid #fecaca; color: #991b1b; font-size: 12.5px;
- }
- .legend {
- display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 14px; font-size: 12px; color: var(--muted);
- }
- .legend span {
- display: inline-flex; align-items: center; gap: 6px;
- padding: 4px 8px; border-radius: 6px; border: 1px solid var(--border);
- }
- .swatch { width: 12px; height: 12px; border-radius: 3px; border: 1px solid rgba(0,0,0,.08); }
- .swatch.base { background: #e2e8f0; }
- .swatch.load { background: #a7f3d0; }
- .swatch.need { background: #7dd3fc; }
- .swatch.prod { background: #fde68a; }
- .table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: 8px; }
- table.list {
- width: 100%;
- border-collapse: collapse;
- min-width: 1280px;
- background: #fff;
- }
- table.list th,
- table.list td {
- border-bottom: 1px solid var(--border);
- border-right: 1px solid #eef2f0;
- padding: 10px 12px;
- vertical-align: top;
- font-size: 13px;
- }
- table.list th:last-child,
- table.list td:last-child { border-right: none; }
- table.list thead th {
- position: sticky; top: 0; z-index: 2;
- background: var(--head);
- color: var(--muted);
- font-size: 12px;
- font-weight: 600;
- white-space: nowrap;
- text-align: left;
- }
- table.list thead tr.zone-row th {
- text-align: center;
- font-size: 12px;
- letter-spacing: 0.02em;
- border-bottom: 1px solid var(--border);
- }
- table.list thead th.zone-base {
- background: #e2e8f0 !important; color: #334155 !important;
- }
- table.list thead th.zone-load {
- background: #d1fae5 !important; color: var(--primary-dark) !important;
- }
- table.list thead th.zone-need {
- background: #bae6fd !important; color: #0369a1 !important;
- }
- table.list thead th.zone-prod {
- background: #fef3c7 !important; color: #92400e !important;
- }
- table.list thead th.col-base { background: #f1f5f9 !important; }
- table.list thead th.col-load { background: #ecfdf5 !important; color: var(--primary-dark) !important; }
- table.list thead th.col-need { background: #e0f2fe !important; color: #0369a1 !important; }
- table.list thead th.col-prod { background: #fffbeb !important; color: #92400e !important; }
- table.list tbody tr:hover td { background: #f8fafc; }
- table.list a { color: var(--primary-dark); font-weight: 500; text-decoration: none; }
- table.list a:hover { text-decoration: underline; }
- td.cell-base { background: rgba(241, 245, 249, 0.55); }
- td.cell-load { background: rgba(236, 253, 245, 0.55); }
- td.cell-need { background: rgba(240, 249, 255, 0.65); }
- td.cell-prod { background: #fff; }
- td.plan-end { border-bottom: 2px solid #94a3b8 !important; }
- .tag {
- display: inline-flex; align-items: center;
- padding: 1px 8px; border-radius: 6px;
- font-size: 12px; font-weight: 600; line-height: 1.45; white-space: nowrap;
- }
- .tag.success { background: #059669; color: #fff; }
- .tag.warn { background: #d97706; color: #fff; }
- .tag.danger { background: #dc2626; color: #fff; }
- .tag.side-load {
- background: var(--load-bg); color: var(--primary-dark);
- border: 1px solid var(--load-border);
- }
- .tag.side-need {
- background: var(--delivery-bg); color: #0369a1;
- border: 1px solid var(--delivery-border);
- }
- .muted { color: var(--muted); }
- .stack { display: flex; flex-direction: column; gap: 4px; }
- .stack .sub { color: var(--muted); font-size: 12px; }
- .name-with-mark {
- display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px;
- }
- .seg-divider {
- margin: 8px 0;
- border: 0;
- border-top: 1px dashed #cbd5e1;
- }
- .hint-row {
- font-size: 11px; color: var(--muted); margin-top: 4px;
- }
- .meta {
- margin-top: 14px; font-size: 12px; color: var(--muted);
- }
- .meta code {
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
- background: #f1f5f9; padding: 1px 6px; border-radius: 4px;
- }
- </style>
- </head>
- <body>
- <div class="page">
- <header class="hero">
- <h1>运输计划列表 · <em>三区列</em>(基础 / 装货 / 送货)合并 Demo</h1>
- <p>
- 案例:<strong>PO20261009016</strong> —— 1 个装货段、2 个送货段;
- 展平后产品侧共 3 行(1 供产品 + 2 需产品)。
- 目标验证:列表分成<strong>基础信息列</strong>、<strong>装货段次列</strong>、<strong>送货段次列</strong>三块,并各自做合并单元格时的观感。
- </p>
- <div class="pills">
- <span class="pill">PO20261009016</span>
- <span class="pill warn">待安排</span>
- <span class="pill muted">皖R4B299/皖R8131挂</span>
- <span class="pill base">基础信息区</span>
- <span class="pill load">装货段次区</span>
- <span class="pill need">送货段次区</span>
- </div>
- </header>
- <div class="tabs" role="tablist">
- <button class="tab active" data-tab="a" type="button">
- 方案 A · 送货按段合并(跨产品行)<span class="rec">贴近你的描述</span>
- </button>
- <button class="tab" data-tab="b" type="button">方案 B · 送货整单合并(格内叠段)</button>
- <button class="tab" data-tab="c" type="button">对照 · 现状(供行出现 —)</button>
- </div>
- <!-- 方案 A -->
- <section class="panel active" id="panel-a">
- <p class="desc">
- <strong>方案 A:</strong>表头分三区。
- 行模型仍是「先 1 行供产品,再各送货段产品行」(本单共 3 行)。
- <strong>基础区 / 装货区</strong>整单合并(rowspan=3);
- <strong>送货区</strong>按送货段合并——第 1 个送货段 rowspan=2(盖住供产品行 + 该送货产品行),第 2 个送货段 rowspan=1。
- 送货列<strong>不再出现「—」占位行</strong>,但第 1 个送货客户会在视觉上与供产品行对齐(略高一截)。
- </p>
- <p class="ok">
- 可实现:三区列 + 合并单元格都成立;送货客户/地址恰好 2 段。
- 代价:多送货时,第一个送货段的合并格会「借」供侧产品行的高度,和产品行不是严格语义对齐。
- </p>
- <div class="legend">
- <span><i class="swatch base"></i>基础信息(整单合并)</span>
- <span><i class="swatch load"></i>装货段次(整单合并)</span>
- <span><i class="swatch need"></i>送货段次(按段合并)</span>
- <span><i class="swatch prod"></i>产品明细(不合并)</span>
- </div>
- <div class="table-wrap">
- <table class="list">
- <thead>
- <tr class="zone-row">
- <th class="zone-base" colspan="5">基础信息</th>
- <th class="zone-load" colspan="3">装货段次</th>
- <th class="zone-need" colspan="3">送货段次</th>
- <th class="zone-prod" colspan="4">产品明细(供/需)</th>
- </tr>
- <tr>
- <th class="col-base">计划编号</th>
- <th class="col-base">跟进状态</th>
- <th class="col-base">计划日期</th>
- <th class="col-base">车牌号</th>
- <th class="col-base">人员</th>
- <th class="col-load">装货客户</th>
- <th class="col-load">装货地址/时间</th>
- <th class="col-load">供合同</th>
- <th class="col-need">送货客户</th>
- <th class="col-need">送货地址/时间</th>
- <th class="col-need">需合同</th>
- <th class="col-prod">侧别</th>
- <th class="col-prod">产品名称</th>
- <th class="col-prod">单位</th>
- <th class="col-prod">计划量</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td class="cell-base" rowspan="3">
- <a href="#">PO20261009016</a>
- </td>
- <td class="cell-base" rowspan="3"><span class="tag danger">待安排</span></td>
- <td class="cell-base" rowspan="3">2026-10-13</td>
- <td class="cell-base" rowspan="3">皖R4B299/皖R8131挂</td>
- <td class="cell-base" rowspan="3">彭双青(驾)、汪的霞(押)</td>
- <td class="cell-load" rowspan="3">铜陵华博精细化工有限公司</td>
- <td class="cell-load" rowspan="3">
- <div class="stack">
- <span>铜官大道南段3888号铜陵市华兴化工有限公司</span>
- <span class="sub">2026-10-13</span>
- </div>
- </td>
- <td class="cell-load" rowspan="3"><span class="muted">—</span></td>
- <td class="cell-need" rowspan="2">
- 合肥瞻宇环保科技有限公司
- <div class="hint-row">rowspan=2(含上方供产品行高度)</div>
- </td>
- <td class="cell-need" rowspan="2">
- <div class="stack">
- <span class="muted">—</span>
- <span class="sub">2026-10-13</span>
- </div>
- </td>
- <td class="cell-need" rowspan="2"><span class="muted">—</span></td>
- <td class="cell-prod"><span class="tag side-load">供</span></td>
- <td class="cell-prod">示例装货产品</td>
- <td class="cell-prod">吨</td>
- <td class="cell-prod">30</td>
- </tr>
- <tr>
- <td class="cell-prod"><span class="tag side-need">需</span></td>
- <td class="cell-prod">示例送货产品 A</td>
- <td class="cell-prod">吨</td>
- <td class="cell-prod">18</td>
- </tr>
- <tr>
- <td class="cell-need">
- <span class="name-with-mark">
- 安庆市山峡化工有限公司
- <span class="tag success">内部</span>
- </span>
- </td>
- <td class="cell-need">
- <div class="stack">
- <span>高新区震虹路5号安庆市山峡化工有限公司</span>
- <span class="sub">2026-10-13</span>
- </div>
- </td>
- <td class="cell-need"><span class="muted">—</span></td>
- <td class="cell-prod plan-end"><span class="tag side-need">需</span></td>
- <td class="cell-prod plan-end">示例送货产品 B</td>
- <td class="cell-prod plan-end">吨</td>
- <td class="cell-prod plan-end">12</td>
- </tr>
- </tbody>
- </table>
- </div>
- <p class="meta">
- 合并规则:基础/装货 <code>rowspan = 整单行数</code>;送货段
- <code>首段 rowspan = 供产品行数 + 本段产品行数</code>,后续段
- <code>rowspan = 本段产品行数</code>。
- </p>
- </section>
- <!-- 方案 B -->
- <section class="panel" id="panel-b">
- <p class="desc">
- <strong>方案 B:</strong>同样三区列表头。
- <strong>基础 / 装货 / 送货</strong>全部按整单合并(rowspan=3);
- 送货区在<strong>一个单元格内</strong>用虚线叠放 2 个送货段,不要求和右侧产品行一一对应。
- 产品明细仍 3 行。
- </p>
- <p class="ok">
- 实现最简单(送货列改成计划级合并 + 格内 v-for);送货客户/地址视觉上就是 2 行信息,不会出现第三行「—」。
- 代价:送货段与产品行不再纵向对齐。
- </p>
- <div class="legend">
- <span><i class="swatch base"></i>基础信息(整单合并)</span>
- <span><i class="swatch load"></i>装货段次(整单合并)</span>
- <span><i class="swatch need"></i>送货段次(整单合并,格内叠段)</span>
- <span><i class="swatch prod"></i>产品明细(不合并)</span>
- </div>
- <div class="table-wrap">
- <table class="list">
- <thead>
- <tr class="zone-row">
- <th class="zone-base" colspan="5">基础信息</th>
- <th class="zone-load" colspan="3">装货段次</th>
- <th class="zone-need" colspan="3">送货段次</th>
- <th class="zone-prod" colspan="4">产品明细(供/需)</th>
- </tr>
- <tr>
- <th class="col-base">计划编号</th>
- <th class="col-base">跟进状态</th>
- <th class="col-base">计划日期</th>
- <th class="col-base">车牌号</th>
- <th class="col-base">人员</th>
- <th class="col-load">装货客户</th>
- <th class="col-load">装货地址/时间</th>
- <th class="col-load">供合同</th>
- <th class="col-need">送货客户</th>
- <th class="col-need">送货地址/时间</th>
- <th class="col-need">需合同</th>
- <th class="col-prod">侧别</th>
- <th class="col-prod">产品名称</th>
- <th class="col-prod">单位</th>
- <th class="col-prod">计划量</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td class="cell-base" rowspan="3"><a href="#">PO20261009016</a></td>
- <td class="cell-base" rowspan="3"><span class="tag danger">待安排</span></td>
- <td class="cell-base" rowspan="3">2026-10-13</td>
- <td class="cell-base" rowspan="3">皖R4B299/皖R8131挂</td>
- <td class="cell-base" rowspan="3">彭双青(驾)、汪的霞(押)</td>
- <td class="cell-load" rowspan="3">铜陵华博精细化工有限公司</td>
- <td class="cell-load" rowspan="3">
- <div class="stack">
- <span>铜官大道南段3888号铜陵市华兴化工有限公司</span>
- <span class="sub">2026-10-13</span>
- </div>
- </td>
- <td class="cell-load" rowspan="3"><span class="muted">—</span></td>
- <td class="cell-need" rowspan="3">
- <div class="stack">
- <span>合肥瞻宇环保科技有限公司</span>
- <hr class="seg-divider" />
- <span class="name-with-mark">
- 安庆市山峡化工有限公司
- <span class="tag success">内部</span>
- </span>
- </div>
- </td>
- <td class="cell-need" rowspan="3">
- <div class="stack">
- <div class="stack">
- <span class="muted">—</span>
- <span class="sub">2026-10-13</span>
- </div>
- <hr class="seg-divider" />
- <div class="stack">
- <span>高新区震虹路5号安庆市山峡化工有限公司</span>
- <span class="sub">2026-10-13</span>
- </div>
- </div>
- </td>
- <td class="cell-need" rowspan="3">
- <div class="stack">
- <span class="muted">—</span>
- <hr class="seg-divider" />
- <span class="muted">—</span>
- </div>
- </td>
- <td class="cell-prod"><span class="tag side-load">供</span></td>
- <td class="cell-prod">示例装货产品</td>
- <td class="cell-prod">吨</td>
- <td class="cell-prod">30</td>
- </tr>
- <tr>
- <td class="cell-prod"><span class="tag side-need">需</span></td>
- <td class="cell-prod">示例送货产品 A</td>
- <td class="cell-prod">吨</td>
- <td class="cell-prod">18</td>
- </tr>
- <tr>
- <td class="cell-prod plan-end"><span class="tag side-need">需</span></td>
- <td class="cell-prod plan-end">示例送货产品 B</td>
- <td class="cell-prod plan-end">吨</td>
- <td class="cell-prod plan-end">12</td>
- </tr>
- </tbody>
- </table>
- </div>
- <p class="meta">
- 合并规则:三区段信息列均为 <code>rowspan = 整单行数</code>;多送货在格内用分隔线叠放。
- 产品明细列不合并。
- </p>
- </section>
- <!-- 对照 C:现状 -->
- <section class="panel" id="panel-c">
- <p class="desc">
- <strong>对照 · 接近现状:</strong>同样三区列,但送货区按「展平行」各自出格——
- 供产品行没有可绑定的唯一送货客户时显示 <strong>—</strong>,再跟 2 个真实送货段,
- 于是送货客户/地址看起来像 <strong>3 行</strong>(你截图里的问题)。
- </p>
- <p class="pain">
- 问题:业务上只有 2 个送货段,列表却多出一行「—」占位,扫读时像第三个送货客户。
- </p>
- <div class="table-wrap">
- <table class="list">
- <thead>
- <tr class="zone-row">
- <th class="zone-base" colspan="5">基础信息</th>
- <th class="zone-load" colspan="2">装货段次</th>
- <th class="zone-need" colspan="2">送货段次</th>
- <th class="zone-prod" colspan="3">产品明细</th>
- </tr>
- <tr>
- <th class="col-base">计划编号</th>
- <th class="col-base">跟进状态</th>
- <th class="col-base">计划日期</th>
- <th class="col-base">车牌号</th>
- <th class="col-base">人员</th>
- <th class="col-load">装货客户</th>
- <th class="col-load">装货地址/时间</th>
- <th class="col-need">送货客户</th>
- <th class="col-need">送货地址/时间</th>
- <th class="col-prod">侧别</th>
- <th class="col-prod">产品名称</th>
- <th class="col-prod">计划量</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td class="cell-base" rowspan="3"><a href="#">PO20261009016</a></td>
- <td class="cell-base" rowspan="3"><span class="tag danger">待安排</span></td>
- <td class="cell-base" rowspan="3">2026-10-13</td>
- <td class="cell-base" rowspan="3">皖R4B299/皖R8131挂</td>
- <td class="cell-base" rowspan="3">彭双青(驾)、汪的霞(押)</td>
- <td class="cell-load" rowspan="3">铜陵华博精细化工有限公司</td>
- <td class="cell-load" rowspan="3">
- <div class="stack">
- <span>铜官大道南段3888号…</span>
- <span class="sub">2026-10-13</span>
- </div>
- </td>
- <td class="cell-need"><span class="muted">—</span></td>
- <td class="cell-need">
- <div class="stack">
- <span class="muted">—</span>
- <span class="sub muted">—</span>
- </div>
- </td>
- <td class="cell-prod"><span class="tag side-load">供</span></td>
- <td class="cell-prod">示例装货产品</td>
- <td class="cell-prod">30</td>
- </tr>
- <tr>
- <td class="cell-need">合肥瞻宇环保科技有限公司</td>
- <td class="cell-need">
- <div class="stack">
- <span class="muted">—</span>
- <span class="sub">2026-10-13</span>
- </div>
- </td>
- <td class="cell-prod"><span class="tag side-need">需</span></td>
- <td class="cell-prod">示例送货产品 A</td>
- <td class="cell-prod">18</td>
- </tr>
- <tr>
- <td class="cell-need plan-end">
- <span class="name-with-mark">
- 安庆市山峡化工有限公司
- <span class="tag success">内部</span>
- </span>
- </td>
- <td class="cell-need plan-end">
- <div class="stack">
- <span>高新区震虹路5号…</span>
- <span class="sub">2026-10-13</span>
- </div>
- </td>
- <td class="cell-prod plan-end"><span class="tag side-need">需</span></td>
- <td class="cell-prod plan-end">示例送货产品 B</td>
- <td class="cell-prod plan-end">12</td>
- </tr>
- </tbody>
- </table>
- </div>
- <p class="meta">对照用:说明「三区列」本身可行,但若送货列仍跟供/需产品行一一出格,多送货时就会冒出「—」。</p>
- </section>
- </div>
- <script>
- const tabs = document.querySelectorAll('.tab')
- const panels = {
- a: document.getElementById('panel-a'),
- b: document.getElementById('panel-b'),
- c: document.getElementById('panel-c')
- }
- tabs.forEach((tab) => {
- tab.addEventListener('click', () => {
- const key = tab.getAttribute('data-tab')
- tabs.forEach((t) => t.classList.toggle('active', t === tab))
- Object.entries(panels).forEach(([k, el]) => {
- el.classList.toggle('active', k === key)
- })
- })
- })
- </script>
- </body>
- </html>
|