427 lines
17 KiB
HTML
427 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||
<title>草稿箱 · 标题栏管理 + 列表是否显示按钮</title>
|
||
<style>
|
||
:root {
|
||
--brand: #0a9f6d;
|
||
--brand-dark: #087f57;
|
||
--brand-soft: #e9f9f2;
|
||
--warn: #d97706;
|
||
--warn-soft: #fff7e8;
|
||
--danger: #ef4444;
|
||
--nav-bg: #ecfdf5;
|
||
--page-bg: #f5f8f7;
|
||
--text: #1f2a26;
|
||
--text-muted: #6b7b74;
|
||
}
|
||
* { box-sizing: border-box; }
|
||
body {
|
||
margin: 0;
|
||
font-family: "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", -apple-system, system-ui, sans-serif;
|
||
color: var(--text);
|
||
background:
|
||
radial-gradient(900px 420px at 8% -8%, rgba(10, 159, 109, 0.12), transparent 55%),
|
||
linear-gradient(180deg, #f8fffc 0%, #f4f7fb 50%, #f7f8fa 100%);
|
||
line-height: 1.45;
|
||
}
|
||
.stage { max-width: 1200px; margin: 0 auto; padding: 28px 16px 56px; }
|
||
.hero h1 { margin: 0 0 8px; font-size: 22px; font-weight: 720; }
|
||
.hero p { margin: 0; color: #64748b; font-size: 14px; max-width: 780px; }
|
||
.hero .note {
|
||
margin-top: 12px; display: inline-block; padding: 8px 12px;
|
||
border-radius: 10px; background: #fff; border: 1px solid #e2e8f0;
|
||
font-size: 12px; color: #64748b;
|
||
}
|
||
.hero .note strong { color: #0f766e; }
|
||
|
||
.rec {
|
||
margin: 16px 0 0;
|
||
padding: 14px 16px;
|
||
border-radius: 14px;
|
||
background: var(--brand-soft);
|
||
border: 1px solid #b7ebd4;
|
||
font-size: 13px;
|
||
color: #166534;
|
||
line-height: 1.55;
|
||
}
|
||
.rec b { color: var(--brand-dark); }
|
||
|
||
.tabs { display: flex; flex-wrap: wrap; gap: 10px; margin: 20px 0 16px; }
|
||
.tab {
|
||
appearance: none; border: 1px solid #e2e8f0; background: #fff;
|
||
border-radius: 999px; padding: 10px 16px; font-size: 13px;
|
||
font-weight: 600; color: #475569; cursor: pointer;
|
||
}
|
||
.tab.is-active {
|
||
color: var(--brand-dark); border-color: var(--brand);
|
||
background: var(--brand-soft);
|
||
box-shadow: 0 0 0 3px rgba(10, 159, 109, 0.16);
|
||
}
|
||
.tab .badge {
|
||
margin-left: 6px; font-size: 10px; padding: 2px 6px;
|
||
border-radius: 999px; background: #ecfdf5; color: #047857; font-weight: 700;
|
||
}
|
||
|
||
.layout {
|
||
display: grid;
|
||
grid-template-columns: minmax(240px, 300px) 1fr;
|
||
gap: 20px; align-items: start;
|
||
}
|
||
@media (max-width: 900px) { .layout { grid-template-columns: 1fr; } }
|
||
|
||
.panel {
|
||
background: rgba(255,255,255,.94);
|
||
border: 1px solid #e2e8f0; border-radius: 16px; padding: 16px;
|
||
box-shadow: 0 10px 28px rgba(15,23,42,.05);
|
||
}
|
||
.panel h2 { margin: 0 0 4px; font-size: 15px; }
|
||
.panel .sub { margin: 0 0 10px; font-size: 12px; color: #64748b; }
|
||
.panel ul { margin: 0; padding-left: 18px; font-size: 13px; color: #475569; }
|
||
.panel li { margin: 5px 0; }
|
||
.panel .pick {
|
||
margin-top: 12px; padding: 10px 12px; border-radius: 10px;
|
||
background: #fff7e8; border: 1px solid #fde68a;
|
||
font-size: 12px; color: #92400e;
|
||
}
|
||
|
||
.phones { display: flex; flex-wrap: wrap; gap: 18px; justify-content: center; }
|
||
.phone {
|
||
width: 375px; background: #fff; border-radius: 28px; overflow: hidden;
|
||
box-shadow: 0 0 0 1px rgb(15 23 42 / 6%), 0 18px 40px rgb(15 23 42 / 12%);
|
||
}
|
||
.cap {
|
||
text-align: center; font-size: 11px; font-weight: 650; color: #64748b;
|
||
padding: 8px; background: #f8fafc; border-bottom: 1px solid #eef2f0;
|
||
}
|
||
|
||
/* 模拟系统标题栏(对齐 pages.json #ecfdf5) */
|
||
.nav {
|
||
height: 44px; display: flex; align-items: center; padding: 0 8px 0 4px;
|
||
background: var(--nav-bg); border-bottom: 1px solid #d8f3e5;
|
||
position: relative;
|
||
}
|
||
.nav-back {
|
||
width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
|
||
color: #0f291e; flex-shrink: 0;
|
||
}
|
||
.nav-back::before {
|
||
content: ""; width: 10px; height: 10px;
|
||
border-left: 2px solid #0f291e; border-bottom: 2px solid #0f291e;
|
||
transform: rotate(45deg); margin-left: 4px;
|
||
}
|
||
.nav-title {
|
||
position: absolute; left: 50%; transform: translateX(-50%);
|
||
font-size: 16px; font-weight: 650; color: #0f291e;
|
||
}
|
||
.nav-right {
|
||
margin-left: auto; padding: 0 10px; height: 36px;
|
||
display: inline-flex; align-items: center;
|
||
font-size: 14px; font-weight: 650; color: var(--brand-dark);
|
||
cursor: pointer; user-select: none;
|
||
}
|
||
.nav-right.is-done { color: #64748b; }
|
||
|
||
.page { background: var(--page-bg); min-height: 560px; padding-bottom: 16px; }
|
||
.search-wrap { padding: 10px 12px; background: #fff; border-bottom: 1px solid #f1f5f9; }
|
||
.search {
|
||
height: 36px; display: flex; align-items: center; gap: 8px;
|
||
padding: 0 12px; border-radius: 10px; border: 1px solid #e8eaed;
|
||
background: #fafafa; font-size: 13px; color: #94a3b8;
|
||
}
|
||
.search::before {
|
||
content: ""; width: 12px; height: 12px; border: 1.5px solid #94a3b8;
|
||
border-radius: 50%; flex-shrink: 0;
|
||
}
|
||
|
||
.list { padding: 10px 12px 0; display: flex; flex-direction: column; gap: 10px; }
|
||
.end { text-align: center; padding: 12px 0; font-size: 12px; color: #94a3b8; }
|
||
|
||
.card {
|
||
width: 100%; background: #fff; border-radius: 14px;
|
||
box-shadow: 0 8px 22px rgba(15, 23, 42, 0.05);
|
||
overflow: hidden; border: 1px solid transparent;
|
||
}
|
||
.card-body { padding: 14px; }
|
||
.card-top { display: flex; align-items: flex-start; gap: 10px; }
|
||
.card-title { flex: 1; min-width: 0; font-size: 15px; font-weight: 700; line-height: 1.35; }
|
||
.card-status {
|
||
flex-shrink: 0; font-size: 11px; font-weight: 700;
|
||
padding: 3px 9px; border-radius: 999px;
|
||
background: var(--warn-soft); color: var(--warn);
|
||
}
|
||
.meta {
|
||
margin-top: 8px; font-size: 12px; color: #64748b;
|
||
}
|
||
.meta .dot { margin: 0 6px; color: #cbd5e1; }
|
||
.hint-tap {
|
||
margin-top: 8px; font-size: 11px; color: #94a3b8;
|
||
}
|
||
|
||
.card-footer {
|
||
display: flex; gap: 8px; padding: 10px 12px 12px;
|
||
border-top: 1px dashed rgba(140, 170, 155, 0.28);
|
||
}
|
||
.card-footer button {
|
||
flex: 1; height: 34px; border-radius: 10px; border: 1px solid #d8e3de;
|
||
background: #fff; font-size: 12px; font-weight: 650; color: #334155;
|
||
}
|
||
.card-footer .p { background: var(--brand); border-color: var(--brand); color: #fff; }
|
||
.card-footer .d {
|
||
color: var(--danger); border-color: rgba(239,68,68,.35);
|
||
background: rgba(239,68,68,.06);
|
||
}
|
||
|
||
.row { display: flex; align-items: center; gap: 10px; }
|
||
.row .card { flex: 1; min-width: 0; }
|
||
.check {
|
||
width: 20px; height: 20px; border-radius: 50%; border: 1.5px solid #cbd5e1;
|
||
background: #fff; display: flex; align-items: center; justify-content: center;
|
||
font-size: 11px; color: #fff; font-weight: 700; flex-shrink: 0;
|
||
}
|
||
.check.on { background: #22c55e; border-color: #22c55e; }
|
||
.row.is-on .card {
|
||
border-color: rgba(34, 197, 94, 0.45);
|
||
box-shadow: 0 8px 20px rgba(22, 163, 74, 0.12);
|
||
}
|
||
.batch {
|
||
margin: 10px 12px 0; padding: 10px 12px; border-radius: 12px;
|
||
background: #fff; border: 1px solid #c6f0dc;
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
font-size: 13px; color: #166534;
|
||
}
|
||
.batch button {
|
||
height: 30px; padding: 0 12px; border-radius: 8px;
|
||
border: 1px solid rgba(239,68,68,.35);
|
||
background: rgba(239,68,68,.06); color: var(--danger);
|
||
font-size: 12px; font-weight: 650;
|
||
}
|
||
|
||
/* 详情底栏示意 */
|
||
.detail {
|
||
display: flex; flex-direction: column; min-height: 560px;
|
||
background: var(--page-bg);
|
||
}
|
||
.detail-body { flex: 1; padding: 12px; }
|
||
.detail-sheet {
|
||
background: #fff; border-radius: 14px; padding: 16px;
|
||
box-shadow: 0 8px 22px rgba(15,23,42,.05);
|
||
}
|
||
.detail-sheet h3 { margin: 0 0 12px; font-size: 17px; }
|
||
.detail-sheet .line {
|
||
display: flex; gap: 10px; font-size: 13px; margin: 8px 0; color: #475569;
|
||
}
|
||
.detail-sheet .line span:first-child { color: #94a3b8; min-width: 64px; }
|
||
.detail-foot {
|
||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
|
||
background: rgba(255,255,255,.96);
|
||
border-top: 1px solid #e8eeeb;
|
||
display: flex; gap: 8px;
|
||
}
|
||
.detail-foot button {
|
||
height: 44px; border-radius: 12px; border: 0;
|
||
font-size: 15px; font-weight: 700; cursor: pointer;
|
||
}
|
||
.detail-foot .ghost { flex: 0 0 72px; background: #f1f5f9; color: #64748b; }
|
||
.detail-foot .main { flex: 1; background: linear-gradient(135deg, #0a9f6d, #087f57); color: #fff; }
|
||
.detail-foot .danger { flex: 0 0 72px; background: rgba(239,68,68,.08); color: var(--danger); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="stage">
|
||
<div class="hero">
|
||
<h1>草稿箱 · 标题栏「管理」+ 列表是否放按钮</h1>
|
||
<p>
|
||
回应两点:①「管理」放到导航栏右侧;②列表卡片是否还要「编辑 / 提交 / 删除」。
|
||
右侧每个方案可左右滑动对比普通态 / 管理态(或详情底栏)。
|
||
</p>
|
||
<div class="note">落地时草稿页可用系统导航栏右侧文字按钮,或自定义顶栏(与工作台一致)。</div>
|
||
<div class="rec">
|
||
<b>建议:</b>标题栏右侧「管理」+ <b>列表不展示操作按钮</b>,点卡片进入编辑/详情,
|
||
「提交审批 / 删除」放详情(或编辑页)底部。列表更干净,也符合多数 OA / 邮件 App 习惯。
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tabs" id="tabs">
|
||
<button class="tab is-active" data-k="nav_clean">标题栏管理 · 列表无按钮<span class="badge">推荐</span></button>
|
||
<button class="tab" data-k="nav_btns">标题栏管理 · 列表仍有按钮</button>
|
||
<button class="tab" data-k="detail">详情底栏操作示意</button>
|
||
</div>
|
||
|
||
<div class="layout">
|
||
<div class="panel" id="desc"></div>
|
||
<div class="phones" id="phones"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const ROWS = [
|
||
["入帐单", "08-12 17:03", "v5"],
|
||
["出差申请", "08-11 09:18", "v3"],
|
||
["采购报销", "08-10 17:05", "v2"]
|
||
];
|
||
|
||
function nav(rightText, rightDone) {
|
||
return (
|
||
'<div class="nav">' +
|
||
'<div class="nav-back"></div>' +
|
||
'<div class="nav-title">草稿箱</div>' +
|
||
'<div class="nav-right' + (rightDone ? ' is-done' : '') + '">' + rightText + '</div>' +
|
||
'</div>'
|
||
);
|
||
}
|
||
|
||
function card(title, time, ver, withBtns) {
|
||
return (
|
||
'<div class="card">' +
|
||
'<div class="card-body">' +
|
||
'<div class="card-top">' +
|
||
'<div class="card-title">' + title + '</div>' +
|
||
'<div class="card-status">草稿</div>' +
|
||
'</div>' +
|
||
'<div class="meta">' + time + '<span class="dot">·</span>版本 ' + ver + '</div>' +
|
||
(withBtns ? '' : '<div class="hint-tap">点击继续编辑</div>') +
|
||
'</div>' +
|
||
(withBtns
|
||
? '<div class="card-footer"><button class="p">编辑</button><button>提交审批</button><button class="d">删除</button></div>'
|
||
: '') +
|
||
'</div>'
|
||
);
|
||
}
|
||
|
||
function phone(cap, html) {
|
||
return '<div class="phone"><div class="cap">' + cap + '</div>' + html + '</div>';
|
||
}
|
||
|
||
const DESCS = {
|
||
nav_clean: {
|
||
title: "推荐 · 标题栏管理 + 列表无按钮",
|
||
sub: "顶栏右侧「管理」;卡片只展示信息,整卡可点。",
|
||
items: [
|
||
"「管理」进导航栏右侧,搜索区干净",
|
||
"列表无编辑/提交/删除,一屏信息更疏朗",
|
||
"点卡片 → 进入编辑(现有逻辑已支持)",
|
||
"删除用「管理」批量;提交放详情/编辑底栏",
|
||
"管理态:勾选与卡片垂直居中"
|
||
],
|
||
pick: "与钉钉/飞书/企业微信草稿、邮件列表习惯一致。"
|
||
},
|
||
nav_btns: {
|
||
title: "标题栏管理 · 列表保留按钮",
|
||
sub: "管理上移后,卡片仍保留三按钮(当前能力不丢)。",
|
||
items: [
|
||
"管理入口问题已解决",
|
||
"列表仍可一键提交/删除,少一次跳转",
|
||
"代价:卡片更高、更挤,尤其短流程名时按钮区抢戏"
|
||
],
|
||
pick: "若强依赖「列表内直接提交」,可选此方案。"
|
||
},
|
||
detail: {
|
||
title: "详情 / 编辑页底部操作",
|
||
sub: "列表无按钮时,动作收口到详情底栏。",
|
||
items: [
|
||
"主按钮:提交审批(最高优先级)",
|
||
"次按钮:删除(或更多里放删除)",
|
||
"返回即退出编辑;草稿自动保存可沿用现逻辑"
|
||
],
|
||
pick: "与「列表无按钮」配套使用。"
|
||
}
|
||
};
|
||
|
||
function renderClean() {
|
||
var list = ROWS.map(function (r) { return card(r[0], r[1], r[2], false); }).join("");
|
||
var normal = phone("普通态",
|
||
nav("管理", false) +
|
||
'<div class="page"><div class="search-wrap"><div class="search">搜索流程名称</div></div>' +
|
||
'<div class="list">' + list + '<div class="end">已经到底了</div></div></div>'
|
||
);
|
||
var manage = phone("管理态 · 勾选居中",
|
||
nav("完成", true) +
|
||
'<div class="page"><div class="search-wrap"><div class="search">搜索流程名称</div></div>' +
|
||
'<div class="batch"><span>已选 1 项</span><button>批量删除</button></div>' +
|
||
'<div class="list">' +
|
||
'<div class="row is-on"><div class="check on">✓</div>' + card(ROWS[0][0], ROWS[0][1], ROWS[0][2], false).replace('hint-tap">点击继续编辑', 'hint-tap" style="display:none">') + '</div>' +
|
||
'<div class="row"><div class="check"></div>' + card(ROWS[1][0], ROWS[1][1], ROWS[1][2], false).replace('hint-tap">点击继续编辑', 'hint-tap" style="display:none">') + '</div>' +
|
||
'<div class="row"><div class="check"></div>' + card(ROWS[2][0], ROWS[2][1], ROWS[2][2], false).replace('hint-tap">点击继续编辑', 'hint-tap" style="display:none">') + '</div>' +
|
||
'</div></div>'
|
||
);
|
||
return normal + manage;
|
||
}
|
||
|
||
function renderBtns() {
|
||
var list = ROWS.map(function (r) { return card(r[0], r[1], r[2], true); }).join("");
|
||
var normal = phone("普通态 · 仍有按钮",
|
||
nav("管理", false) +
|
||
'<div class="page"><div class="search-wrap"><div class="search">搜索流程名称</div></div>' +
|
||
'<div class="list">' + list + '<div class="end">已经到底了</div></div></div>'
|
||
);
|
||
var manage = phone("管理态",
|
||
nav("完成", true) +
|
||
'<div class="page"><div class="search-wrap"><div class="search">搜索流程名称</div></div>' +
|
||
'<div class="batch"><span>已选 1 项</span><button>批量删除</button></div>' +
|
||
'<div class="list">' +
|
||
'<div class="row is-on"><div class="check on">✓</div>' + card(ROWS[0][0], ROWS[0][1], ROWS[0][2], false) + '</div>' +
|
||
'<div class="row"><div class="check"></div>' + card(ROWS[1][0], ROWS[1][1], ROWS[1][2], false) + '</div>' +
|
||
'</div></div>'
|
||
);
|
||
return normal + manage;
|
||
}
|
||
|
||
function renderDetail() {
|
||
return phone("编辑 / 详情 · 底栏",
|
||
nav("", false).replace('nav-right">', 'nav-right" style="display:none">') +
|
||
'<div class="detail">' +
|
||
'<div class="detail-body">' +
|
||
'<div class="detail-sheet">' +
|
||
'<h3>入帐单</h3>' +
|
||
'<div class="line"><span>状态</span><span>草稿</span></div>' +
|
||
'<div class="line"><span>最近保存</span><span>2026-08-12 17:03:42</span></div>' +
|
||
'<div class="line"><span>版本</span><span>v5</span></div>' +
|
||
'<div class="line"><span>说明</span><span>表单正文区域…</span></div>' +
|
||
'</div>' +
|
||
'</div>' +
|
||
'<div class="detail-foot">' +
|
||
'<button class="danger">删除</button>' +
|
||
'<button class="main">提交审批</button>' +
|
||
'</div>' +
|
||
'</div>'
|
||
) + phone("列表侧(无按钮)",
|
||
nav("管理", false) +
|
||
'<div class="page"><div class="search-wrap"><div class="search">搜索流程名称</div></div>' +
|
||
'<div class="list">' +
|
||
ROWS.map(function (r) { return card(r[0], r[1], r[2], false); }).join("") +
|
||
'</div></div>'
|
||
);
|
||
}
|
||
|
||
const RENDER = { nav_clean: renderClean, nav_btns: renderBtns, detail: renderDetail };
|
||
const descEl = document.getElementById("desc");
|
||
const phonesEl = document.getElementById("phones");
|
||
const tabs = document.getElementById("tabs");
|
||
|
||
function show(k) {
|
||
var d = DESCS[k];
|
||
descEl.innerHTML =
|
||
"<h2>" + d.title + "</h2>" +
|
||
'<p class="sub">' + d.sub + "</p>" +
|
||
"<ul>" + d.items.map(function (i) { return "<li>" + i + "</li>"; }).join("") + "</ul>" +
|
||
'<div class="pick">' + d.pick + "</div>";
|
||
phonesEl.innerHTML = RENDER[k]();
|
||
}
|
||
|
||
tabs.addEventListener("click", function (e) {
|
||
var btn = e.target.closest(".tab");
|
||
if (!btn) return;
|
||
tabs.querySelectorAll(".tab").forEach(function (t) {
|
||
t.classList.toggle("is-active", t === btn);
|
||
});
|
||
show(btn.getAttribute("data-k"));
|
||
});
|
||
|
||
show("nav_clean");
|
||
</script>
|
||
</body>
|
||
</html>
|