Files
zkxw/docs/mockups/oa-related-approval-print-demo.html
T
zlwuandCursor 51ce9d6059 docs(oa): add nested relatedApproval print design, plan, and demos
Records screen count+jump vs print multi-line recursion (max 3 levels)
and links the V1 related-approval spec to the revision.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-22 23:04:41 +08:00

281 lines
10 KiB
HTML
Raw 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" />
<title>关联审批单 · 打印展示方案 Demo</title>
<style>
:root {
--primary: #10b981;
--primary-dark: #059669;
--primary-bg: #ecfdf5;
--text: #334155;
--text-muted: #94a3b8;
--text-strong: #0f172a;
--border: #e2e8f0;
--bg: #f1f5f9;
--line: #94a3b8;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: Inter, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", system-ui, sans-serif;
font-size: 14px;
line-height: 1.5;
color: var(--text);
background: var(--bg);
}
.page { max-width: 1100px; margin: 0 auto; padding: 28px 24px 80px; }
h1 { margin: 0 0 8px; font-size: 22px; color: var(--text-strong); }
.lead { margin: 0 0 12px; color: var(--text-muted); max-width: 780px; }
.decision {
margin-bottom: 20px;
padding: 12px 14px;
border-radius: 10px;
background: var(--primary-bg);
border: 1px solid #a7f3d0;
font-size: 13px;
}
.decision strong { color: var(--primary-dark); }
.grid {
display: grid;
gap: 16px;
}
@media (min-width: 960px) {
.grid { grid-template-columns: 1fr 1fr; }
}
.option {
background: #fff;
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
cursor: pointer;
transition: border-color .15s, box-shadow .15s;
}
.option:hover { border-color: #a7f3d0; }
.option.is-selected {
border-color: var(--primary);
box-shadow: 0 0 0 2px rgb(16 185 129 / 25%);
}
.option.is-bad { opacity: 0.92; }
.head {
display: flex;
gap: 10px;
padding: 14px 16px 10px;
border-bottom: 1px solid var(--border);
background: #fafafa;
}
.badge {
width: 28px; height: 28px; border-radius: 8px;
display: grid; place-items: center;
background: var(--primary-bg); color: var(--primary-dark);
font-weight: 700; font-size: 13px; flex-shrink: 0;
}
.option.is-bad .badge { background: #fee2e2; color: #b91c1c; }
.meta h3 { margin: 0 0 4px; font-size: 15px; color: var(--text-strong); }
.meta p { margin: 0; font-size: 12.5px; color: var(--text-muted); }
.tag {
display: inline-block; margin-left: 6px; padding: 1px 6px;
border-radius: 4px; font-size: 11px; font-weight: 600; vertical-align: middle;
}
.tag-now { background: #fef3c7; color: #b45309; }
.tag-warn { background: #fee2e2; color: #b91c1c; }
.mock { padding: 14px 16px; background: #eef2f7; }
/* mini print sheet */
.sheet {
background: #fff;
border: 1px solid #cbd5e1;
border-radius: 4px;
padding: 14px 14px 12px;
box-shadow: 0 1px 2px rgb(15 23 42 / 6%);
}
.sheet-title {
text-align: center;
font-size: 16px;
font-weight: 700;
color: #0f172a;
margin: 0 0 8px;
}
.sheet-meta {
display: flex;
justify-content: space-between;
font-size: 11px;
color: #64748b;
margin-bottom: 8px;
}
table.print {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
table.print th,
table.print td {
border: 1px solid var(--line);
padding: 6px 8px;
vertical-align: top;
}
table.print th {
width: 28%;
background: #f8fafc;
font-weight: 600;
color: #475569;
text-align: left;
}
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; word-break: break-all; color: #64748b; }
.hl { background: #ecfdf5; }
.hl-bad { background: #fef2f2; }
.note {
margin: 0 16px 16px;
padding: 10px 12px;
border-radius: 8px;
background: #f1f5f9;
font-size: 12.5px;
}
.note strong { color: var(--primary-dark); }
.option.is-bad .note strong { color: #b91c1c; }
.pick-bar {
position: sticky; bottom: 0;
margin: 24px -24px -80px;
padding: 14px 24px;
background: rgb(255 255 255 / 94%);
border-top: 1px solid var(--border);
display: flex; justify-content: space-between; gap: 12px;
font-size: 13px; color: var(--text-muted);
}
.pick-bar em { font-style: normal; font-weight: 600; color: var(--primary-dark); }
</style>
</head>
<body>
<div class="page">
<h1>关联审批单 · 打印(PDF)如何展示?</h1>
<p class="lead">
屏幕端你已选 <strong>方案 B</strong>:嵌套关联显示「已关联 M 条」,可点进详情。
但「打印」导出的是静态 PDF,<strong>无法点击跳转</strong>。请选择打印行里该字段怎么写。
</p>
<div class="decision">
<strong>现状问题:</strong>打印逻辑把 <code>relatedApproval</code> 的值当普通数组格式化,
会直接打出一串 instanceId(UUID),既不可读,也和屏幕端「已关联 M 条」不一致。
</div>
<div class="grid" id="options">
<!-- P0 current bad -->
<article class="option is-bad" data-choice="p0-raw-id" onclick="pick(this)">
<div class="head">
<div class="badge">0</div>
<div class="meta">
<h3>现状(未特判)<span class="tag tag-warn">需改</span></h3>
<p>直接打印 UUID 列表 —— 不可接受</p>
</div>
</div>
<div class="mock">
<div class="sheet">
<div class="sheet-title">差旅报销</div>
<div class="sheet-meta"><span>安徽中科兴皖医学研究有限公司</span><span>创建时间:2026-07-20</span></div>
<table class="print">
<tr><th>审批编号</th><td>57F72ADA…</td></tr>
<tr><th>事由</th><td>客户拜访</td></tr>
<tr class="hl-bad"><th>关联审批单</th><td class="mono">B6244B87…、C1D2E3F4…</td></tr>
</table>
</div>
</div>
<div class="note"><strong>问题</strong>:纸面无法读,也不符合方案 B 语义。</div>
</article>
<!-- P1 count only -->
<article class="option" data-choice="p1-count" onclick="pick(this)">
<div class="head">
<div class="badge">1</div>
<div class="meta">
<h3>仅计数(严格对齐屏幕 B)</h3>
<p>打印「已关联 M 条」;纸面无法跳转,信息最少</p>
</div>
</div>
<div class="mock">
<div class="sheet">
<div class="sheet-title">差旅报销</div>
<div class="sheet-meta"><span>安徽中科兴皖医学研究有限公司</span><span>创建时间:2026-07-20</span></div>
<table class="print">
<tr><th>审批编号</th><td>57F72ADA…</td></tr>
<tr><th>事由</th><td>客户拜访</td></tr>
<tr class="hl"><th>关联审批单</th><td>已关联 2 条</td></tr>
</table>
</div>
</div>
<div class="note"><strong>优点</strong>:实现最简单、与屏幕文案一致。<strong>缺点</strong>:打印归档时看不出关联了哪几单。</div>
</article>
<!-- P2 names list - recommended with B -->
<article class="option" data-choice="p2-names" onclick="pick(this)">
<div class="head">
<div class="badge">2</div>
<div class="meta">
<h3>可读清单(推荐配合 B)</h3>
<p>一行汇总:应用名 · 日期(多条顿号分隔);不展开对方全字段</p>
</div>
</div>
<div class="mock">
<div class="sheet">
<div class="sheet-title">差旅报销</div>
<div class="sheet-meta"><span>安徽中科兴皖医学研究有限公司</span><span>创建时间:2026-07-20</span></div>
<table class="print">
<tr><th>审批编号</th><td>57F72ADA…</td></tr>
<tr><th>事由</th><td>客户拜访</td></tr>
<tr class="hl"><th>关联审批单</th><td>外出申请 · 07-10、立项申请 · 06-01</td></tr>
</table>
</div>
</div>
<div class="note"><strong>优点</strong>:纸面可辨认关联对象;仍不递归嵌套内容。<strong>缺点</strong>:打印前需 enrichment 取应用名/时间。</div>
</article>
<!-- P3 multi-line -->
<article class="option" data-choice="p3-multiline" onclick="pick(this)">
<div class="head">
<div class="badge">3</div>
<div class="meta">
<h3>多行清单</h3>
<p>每条关联单独占一行(或单元格内换行),含应用名、时间、可选编号尾号</p>
</div>
</div>
<div class="mock">
<div class="sheet">
<div class="sheet-title">差旅报销</div>
<div class="sheet-meta"><span>安徽中科兴皖医学研究有限公司</span><span>创建时间:2026-07-20</span></div>
<table class="print">
<tr><th>审批编号</th><td>57F72ADA…</td></tr>
<tr><th>事由</th><td>客户拜访</td></tr>
<tr class="hl">
<th>关联审批单</th>
<td>
1. 外出申请 · 2026-07-10<br />
2. 立项申请 · 2026-06-01
</td>
</tr>
</table>
</div>
</div>
<div class="note"><strong>优点</strong>:多条时更清晰。<strong>缺点</strong>:表格略占高;仍不打印对方表单正文。</div>
</article>
</div>
<p class="lead" style="margin-top:20px">
关于「嵌套」:若关联单 A 里还有关联单 B,打印侧建议与屏幕 B 一致 ——
<strong>不递归打印 B 的字段</strong>,只打印当前单直接关联的那一层可读清单(方案 2/3)。
</p>
<div class="pick-bar">
<span>当前选择:<em id="picked">尚未选择</em></span>
<span>也可回复:1 / 2 / 3(0 为需废弃的现状)</span>
</div>
</div>
<script>
function pick(el) {
document.querySelectorAll('.option').forEach((n) => n.classList.remove('is-selected'))
el.classList.add('is-selected')
const t = el.querySelector('h3')?.childNodes[0]?.textContent?.trim() || el.dataset.choice
document.getElementById('picked').textContent = t
window.__printChoice = el.dataset.choice
}
</script>
</body>
</html>