baseline: 薪酬逻辑收口到 shared/payroll.js 后的当前全量状态

这是第一个包含完整工作区的提交,也是后续「拆 SFC / 上 Vite」的回滚基线。

此前的提交均为 index.html 单文件历史快照,由 .bak 文件重建。

当前状态(提交前已实测):
- index.html 内联薪酬算法已删除,改调 WHTPayroll
- shared/payroll.js 为唯一薪酬实现,浏览器与 Node 共用
- 对外接口未变:aggregateMonth / isCutEdge / payDayKind 等保留同名薄包装

未入库内容见 .gitignore:依赖、Chrome 验证 profile、验证截图、
运行时 sqlite 数据与日志、时间戳备份、.trash。
This commit is contained in:
OpenClaw Agent
2026-09-05 14:35:00 +08:00
parent 7d48c4ac65
commit 2329955e32
94 changed files with 12770 additions and 237 deletions
+165
View File
@@ -0,0 +1,165 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1080" height="1520" viewBox="0 0 1080 1520" font-family="'PingFang SC','Microsoft YaHei',sans-serif">
<defs>
<linearGradient id="hd" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#1E293B"/>
<stop offset="0.56" stop-color="#312E81"/>
<stop offset="1" stop-color="#4F46E5"/>
</linearGradient>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="8" stdDeviation="18" flood-color="#312E81" flood-opacity="0.30"/>
</filter>
</defs>
<!-- 背景 -->
<rect width="1080" height="1520" fill="#F1F5F9"/>
<!-- 标题 -->
<text x="60" y="80" font-size="42" font-weight="800" fill="#0F172A">设置 · 底部抽屉面板(Bottom Drawer)设计</text>
<text x="60" y="122" font-size="24" fill="#64748B">齿轮触发 → 底部滑出 → 五个设置分区;遮罩点击/下滑关闭。替代"齿轮直达设置页"。</text>
<line x1="60" y1="146" x2="1020" y2="146" stroke="#CBD5E1" stroke-width="2"/>
<!-- ============ 左:滑出前的页面(日历页参考) ============ -->
<g transform="translate(60,220)">
<rect width="440" height="900" rx="30" fill="#FFFFFF" stroke="#E2E8F0" stroke-width="2"/>
<!-- 顶部渐变看板 -->
<rect x="8" y="8" width="424" height="150" rx="24" fill="url(#hd)"/>
<text x="40" y="60" font-size="22" fill="#C7D2FE">2026年9月</text>
<text x="40" y="105" font-size="34" font-weight="800" fill="#fff">¥ 6,180.0</text>
<text x="40" y="132" font-size="16" fill="#C7D2FE">10日 ¥2,940.0 · 22日 ¥3,240.0</text>
<!-- 齿轮按钮 -->
<circle cx="392" cy="48" r="18" fill="rgba(255,255,255,.16)"/>
<text x="376" y="57" font-size="24" fill="#fff">⚙</text>
<text x="300" y="92" font-size="13" text-anchor="middle" fill="#A5B4FC" opacity="0.0">.</text>
<!-- 胶囊标签行 -->
<g font-size="15">
<rect x="40" y="138" width="86" height="28" rx="14" fill="rgba(255,255,255,.14)" stroke="rgba(255,255,255,.16)"/>
<text x="56" y="158" fill="#E2E8F0">出勤 16</text>
<rect x="134" y="138" width="86" height="28" rx="14" fill="rgba(255,255,255,.14)" stroke="rgba(255,255,255,.16)"/>
<text x="150" y="158" fill="#E2E8F0">工时 124h</text>
<rect x="228" y="138" width="104" height="28" rx="14" fill="rgba(255,255,255,.14)" stroke="rgba(255,255,255,.16)"/>
<text x="244" y="158" fill="#FDE68A">收入 ¥5,000</text>
</g>
<!-- 周日头 -->
<g transform="translate(36,200)" font-size="15" fill="#94A3B8">
<text x="0">日</text><text x="47">一</text><text x="94">二</text><text x="141">三</text>
<text x="188">四</text><text x="235">五</text><text x="282">六</text>
</g>
<!-- 一横行日历格(示意 4 格) -->
<g transform="translate(36,232)">
<!-- 格1 空 -->
<rect width="56" height="62" rx="10" fill="#fff" stroke="#E2E8F0"/>
<text x="8" y="18" font-size="16" fill="#1F2937">1</text>
<text x="24" y="52" font-size="12" fill="#CBD5E1">—</text>
<!-- 格2 白班 -->
<rect x="70" width="56" height="62" rx="10" fill="#FFF7ED" stroke="#FED7AA"/>
<text x="78" y="18" font-size="16" fill="#1F2937">2</text>
<rect x="80" y="2" width="6" height="6" rx="3" fill="#10B981"/>
<!-- 白班胶囊 -->
<rect x="76" y="34" width="46" height="20" rx="10" fill="#FFEDD5"/>
<text x="82" y="48" font-size="13" font-weight="700" fill="#EA580C">白 8h</text>
<!-- 格3 夜班 -->
<rect x="140" width="56" height="62" rx="10" fill="#EEF2FF" stroke="#C7D2FE"/>
<text x="148" y="18" font-size="16" fill="#1F2937">3</text>
<rect x="150" y="2" width="6" height="6" rx="3" fill="#F43F5E"/>
<!-- 夜班胶囊 -->
<rect x="146" y="34" width="46" height="20" rx="10" fill="#E0E7FF"/>
<text x="152" y="48" font-size="13" font-weight="700" fill="#4F46E5">夜 10h</text>
<!-- 格4 休 -->
<rect x="210" width="56" height="62" rx="10" fill="#F1F5F9" stroke="#E2E8F0"/>
<text x="218" y="18" font-size="16" fill="#1F2937">4</text>
<text x="234" y="48" font-size="13" fill="#9CA3AF">休</text>
</g>
<text x="36" y="352" font-size="16" fill="#94A3B8">▲ 滑出前:顶部看板 + 齿轮 + 胶囊日历格</text>
<!-- 底部 Tab -->
<g transform="translate(0,810)">
<rect width="440" height="66" rx="0" fill="#fff" stroke="#E2E8F0"/>
<g text-anchor="middle" font-size="15" fill="#94A3B8">
<text x="80" y="30" font-size="24">📅</text><text x="80" y="50">打卡</text>
<text x="220" y="30" font-size="24">📊</text><text x="220" y="50">汇总</text>
<text x="360" y="30" font-size="24" fill="#4F46E5">⚙</text><text x="360" y="50" fill="#4F46E5">设置</text>
</g>
<rect x="332" y="0" width="56" height="3" fill="#4F46E5"/>
</g>
<text x="36" y="360" font-size="16" fill="#64748B">底部 Tab 保留设置项(抽屉打开在 Tab 之上)</text>
</g>
<!-- 分隔箭头 -->
<text x="545" y="580" font-size="60" fill="#94A3B8">→</text>
<!-- ============ 右:抽屉展开状态 ============ -->
<g transform="translate(590,190)">
<!-- 遮罩 -->
<rect width="430" height="940" rx="30" fill="#0F172A" opacity="0.35"/>
<!-- 页面底色上露出部分看板顶部 -->
<rect x="6" y="6" width="418" height="90" rx="20" fill="url(#hd)" opacity="0.9"/>
<text x="28" y="50" font-size="18" fill="#C7D2FE">2026年9月 · 日历页(被遮罩压暗)</text>
<!-- 抽屉主体:底部滑出 -->
<g transform="translate(0,270)" filter="url(#shadow)">
<rect width="430" height="670" rx="26" fill="#FFFFFF"/>
<!-- 拖拽把手 -->
<rect x="185" y="12" width="60" height="5" rx="2.5" fill="#CBD5E1"/>
<!-- 抽屉标题 -->
<text x="30" y="52" font-size="22" font-weight="800" fill="#0F172A">设置</text>
<text x="334" y="50" font-size="18" fill="#94A3B8">✕ 关闭</text>
<line x1="30" y1="68" x2="400" y2="68" stroke="#F1F5F9" stroke-width="2"/>
<!-- 分区① 薪酬规则 -->
<text x="30" y="104" font-size="15" font-weight="700" fill="#4F46E5">👛 薪酬规则</text>
<rect x="30" y="116" width="370" height="96" rx="12" fill="#F8FAFC" stroke="#EEF2F7"/>
<text x="46" y="144" font-size="14" fill="#475569">基础时薪</text>
<rect x="270" y="128" width="116" height="40" rx="8" fill="#fff" stroke="#E2E8F0"/>
<text x="292" y="155" font-size="15" text-anchor="middle" fill="#0F172A">19.5 元/h</text>
<text x="46" y="184" font-size="14" fill="#475569">满勤天数</text>
<rect x="270" y="168" width="116" height="34" rx="8" fill="#fff" stroke="#E2E8F0"/>
<text x="318" y="191" font-size="15" text-anchor="middle" fill="#0F172A">27 天</text>
<!-- 分区② 奖惩标准 -->
<text x="30" y="244" font-size="15" font-weight="700" fill="#4F46E5">🎖 奖惩标准</text>
<rect x="30" y="256" width="370" height="96" rx="12" fill="#F8FAFC" stroke="#EEF2F7"/>
<text x="46" y="284" font-size="14" fill="#475569">查获奖励 / 件</text>
<rect x="290" y="268" width="96" height="30" rx="8" fill="#ECFDF5"/>
<text x="308" y="289" text-anchor="middle" font-size="14" font-weight="700" fill="#059669">+¥10</text>
<text x="46" y="324" font-size="14" fill="#475569">漏查处罚 / 件</text>
<rect x="290" y="308" width="96" height="30" rx="8" fill="#FFF1F2"/>
<text x="308" y="329" text-anchor="middle" font-size="14" font-weight="700" fill="#E11D48">-¥20</text>
<!-- 分区③ 发放周期 -->
<text x="30" y="386" font-size="15" font-weight="700" fill="#4F46E5">📆 发放周期</text>
<rect x="30" y="398" width="370" height="86" rx="12" fill="#F8FAFC" stroke="#EEF2F7"/>
<text x="46" y="426" font-size="14" fill="#475569">当月发 上半月 → 次月 B 日</text>
<text x="46" y="452" font-size="14" fill="#475569">上半月工资日期 (payDayA)</text>
<rect x="290" y="410" width="96" height="34" rx="8" fill="#fff" stroke="#E2E8F0"/>
<text x="312" y="433" text-anchor="middle" font-size="14" fill="#0F172A">9月22日</text>
<!-- 分区④ 班次默认工时 -->
<text x="30" y="518" font-size="15" font-weight="700" fill="#4F46E5">🕐 班次默认工时</text>
<rect x="30" y="530" width="370" height="86" rx="12" fill="#F8FAFC" stroke="#EEF2F7"/>
<rect x="46" y="544" width="70" height="30" rx="15" fill="#FFEDD5"/>
<text x="58" y="565" font-size="13" font-weight="700" fill="#EA580C">白班 8h</text>
<rect x="126" y="544" width="70" height="30" rx="15" fill="#E0E7FF"/>
<text x="138" y="565" font-size="13" font-weight="700" fill="#4F46E5">夜班 10h</text>
<text x="46" y="600" font-size="12" fill="#94A3B8">夜班跨天,工时全归开始打卡那天</text>
<!-- 分区⑤ 数据 -->
<text x="30" y="650" font-size="15" font-weight="700" fill="#4F46E5">💾 数据</text>
<rect x="30" y="660" width="370" height="88" rx="12" fill="#F8FAFC" stroke="#EEF2F7"/>
<text x="46" y="688" font-size="14" fill="#475569">导出备份(JSON)</text>
<text x="330" y="688" font-size="14" fill="#A0AEC0">↗</text>
<line x1="46" y1="704" x2="384" y2="704" stroke="#EEF2F7"/>
<text x="46" y="726" font-size="14" fill="#475569">恢复默认设置</text>
<text x="330" y="726" font-size="14" fill="#A0AEC0">↗</text>
<line x1="46" y1="718" x2="384" y2="718" stroke="#EEF2F7"/>
<text x="30" y="766" font-size="12" fill="#94A3B8">滑出方式:下滑把手 / 点击遮罩 / 点 ✕ 关闭 · Tab 结构不变,不影响用例20</text>
</g>
</g>
<!-- 底部说明 -->
<rect x="60" y="1350" width="960" height="110" rx="16" fill="#EEF2FF" stroke="#C7D2FE"/>
<text x="90" y="1390" font-size="24" font-weight="700" fill="#312E81">关键决策点</text>
<text x="90" y="1426" font-size="20" fill="#4338CA">抽屉内容 = 现有"设置 Tab"整块搬进底部面板,齿轮/遮罩/下滑三种方式开关,底部 Tab 保留"设置"页签</text>
<text x="90" y="1456" font-size="18" fill="#6366F1">改动范围:新增 settingsOpen 状态 + 抽屉容器;不动 tabs 数组 → 用例20 不受影响</text>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

