Files
zkxw/mobile-ui/zkxw-mobile-oa-drafts-nav-actions-demo.html
T
2026-08-13 14:31:57 +08:00

427 lines
17 KiB
HTML
Raw Permalink 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, 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>