Files
jiu/web/docs.njk
T
wangjia 471b980179 refactor(web): 营销站重构为 Eleventy SSG,内容迁移至 Markdown
- 引入 Eleventy 静态站点生成器,页面统一使用 Nunjucks 模板
- base.njk 提供公共 nav / footer / CSS,消除三个页面间的重复代码
- 抽取 color.css(设计 token)+ style.css(公共组件 + utility 类)
- index.njk:首页迁移,用 utility class 替换大量页面私有 CSS
- download.njk:下载页重构,版本号/更新日志从 CHANGELOG.md 构建时解析,OS 自动识别
- docs.njk:文档页重构,12 章内容从 web/content/docs.md 构建时渲染,三列布局保留
- docs.css 单独提取,docs 专有样式不污染公共 CSS
- 内容面向非技术用户重写,去除技术术语和内部路径引用

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 12:24:14 +08:00

195 lines
6.4 KiB
Plaintext

---
layout: base.njk
title: 使用手册
description: 岩美酒库管理系统使用手册,覆盖入库、出库、库存、财务等全功能操作说明。
pageExtraCss: /assets/docs.css
---
<!-- ============================== DOCS SUB-NAV ============================== -->
<div class="docs-subnav">
<div class="docs-subnav-inner">
<nav class="breadcrumb">
<a href="/">岩美</a>
<span class="sep">/</span>
<span class="current">使用手册</span>
</nav>
<div class="docs-search">
<i data-lucide="search" class="search-icon icon"></i>
<input type="text" placeholder="搜索文档..." id="docs-search-input" />
<span class="kbd">⌘K</span>
</div>
<div class="docs-version">
<i data-lucide="tag" class="icon"></i>
<span class="docs-version-label">版本</span>
<span>v{{ changelog[0].version }}</span>
</div>
</div>
</div>
<!-- ============================== THREE-COLUMN LAYOUT ============================== -->
<div class="docs-layout">
<!-- Left TOC -->
<aside class="docs-toc" id="docs-toc">
{% for group in docs.toc %}
<div class="toc-section">
<div class="toc-section-title">{{ group.group }}</div>
{% for item in group.items %}
<a href="#{{ item.id }}" class="toc-link" data-chapter="{{ item.id }}">
<span class="toc-num">{{ item.num }}</span>
{{ item.title }}
</a>
{% endfor %}
</div>
{% endfor %}
</aside>
<!-- Main content -->
<main class="docs-main" id="docs-main">
{% for chapter in docs.chapters %}
<section class="docs-chapter" id="{{ chapter.id }}">
<h2>{{ chapter.num }}. {{ chapter.title }}</h2>
{{ chapter.html | safe }}
</section>
{% endfor %}
<div class="docs-feedback">
<span class="feedback-q">这篇文档对您有帮助吗?</span>
<div class="feedback-actions">
<button class="feedback-btn" onclick="sendFeedback('yes')">
<i data-lucide="thumbs-up" class="icon"></i>有帮助
</button>
<button class="feedback-btn" onclick="sendFeedback('no')">
<i data-lucide="thumbs-down" class="icon"></i>需要改进
</button>
</div>
</div>
</main>
<!-- Right rail -->
<aside class="docs-rail" id="docs-rail">
<div class="rail-title">本页目录</div>
<ul class="rail-list" id="rail-list"></ul>
<div class="rail-actions">
<button class="rail-action" onclick="window.print()">
<i data-lucide="printer" class="icon"></i>打印此页
</button>
<button class="rail-action" id="copy-link-btn">
<i data-lucide="link" class="icon"></i>复制链接
</button>
<a class="rail-action" href="#ch-1">
<i data-lucide="arrow-up" class="icon"></i>回到顶部
</a>
</div>
</aside>
</div>
<script>
(function() {
var chapters = document.querySelectorAll('.docs-chapter');
var tocLinks = document.querySelectorAll('.toc-link');
var railList = document.getElementById('rail-list');
// Build right rail from all chapter h2+h3 headings
function buildRail() {
var items = [];
chapters.forEach(function(ch) {
var chId = ch.id;
var chTitle = ch.querySelector('h2');
if (chTitle) {
items.push({ id: chId, text: chTitle.textContent, level: 2 });
}
ch.querySelectorAll('h3').forEach(function(h3) {
if (!h3.id) {
h3.id = chId + '-' + h3.textContent.replace(/\s+/g, '-').replace(/[^\w\-]/g, '').toLowerCase();
}
items.push({ id: h3.id, text: h3.textContent, level: 3 });
});
});
railList.innerHTML = items.map(function(item) {
var indent = item.level === 3 ? ' style="padding-left:20px;"' : '';
return '<li><a href="#' + item.id + '"' + indent + '>' + item.text + '</a></li>';
}).join('');
}
// Scrollspy: highlight active TOC link and rail link
function setupScrollspy() {
if (!window.IntersectionObserver) return;
var activeChapterId = null;
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
activeChapterId = entry.target.id;
}
});
if (!activeChapterId) return;
// Update left TOC
tocLinks.forEach(function(link) {
var isActive = link.getAttribute('data-chapter') === activeChapterId;
link.classList.toggle('active', isActive);
});
// Update rail links
railList.querySelectorAll('a').forEach(function(a) {
a.classList.remove('active');
if (a.getAttribute('href') === '#' + activeChapterId) {
a.classList.add('active');
}
});
}, { rootMargin: '-20% 0px -70% 0px', threshold: 0 });
chapters.forEach(function(ch) { observer.observe(ch); });
}
// Simple search: highlight matching text in main content
var searchInput = document.getElementById('docs-search-input');
if (searchInput) {
searchInput.addEventListener('input', function() {
var q = this.value.trim().toLowerCase();
if (!q) {
chapters.forEach(function(ch) { ch.style.display = ''; });
return;
}
chapters.forEach(function(ch) {
var text = ch.textContent.toLowerCase();
ch.style.display = text.includes(q) ? '' : 'none';
});
});
}
// Copy link button
var copyBtn = document.getElementById('copy-link-btn');
if (copyBtn) {
copyBtn.addEventListener('click', function() {
navigator.clipboard.writeText(window.location.href).then(function() {
copyBtn.querySelector('span, .icon') && null;
var orig = copyBtn.innerHTML;
copyBtn.innerHTML = '<i data-lucide="check" class="icon"></i>已复制';
if (window.lucide) lucide.createIcons();
setTimeout(function() { copyBtn.innerHTML = orig; if (window.lucide) lucide.createIcons(); }, 2000);
});
});
}
function sendFeedback(val) {
// Fire-and-forget; no user-visible side effect needed
try { fetch('/api/v1/public/feedback', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ helpful: val === 'yes' }) }); } catch(e) {}
var fb = document.querySelector('.docs-feedback');
if (fb) fb.innerHTML = '<span style="color:var(--success-700);font-size:var(--text-md);">感谢您的反馈!</span>';
}
window.sendFeedback = sendFeedback;
document.addEventListener('DOMContentLoaded', function() {
buildRail();
setupScrollspy();
if (window.lucide) lucide.createIcons();
});
})();
</script>