+211
View File
@@ -0,0 +1,211 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>设置 · 底部抽屉面板设计</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif; }
body { background: #F1F5F9; padding: 24px; color: #0F172A; }
h1 { font-size: 24px; font-weight: 800; margin-bottom: 4px; }
.sub { font-size: 14px; color: #64748B; margin-bottom: 20px; }
.wrap { display: flex; gap: 32px; flex-wrap: wrap; align-items: flex-start; }
/* ===== 手机外框 ===== */
.phone {
width: 380px; border-radius: 30px; background: #fff;
box-shadow: 0 20px 50px rgba(49,46,129,.25);
overflow: hidden; border: 1px solid #E2E8F0; position: relative;
}
.phone-title { padding: 12px 20px; font-size: 13px; font-weight: 700; color: #64748B; background:#F8FAFC; border-bottom:1px solid #EEF2F7; }
/* ===== 看板 ===== */
.board {
background: linear-gradient(135deg,#1E293B 0%,#312E81 56%,#4F46E5 100%);
color:#fff; padding: 18px 20px 16px; position: relative;
}
.board .row1 { display:flex; justify-content:space-between; align-items:center; }
.board .month { font-size:16px; font-weight:700; letter-spacing:.5px; }
.gear { width:32px; height:32px; border-radius:50%; background:rgba(255,255,255,.16); display:flex; align-items:center; justify-content:center; font-size:16px; cursor:pointer; }
.board .money { font-size:34px; font-weight:800; margin-top:6px; font-variant-numeric:tabular-nums; }
.board .money small { font-size:15px; opacity:.75; }
.board .payout { font-size:12px; color:#C7D2FE; margin-top:4px; }
.pills { display:flex; gap:6px; margin-top:14px; }
.pill { font-size:11px; padding:4px 10px; border-radius:999px; background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.16); }
/* ===== 日历 ===== */
.cal { padding: 12px 14px 16px; }
.cal .week { display:grid; grid-template-columns:repeat(7,1fr); text-align:center; font-size:12px; color:#94A3B8; margin-bottom:6px; }
.cal .week .sun{color:#F87171;}
.cal .week .sat{color:#818CF8;}
.cal .grid { display:grid; grid-template-columns:repeat(7,1fr); gap:4px; }
.cell {
height:58px; border-radius:10px; padding:3px; border:1px solid #EEF2F7;
display:flex; flex-direction:column; justify-content:space-between; position:relative;
}
.cell .top { display:flex; justify-content:space-between; align-items:center; padding:0 3px; }
.cell .day { font-size:13px; font-weight:500; font-variant-numeric:tabular-nums; }
.cell .dot { width:5px; height:5px; border-radius:50%; }
.dot.green{background:#10B981;} .dot.rose{background:#F43F5E;}
.cell .bottom { display:flex; justify-content:center; }
.pill-badge { display:inline-flex; align-items:center; gap:1.5px; padding:1px 4px; border-radius:999px; font-size:10px; font-weight:600; white-space:nowrap; }
.pill-badge.day{background:#FFF7ED;color:#EA580C;}
.pill-badge.night{background:#EEF2FF;color:#4F46E5;}
.pill-badge .t{font-weight:700;}
.st { font-size:11px; }
.st.rest{color:#9CA3AF;} .st.leave{color:#0EA5E9;} .st.empty{color:#D1D5DB;}
.cell-day{background:#FFF7ED;border-color:#FED7AA;}
.cell-night{background:#EEF2FF;border-color:#C7D2FE;}
.cell-rest{background:#F1F5F9;}
.cut { border-bottom:2px dashed #94A3B8; }
/* ===== 底部Tab ===== */
.tabbar { border-top:1px solid #E2E8F0; display:flex; }
.tab { flex:1; padding:8px 0 10px; text-align:center; font-size:10px; color:#94A3B8; position:relative; }
.tab .ic { font-size:19px; display:block; }
.tab.on { color:#4F46E5; }
.tab.on::before { content:''; position:absolute; top:0; left:50%; transform:translateX(-50%); width:34px; height:3px; border-radius:0 0 6px 6px; background:#4F46E5; }
/* ===== 抽屉 ===== */
.drawer-wrap { position:relative; }
.mask { position:absolute; inset:0; border-radius:30px; background:rgba(15,23,42,.45); z-index:2; }
.mask .board { border-radius:30px 30px 0 0; height:96px; opacity:.92; }
.drawer {
position:relative; z-index:3; background:#fff; border-radius:26px 26px 0 0;
padding: 10px 20px 20px; box-shadow:0 -12px 40px rgba(15,23,42,.35);
margin-top:-1px;
}
.handle { width:54px; height:5px; border-radius:3px; background:#CBD5E1; margin:4px auto 12px; }
.d-title { display:flex; justify-content:space-between; align-items:center; font-size:18px; font-weight:800; margin-bottom:12px; }
.d-title .x { color:#94A3B8; font-size:14px; cursor:pointer; }
.group-title { font-size:13px; font-weight:700; color:#4F46E5; margin:14px 0 6px; }
.card { background:#F8FAFC; border:1px solid #EEF2F7; border-radius:12px; padding:10px 12px; font-size:13px; }
.row { display:flex; justify-content:space-between; align-items:center; margin:6px 0; }
.row .l { color:#475569; }
.input { font-size:13px; font-variant-numeric:tabular-nums; color:#0F172A; font-weight:600; background:#fff; border:1px solid #E2E8F0; border-radius:8px; padding:3px 8px; }
.badge-pos { background:#ECFDF5; color:#059669; font-weight:700; padding:2px 8px; border-radius:999px; font-size:12px; }
.badge-neg { background:#FFF1F2; color:#E11D48; font-weight:700; padding:2px 8px; border-radius:999px; font-size:12px; }
.mini-pill { padding:3px 10px; border-radius:999px; font-size:12px; font-weight:700; }
.mini-pill.day{background:#FFEDD5;color:#EA580C;}
.mini-pill.night{background:#E0E7FF;color:#4F46E5;}
.hint { font-size:11px; color:#94A3B8; margin-top:4px; }
.data-item { color:#475569; padding:7px 0; border-bottom:1px solid #EEF2F7; display:flex; justify-content:space-between; }
.data-item:last-child{border-bottom:none;}
.note { font-size:11px; color:#94A3B8; margin-top:12px; line-height:1.5; }
/* ===== 说明卡片 ===== */
.aside { max-width:420px; background:#EEF2FF; border:1px solid #C7D2FE; border-radius:16px; padding:20px 22px; }
.aside h2 { font-size:17px; font-weight:800; color:#312E81; margin-bottom:10px; }
.aside ul { margin-left:18px; color:#4338CA; font-size:14px; line-height:1.7; }
.decision { margin-top:14px; background:#fff; border-radius:10px; padding:12px 14px; color:#1E293B; font-size:13px; line-height:1.6; }
.decision b{color:#4F46E5;}
</style>
</head>
<body>
<h1>设置 · 底部抽屉面板(Bottom Drawer)设计</h1>
<div class="sub">齿轮触发 → 底部滑出 → 五个设置分区;遮罩点击 / 下滑把手 / ✕ 关闭</div>
<div class="wrap">
<!-- 左:滑出前 -->
<div class="phone">
<div class="phone-title">① 滑出前 · 日历页(齿轮在右上角)</div>
<div class="board">
<div class="row1"><span class="month">2026年9月</span><span class="gear">⚙</span></div>
<div class="money"><small>¥</small>6,180.0</div>
<div class="payout">10日 ¥2,940.0 · 22日 ¥3,240.0</div>
<div class="pills">
<span class="pill">出勤 16/27</span>
<span class="pill">工时 124h</span>
<span class="pill">收入 ¥5,000</span>
</div>
</div>
<div class="cal">
<div class="week"><span class="sun">日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span class="sat">六</span></div>
<div class="grid">
<div class="cell"><div class="top"><span class="day">1</span></div><div class="bottom"><span class="st empty">—</span></div></div>
<div class="cell cell-day"><div class="top"><span class="day">2</span><span class="dot green"></span></div><div class="bottom"><span class="pill-badge day"><span class="t">白</span> 8h</span></div></div>
<div class="cell cell-night"><div class="top"><span class="day">3</span><span class="dot rose"></span></div><div class="bottom"><span class="pill-badge night"><span class="t">夜</span> 10h</span></div></div>
<div class="cell cell-rest"><div class="top"><span class="day">4</span></div><div class="bottom"><span class="st rest">休</span></div></div>
<div class="cell"><div class="top"><span class="day">5</span></div><div class="bottom"><span class="st empty">—</span></div></div>
<div class="cell"><div class="top"><span class="day">6</span></div><div class="bottom"><span class="st empty">—</span></div></div>
<div class="cell"><div class="top"><span class="day">7</span></div><div class="bottom"><span class="st empty">—</span></div></div>
<!-- 半月分界行 -->
<div class="cell cut"><div class="top"><span class="day">8</span></div><div class="bottom"><span class="st empty">—</span></div></div>
<div class="cell cut cell-day"><div class="top"><span class="day">9</span></div><div class="bottom"><span class="pill-badge day"><span class="t">白</span> 7.5h</span></div></div>
<div class="cell cut cell-night"><div class="top"><span class="day">10</span></div><div class="bottom"><span class="pill-badge night"><span class="t">夜</span> 6.5h</span></div></div>
</div>
</div>
<div class="tabbar">
<div class="tab"><span class="ic">📅</span>打卡</div>
<div class="tab"><span class="ic">📊</span>汇总</div>
<div class="tab on"><span class="ic">⚙</span>设置</div>
</div>
</div>
<!-- 右:抽屉展开 -->
<div style="display:flex;flex-direction:column;gap:20px;">
<div class="phone" style="height:auto;">
<div class="phone-title">② 抽屉展开 · 遮罩压暗页面 + 底部滑出设置面板</div>
<div class="drawer-wrap">
<div class="mask"><div class="board"><div class="month" style="font-size:13px;opacity:.9;">2026年9月 · 日历页(被遮罩压暗)</div></div></div>
<div class="drawer">
<div class="handle"></div>
<div class="d-title">设置 <span class="x">✕ 关闭</span></div>
<div class="group-title">👛 薪酬规则</div>
<div class="card">
<div class="row"><span class="l">基础时薪</span><span class="input">19.5 元/h</span></div>
<div class="row"><span class="l">满勤天数</span><span class="input">27 天</span></div>
<div class="row"><span class="l">满勤奖金/h</span><span class="input">1 元</span></div>
</div>
<div class="group-title">🎖 奖惩标准</div>
<div class="card">
<div class="row"><span class="l">查获奖励 / 件</span><span class="badge-pos">+¥10</span></div>
<div class="row"><span class="l">漏查处罚 / 件</span><span class="badge-neg">-¥20</span></div>
<div class="row"><span class="l">满勤达标奖励</span><span class="badge-pos">按工时</span></div>
</div>
<div class="group-title">📆 发放周期</div>
<div class="card">
<div class="row"><span class="l">上半月工资日 (payDayA)</span><span class="input">22 号</span></div>
<div class="row"><span class="l">下半月工资日 (payDayB)</span><span class="input">10 号</span></div>
<div class="row"><span class="l">半月分界日 (cutoff)</span><span class="input">15 号</span></div>
</div>
<div class="group-title">🕐 班次默认工时</div>
<div class="card">
<div class="row"><span class="l">白班 / 夜班默认</span>
<span style="display:flex;gap:6px;"><span class="mini-pill day">白 8h</span><span class="mini-pill night">夜 10h</span></span>
</div>
<div class="hint">夜班跨天,工时全归开始打卡那天</div>
</div>
<div class="group-title">💾 数据</div>
<div class="card" style="padding:4px 12px;">
<div class="data-item"><span>导出备份(JSON)</span><span style="color:#A0AEC0;">↗</span></div>
<div class="data-item"><span>复制数据到剪贴板</span><span style="color:#A0AEC0;">↗</span></div>
<div class="data-item"><span>恢复默认设置</span><span style="color:#A0AEC0;">↗</span></div>
</div>
<div class="note">滑出方式:下滑把手 / 点击遮罩 / 点 ✕ 关闭 · 不动 tabs 数组 → 用例20 不受影响</div>
</div>
</div>
</div>
<div class="aside">
<h2>关键决策点</h2>
<ul>
<li>抽屉内容 = 现有「设置 Tab」整块搬进底部面板</li>
<li>三种关闭方式:下滑把手 / 点遮罩 / 点 ✕</li>
<li>齿轮按钮(看板右上)+ 底部 Tab「设置」都触发抽屉</li>
<li><b>不动 tabs 数组</b> → 用例20 不受影响,规避重写测试</li>
</ul>
<div class="decision">
要落地的话改动范围:新增 <b>settingsOpen</b> 状态 + 抽屉容器模板(复用现有设置表单),从中置「齿轮直达设置页」改为「齿轮/遮罩/下滑开关抽屉」。改动集中、可逆。
</div>
</div>
</div>
</div>
</body>
</html>