Files
NextEdu/docs/mockups/editor-layout-comparison.html
SpecialX d1ad7a1f75
Some checks failed
Security / deep-security-scan (push) Failing after 2m10s
DR Drill / dr-drill (push) Failing after 1m32s
CI / scheduled-backup (push) Failing after 31s
CI / backup-verify (push) Has been skipped
CI / weekly-dr-drill (push) Failing after 0s
CI / build-deploy (push) Has been cancelled
CI / security-scan (push) Has been cancelled
docs(architecture): update impact map, data, troubleshooting, add mockups
- Update 004_architecture_impact_map.md and 005_architecture_data.json

- Remove obsolete _update_004.cjs helper script

- Update troubleshooting/known-issues.md

- Add docs/mockups/ directory
2026-07-04 23:02:14 +08:00

638 lines
24 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>备课编辑器 · 正文节点布局对比</title>
<style>
:root {
--bg: #f6f7f9;
--surface: #ffffff;
--surface-low: #f0f2f5;
--surface-high: #e7e9ee;
--outline: #d1d5db;
--outline-strong: #9ca3af;
--on-surface: #1f2937;
--on-surface-variant: #6b7280;
--primary: #1976d2;
--primary-soft: rgba(25, 118, 210, 0.12);
--anchor: #f59e0b;
--node-objective: #4caf50;
--node-teach: #1976d2;
--node-exercise: #9c27b0;
--node-summary: #ff9800;
--node-textbook: #455a64;
--radius: 10px;
--shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
--shadow-lg: 0 10px 30px rgba(0,0,0,0.10), 0 3px 8px rgba(0,0,0,0.06);
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
background: var(--bg);
color: var(--on-surface);
line-height: 1.55;
-webkit-font-smoothing: antialiased;
}
.page {
max-width: 1400px;
margin: 0 auto;
padding: 40px 24px 80px;
}
header.page-head {
margin-bottom: 32px;
}
header.page-head h1 {
font-size: 28px;
font-weight: 700;
margin: 0 0 8px;
letter-spacing: -0.01em;
}
header.page-head p {
margin: 0;
color: var(--on-surface-variant);
font-size: 15px;
max-width: 720px;
}
.layout-grid {
display: grid;
grid-template-columns: 1fr;
gap: 40px;
}
@media (min-width: 1100px) {
.layout-grid { grid-template-columns: 1fr 1fr 1fr; gap: 24px; }
}
.option {
background: var(--surface);
border-radius: 16px;
box-shadow: var(--shadow);
overflow: hidden;
display: flex;
flex-direction: column;
}
.option-head {
padding: 20px 20px 16px;
border-bottom: 1px solid var(--outline);
}
.option-tag {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--primary);
background: var(--primary-soft);
padding: 4px 10px;
border-radius: 999px;
margin-bottom: 10px;
}
.option-title {
font-size: 18px;
font-weight: 700;
margin: 0 0 6px;
}
.option-sub {
font-size: 13px;
color: var(--on-surface-variant);
margin: 0;
line-height: 1.5;
}
.option-body {
padding: 20px;
flex: 1;
display: flex;
flex-direction: column;
gap: 16px;
}
/* 共用 wireframe 样式 */
.wireframe {
background: var(--surface-low);
border: 1px solid var(--outline);
border-radius: 8px;
aspect-ratio: 4 / 3;
display: flex;
flex-direction: column;
overflow: hidden;
font-size: 10px;
color: var(--on-surface-variant);
position: relative;
}
.wf-toolbar {
height: 16px;
background: var(--surface);
border-bottom: 1px solid var(--outline);
display: flex;
align-items: center;
padding: 0 6px;
gap: 4px;
flex-shrink: 0;
}
.wf-toolbar .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--outline-strong); }
.wf-toolbar .pill { width: 18px; height: 7px; border-radius: 3px; background: var(--surface-high); }
.wf-toolbar .pill.accent { background: var(--primary-soft); }
.wf-area { flex: 1; display: flex; position: relative; overflow: hidden; }
.wf-sidebar {
width: 22%;
background: var(--surface);
border-right: 1px solid var(--outline);
padding: 6px 4px;
display: flex;
flex-direction: column;
gap: 3px;
flex-shrink: 0;
}
.wf-side-item {
height: 8px;
border-radius: 3px;
background: var(--surface-high);
padding: 0 3px;
display: flex;
align-items: center;
gap: 3px;
font-size: 7px;
}
.wf-side-item.active { background: var(--primary-soft); color: var(--primary); font-weight: 600; }
.wf-side-item .ico { width: 5px; height: 5px; border-radius: 1px; flex-shrink: 0; }
.wf-main { flex: 1; position: relative; overflow: hidden; }
.wf-right {
width: 26%;
background: var(--surface);
border-left: 1px solid var(--outline);
padding: 6px;
display: flex;
flex-direction: column;
gap: 4px;
flex-shrink: 0;
}
.wf-right .field { height: 7px; border-radius: 2px; background: var(--surface-high); }
.wf-right .field.short { width: 60%; }
.wf-right .field.tall { height: 28px; }
.wf-label {
font-size: 7px;
color: var(--on-surface-variant);
font-weight: 600;
margin-bottom: 2px;
}
/* 节点小卡片(画布模式) */
.wf-node {
position: absolute;
background: var(--surface);
border: 1.5px solid var(--outline-strong);
border-radius: 4px;
padding: 3px 5px;
font-size: 7px;
box-shadow: 0 1px 2px rgba(0,0,0,0.08);
display: flex;
align-items: center;
gap: 3px;
white-space: nowrap;
}
.wf-node .ndot { width: 4px; height: 4px; border-radius: 50%; flex-shrink: 0; }
.wf-node.objective { border-color: var(--node-objective); }
.wf-node.objective .ndot { background: var(--node-objective); }
.wf-node.teach { border-color: var(--node-teach); }
.wf-node.teach .ndot { background: var(--node-teach); }
.wf-node.exercise { border-color: var(--node-exercise); }
.wf-node.exercise .ndot { background: var(--node-exercise); }
.wf-node.summary { border-color: var(--node-summary); }
.wf-node.summary .ndot { background: var(--node-summary); }
/* 正文编辑器卡片 */
.wf-textbook {
position: absolute;
background: var(--surface);
border: 2px solid var(--node-textbook);
border-radius: 6px;
box-shadow: var(--shadow-lg);
overflow: hidden;
display: flex;
flex-direction: column;
}
.wf-textbook-head {
background: var(--node-textbook);
color: white;
font-size: 7px;
padding: 2px 5px;
font-weight: 600;
display: flex;
justify-content: space-between;
}
.wf-textbook-body {
padding: 5px 6px;
font-size: 7px;
line-height: 1.5;
flex: 1;
overflow: hidden;
}
.wf-textbook-body .h { font-weight: 700; font-size: 8px; display: block; margin-bottom: 2px; }
.wf-textbook-body .bold { font-weight: 700; }
.wf-textbook-body .anchor {
background: var(--anchor);
color: white;
padding: 0 2px;
border-radius: 2px;
font-size: 6px;
font-weight: 700;
}
.wf-textbook-body .point-anchor {
display: inline-block;
width: 8px;
height: 8px;
line-height: 8px;
text-align: center;
border-radius: 50%;
background: var(--anchor);
color: white;
font-size: 6px;
font-weight: 700;
}
.wf-textbook-toolbar {
display: flex;
gap: 3px;
padding: 2px 5px;
border-top: 1px solid var(--outline);
background: var(--surface-low);
font-size: 6px;
}
.wf-textbook-toolbar .tb {
padding: 1px 3px;
border-radius: 2px;
background: var(--surface-high);
}
/* 连线 */
.wf-edge {
position: absolute;
background: var(--primary);
opacity: 0.4;
transform-origin: 0 0;
height: 1px;
}
/* 文档流样式 */
.wf-docflow {
flex: 1;
overflow: hidden;
padding: 8px 10px;
display: flex;
flex-direction: column;
gap: 6px;
background: var(--surface);
}
.wf-docblock {
border-radius: 4px;
padding: 5px 6px;
font-size: 7px;
line-height: 1.5;
}
.wf-docblock.textbook {
background: rgba(69, 90, 100, 0.06);
border-left: 3px solid var(--node-textbook);
}
.wf-docblock.objective {
background: rgba(76, 175, 80, 0.07);
border-left: 3px solid var(--node-objective);
}
.wf-docblock.teach {
background: rgba(25, 118, 210, 0.07);
border-left: 3px solid var(--node-teach);
}
.wf-docblock.exercise {
background: rgba(156, 39, 176, 0.07);
border-left: 3px solid var(--node-exercise);
}
.wf-docblock.summary {
background: rgba(255, 152, 0, 0.07);
border-left: 3px solid var(--node-summary);
}
.wf-docblock .db-head {
font-weight: 700;
font-size: 7px;
display: flex;
align-items: center;
gap: 3px;
margin-bottom: 2px;
}
.wf-docblock .db-head .ico { width: 6px; height: 6px; border-radius: 1px; }
.wf-docblock.textbook .ico { background: var(--node-textbook); }
.wf-docblock.objective .ico { background: var(--node-objective); }
.wf-docblock.teach .ico { background: var(--node-teach); }
.wf-docblock.exercise .ico { background: var(--node-exercise); }
.wf-docblock.summary .ico { background: var(--node-summary); }
.wf-docblock .anchor { background: var(--anchor); color: white; padding: 0 2px; border-radius: 2px; font-size: 6px; font-weight: 700; }
/* 优劣对比 */
.pros-cons { display: flex; flex-direction: column; gap: 8px; }
.pros-cons .pc {
font-size: 12px;
line-height: 1.5;
}
.pros-cons .pc-label {
font-weight: 700;
font-size: 11px;
margin-bottom: 4px;
display: flex;
align-items: center;
gap: 4px;
}
.pros-cons .pc-label.pro { color: #16a34a; }
.pros-cons .pc-label.con { color: #dc2626; }
.pros-cons ul { margin: 0; padding-left: 14px; }
.pros-cons li { margin-bottom: 2px; color: var(--on-surface-variant); }
.recommend {
margin-top: 8px;
padding: 10px 12px;
background: var(--primary-soft);
border-radius: 8px;
font-size: 12px;
color: var(--primary);
font-weight: 600;
display: flex;
align-items: flex-start;
gap: 6px;
}
footer.page-foot {
margin-top: 40px;
padding-top: 24px;
border-top: 1px solid var(--outline);
color: var(--on-surface-variant);
font-size: 13px;
}
.legend {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 12px;
font-size: 12px;
}
.legend-item { display: flex; align-items: center; gap: 5px; }
.legend-dot { width: 10px; height: 10px; border-radius: 3px; }
</style>
</head>
<body>
<div class="page">
<header class="page-head">
<h1>备课编辑器 · 正文节点布局对比</h1>
<p>三种交互形态对比。共同前提:正文节点变成<strong>真实的富文本编辑器</strong>Tiptap支持加粗/标题/列表/图片真实排版,锚点用 Mark 系统而非字符串偏移。三种方案只差在"正文和教学节点如何排布"。</p>
<div class="legend">
<div class="legend-item"><span class="legend-dot" style="background:var(--node-textbook)"></span>教材正文</div>
<div class="legend-item"><span class="legend-dot" style="background:var(--node-objective)"></span>教学目标</div>
<div class="legend-item"><span class="legend-dot" style="background:var(--node-teach)"></span>新授</div>
<div class="legend-item"><span class="legend-dot" style="background:var(--node-exercise)"></span>练习</div>
<div class="legend-item"><span class="legend-dot" style="background:var(--node-summary)"></span>总结</div>
<div class="legend-item"><span class="legend-dot" style="background:var(--anchor)"></span>锚点标记</div>
</div>
</header>
<div class="layout-grid">
<!-- 方案 1画布 + 真实编辑器 -->
<section class="option">
<div class="option-head">
<span class="option-tag">方案 A</span>
<h2 class="option-title">保留画布 · 正文节点变真实编辑器</h2>
<p class="option-sub">最小改动。React Flow 画布不变,把中央那个 520px 假正文框换成真正的 Tiptap 富文本编辑器卡片,可拖拽缩放到更大。</p>
</div>
<div class="option-body">
<div class="wireframe">
<div class="wf-toolbar">
<span class="dot"></span><span class="dot"></span><span class="dot"></span>
<span class="pill accent"></span><span class="pill"></span><span class="pill"></span>
<span style="margin-left:auto;font-size:6px;">已保存</span>
</div>
<div class="wf-area">
<div class="wf-main">
<!-- 散布的教学节点 -->
<div class="wf-node objective" style="top:8%;left:6%;">
<span class="ndot"></span>教学目标
</div>
<div class="wf-node teach" style="top:14%;right:8%;">
<span class="ndot"></span>新授
</div>
<!-- 中央正文编辑器(变大) -->
<div class="wf-textbook" style="top:26%;left:18%;width:64%;height:52%;">
<div class="wf-textbook-head">
<span>📖 教材正文(可编辑副本)</span>
<span>右键锚定</span>
</div>
<div class="wf-textbook-body">
<span class="h">第一章 · 走进大自然</span>
春天的<span class="anchor"></span>轻轻吹过田野,
带来泥土的芬芳。
<br/>
<span class="bold">观察要点:</span>
<br/>• 花朵的颜色变化
<br/><span class="point-anchor"></span> 叶片的形状
<br/>• 气温的回升
</div>
<div class="wf-textbook-toolbar">
<span class="tb">B</span><span class="tb">I</span>
<span class="tb">H1</span><span class="tb"></span>
<span class="tb">🖼</span><span class="tb"></span>
</div>
</div>
<!-- 下方的教学节点 -->
<div class="wf-node exercise" style="bottom:8%;left:20%;">
<span class="ndot"></span>课堂练习
</div>
<div class="wf-node summary" style="bottom:10%;right:14%;">
<span class="ndot"></span>总结
</div>
<!-- 连线 -->
<div class="wf-edge" style="top:13%;left:14%;width:40px;transform:rotate(35deg);"></div>
<div class="wf-edge" style="top:18%;right:14%;width:38px;transform:rotate(150deg);"></div>
</div>
<div class="wf-right">
<div class="wf-label">选中节点</div>
<div class="field"></div>
<div class="field short"></div>
<div class="field tall"></div>
</div>
</div>
</div>
<div class="pros-cons">
<div class="pc">
<div class="pc-label pro">✓ 优点</div>
<ul>
<li>改动最小,画布交互不变</li>
<li>保留"思维导图"式空间关系</li>
<li>锚点系统改造可独立进行</li>
</ul>
</div>
<div class="pc">
<div class="pc-label con">✗ 缺点</div>
<ul>
<li>长文档在画布上仍受限,需频繁缩放</li>
<li>编辑器卡片和教学节点抢空间</li>
<li>移动端几乎不可用</li>
</ul>
</div>
</div>
</div>
</section>
<!-- 方案 2文档流类 Notion -->
<section class="option">
<div class="option-head">
<span class="option-tag">方案 B</span>
<h2 class="option-title">文档流为主(类 Notion</h2>
<p class="option-sub">正文和教学节点都在同一文档流里,按顺序拼成一篇完整教案。左侧大纲,中间文档,右侧选中节点详情。</p>
</div>
<div class="option-body">
<div class="wireframe">
<div class="wf-toolbar">
<span class="dot"></span><span class="dot"></span><span class="dot"></span>
<span class="pill accent"></span><span class="pill"></span><span class="pill"></span>
<span style="margin-left:auto;font-size:6px;">已保存</span>
</div>
<div class="wf-area">
<div class="wf-sidebar">
<div class="wf-label">大纲</div>
<div class="wf-side-item active"><span class="ico" style="background:var(--node-textbook)"></span>正文</div>
<div class="wf-side-item" style="padding-left:8px;"><span class="ico" style="background:var(--node-objective)"></span>目标</div>
<div class="wf-side-item" style="padding-left:8px;"><span class="ico" style="background:var(--node-teach)"></span>新授</div>
<div class="wf-side-item" style="padding-left:8px;"><span class="ico" style="background:var(--node-exercise)"></span>练习</div>
<div class="wf-side-item" style="padding-left:8px;"><span class="ico" style="background:var(--node-summary)"></span>总结</div>
</div>
<div class="wf-main">
<div class="wf-docflow">
<div class="wf-docblock textbook">
<div class="db-head"><span class="ico"></span>📖 教材正文</div>
<span style="font-weight:700;">第一章 · 走进大自然</span><br/>
春天的<span class="anchor"></span>轻轻吹过田野,带来泥土的芬芳。
<span class="point-anchor" style="display:inline-block;width:8px;height:8px;line-height:8px;text-align:center;border-radius:50%;background:var(--anchor);color:white;font-size:6px;font-weight:700;"></span> 叶片的形状
</div>
<div class="wf-docblock objective">
<div class="db-head"><span class="ico"></span>🎯 教学目标</div>
认识春天的自然现象…
</div>
<div class="wf-docblock teach">
<div class="db-head"><span class="ico"></span>📚 新授</div>
引导学生观察…
</div>
<div class="wf-docblock exercise">
<div class="db-head"><span class="ico"></span>✏ 课堂练习</div>
画一画你看到的春天…
</div>
</div>
</div>
<div class="wf-right">
<div class="wf-label">选中: 新授</div>
<div class="field"></div>
<div class="field short"></div>
<div class="field tall"></div>
</div>
</div>
</div>
<div class="pros-cons">
<div class="pc">
<div class="pc-label pro">✓ 优点</div>
<ul>
<li>编辑体验最好,长文档自然滚动</li>
<li>所见即所得,适合打印导出</li>
<li>移动端友好</li>
<li>教学节点和正文同流,关系清晰</li>
</ul>
</div>
<div class="pc">
<div class="pc-label con">✗ 缺点</div>
<ul>
<li>失去"画布"的空间思维导图感</li>
<li>需要重构数据模型(节点顺序流)</li>
<li>锚点仍需跨"正文块"定位</li>
</ul>
</div>
</div>
</div>
</section>
<!-- 方案 3双栏 -->
<section class="option">
<div class="option-head">
<span class="option-tag">方案 C</span>
<h2 class="option-title">双栏 · 正文编辑器 + 节点面板</h2>
<p class="option-sub">正文富文本编辑器独占主区域(类 A4 文档页),教学节点在右侧面板编辑,左侧是节点树。正文与节点通过锚点关联,互不混排。</p>
</div>
<div class="option-body">
<div class="wireframe">
<div class="wf-toolbar">
<span class="dot"></span><span class="dot"></span><span class="dot"></span>
<span class="pill accent"></span><span class="pill"></span><span class="pill"></span>
<span style="margin-left:auto;font-size:6px;">已保存</span>
</div>
<div class="wf-area">
<div class="wf-sidebar">
<div class="wf-label">节点树</div>
<div class="wf-side-item"><span class="ico" style="background:var(--node-textbook)"></span>📖 正文</div>
<div class="wf-side-item active"><span class="ico" style="background:var(--node-objective)"></span>🎯 目标</div>
<div class="wf-side-item"><span class="ico" style="background:var(--node-teach)"></span>📚 新授</div>
<div class="wf-side-item"><span class="ico" style="background:var(--node-exercise)"></span>✏ 练习</div>
<div class="wf-side-item"><span class="ico" style="background:var(--node-summary)"></span>📝 总结</div>
</div>
<div class="wf-main" style="background:var(--surface-low);display:flex;justify-content:center;padding:8px;">
<div style="background:var(--surface);width:80%;border-radius:4px;box-shadow:var(--shadow);padding:8px;font-size:7px;line-height:1.6;overflow:hidden;">
<div style="font-weight:700;font-size:8px;margin-bottom:3px;">第一章 · 走进大自然</div>
春天的<span class="anchor" style="background:var(--anchor);color:white;padding:0 2px;border-radius:2px;font-size:6px;font-weight:700;"></span>轻轻吹过田野,带来泥土的芬芳。
<br/><br/>
<span style="font-weight:700;">观察要点:</span>
<br/>• 花朵的颜色变化
<br/><span style="display:inline-block;width:8px;height:8px;line-height:8px;text-align:center;border-radius:50%;background:var(--anchor);color:white;font-size:6px;font-weight:700;"></span> 叶片的形状
<br/>• 气温的回升
<div style="margin-top:6px;padding-top:4px;border-top:1px solid var(--outline);display:flex;gap:3px;">
<span style="padding:1px 3px;border-radius:2px;background:var(--surface-high);font-size:6px;">B</span>
<span style="padding:1px 3px;border-radius:2px;background:var(--surface-high);font-size:6px;">I</span>
<span style="padding:1px 3px;border-radius:2px;background:var(--surface-high);font-size:6px;">H1</span>
<span style="padding:1px 3px;border-radius:2px;background:var(--surface-high);font-size:6px;"></span>
<span style="padding:1px 3px;border-radius:2px;background:var(--surface-high);font-size:6px;">🖼</span>
</div>
</div>
</div>
<div class="wf-right">
<div class="wf-label">🎯 教学目标</div>
<div class="field"></div>
<div class="field short"></div>
<div class="field tall"></div>
<div style="margin-top:4px;padding:3px;border:1px dashed var(--primary);border-radius:3px;font-size:6px;color:var(--primary);text-align:center;">+ AI 生成</div>
</div>
</div>
</div>
<div class="pros-cons">
<div class="pc">
<div class="pc-label pro">✓ 优点</div>
<ul>
<li>正文编辑区最大、最专注</li>
<li>正文与节点分离,职责清晰</li>
<li>锚点只在正文里,定位简单</li>
<li>保留节点树导航,不丢结构</li>
</ul>
</div>
<div class="pc">
<div class="pc-label con">✗ 缺点</div>
<ul>
<li>失去画布的连线/空间感</li>
<li>节点间关系靠树而非图表达</li>
<li>需要新增"节点树"组件</li>
</ul>
</div>
</div>
<div class="recommend">
★ 推荐:在"正文必须好编辑"这个核心诉求下C 兼顾了编辑体验和结构清晰,改动量适中。
</div>
</div>
</section>
</div>
<footer class="page-foot">
<p>三种方案的正文节点都是<strong>真正的 Tiptap 富文本编辑器</strong>,区别只在布局。锚点系统统一从"字符串偏移"改为 Tiptap Mark编辑时锚点自动跟随。</p>
</footer>
</div>
</body>
</html>