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>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
module.exports = function(cfg) {
|
||||
// 静态资源直接复制
|
||||
cfg.addPassthroughCopy("assets");
|
||||
|
||||
// scan.html 面向消费者,独立维护,直接复制不经模板
|
||||
cfg.addPassthroughCopy("scan.html");
|
||||
cfg.addPassthroughCopy("features");
|
||||
|
||||
return {
|
||||
dir: {
|
||||
input: ".",
|
||||
output: "dist",
|
||||
includes: "_includes",
|
||||
data: "_data",
|
||||
layouts: "_includes",
|
||||
},
|
||||
// 同时支持 .html 和 .njk 作为模板格式
|
||||
templateFormats: ["njk", "html", "md"],
|
||||
htmlTemplateEngine: "njk",
|
||||
markdownTemplateEngine: "njk",
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
scan.html
|
||||
content/
|
||||
features/approval.html
|
||||
features/inventory.html
|
||||
node_modules
|
||||
dist
|
||||
@@ -0,0 +1,44 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function() {
|
||||
const raw = fs.readFileSync(path.join(__dirname, '../../CHANGELOG.md'), 'utf8');
|
||||
const lines = raw.split('\n');
|
||||
const versions = [];
|
||||
let current = null;
|
||||
let currentSection = null;
|
||||
|
||||
for (const line of lines) {
|
||||
const versionMatch = line.match(/^## \[([^\]]+)\] - (\d{4}-\d{2}-\d{2})/);
|
||||
if (versionMatch) {
|
||||
if (current) versions.push(current);
|
||||
if (versions.length >= 3) break;
|
||||
current = { version: versionMatch[1], date: versionMatch[2], sections: [], intro: '' };
|
||||
currentSection = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
const sectionMatch = line.match(/^### (.+)/);
|
||||
if (sectionMatch && current) {
|
||||
currentSection = { type: sectionMatch[1], items: [] };
|
||||
current.sections.push(currentSection);
|
||||
continue;
|
||||
}
|
||||
|
||||
const itemMatch = line.match(/^- (.+)/);
|
||||
if (itemMatch && current) {
|
||||
if (currentSection) {
|
||||
currentSection.items.push(itemMatch[1]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Free-form text before first section (e.g. v1.0.0 intro paragraph)
|
||||
if (line.trim() && current && !currentSection && !line.startsWith('#')) {
|
||||
current.intro = current.intro ? current.intro + ' ' + line.trim() : line.trim();
|
||||
}
|
||||
}
|
||||
if (current && versions.length < 3) versions.push(current);
|
||||
|
||||
return versions;
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const md = require('markdown-it')({ html: false, breaks: false, linkify: false });
|
||||
|
||||
const TOC_GROUPS = [
|
||||
{ group: '快速开始', nums: [1, 2, 3] },
|
||||
{ group: '业务操作', nums: [4, 5, 6, 7, 8, 9] },
|
||||
{ group: '基础设置', nums: [10, 11, 12] },
|
||||
];
|
||||
|
||||
module.exports = function() {
|
||||
const raw = fs.readFileSync(path.join(__dirname, '../content/docs.md'), 'utf8');
|
||||
const lines = raw.split('\n');
|
||||
|
||||
// Split into chapters by "## {n}. {title}" headings
|
||||
const chapters = [];
|
||||
let current = null;
|
||||
|
||||
for (const line of lines) {
|
||||
const match = line.match(/^## (\d+)\. (.+)/);
|
||||
if (match) {
|
||||
if (current) chapters.push(current);
|
||||
const num = parseInt(match[1], 10);
|
||||
current = { num, id: 'ch-' + num, title: match[2].trim(), bodyLines: [] };
|
||||
} else if (current) {
|
||||
current.bodyLines.push(line);
|
||||
}
|
||||
}
|
||||
if (current) chapters.push(current);
|
||||
|
||||
// Render each chapter's body to HTML
|
||||
const rendered = chapters.map(ch => ({
|
||||
num: ch.num,
|
||||
id: ch.id,
|
||||
title: ch.title,
|
||||
html: md.render(ch.bodyLines.join('\n')),
|
||||
}));
|
||||
|
||||
// Build TOC
|
||||
const chapterMap = {};
|
||||
rendered.forEach(ch => { chapterMap[ch.num] = ch; });
|
||||
|
||||
const toc = TOC_GROUPS.map(g => ({
|
||||
group: g.group,
|
||||
items: g.nums
|
||||
.filter(n => chapterMap[n])
|
||||
.map(n => ({ id: chapterMap[n].id, num: n, title: chapterMap[n].title })),
|
||||
}));
|
||||
|
||||
return { toc, chapters: rendered };
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "岩美酒库管理系统",
|
||||
"tagline": "为酒行与酒店设计的库存管理平台",
|
||||
"copyright": "© 2026 岩美科技 · 保留所有权利",
|
||||
"icp": "沪 ICP 备 2026000000 号 · 沪公网安备 31010000000000 号",
|
||||
"support": {
|
||||
"email": "support@yanmei.app",
|
||||
"phone": "400-880-8888"
|
||||
},
|
||||
"appUrl": "/app/",
|
||||
"lucideVersion": "0.469.0"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const md = require('markdown-it')({ html: false, breaks: false });
|
||||
|
||||
module.exports = function() {
|
||||
const content = fs.readFileSync(path.join(__dirname, '../content/system-requirements.md'), 'utf8');
|
||||
return md.render(content);
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="color-scheme" content="light" />
|
||||
<title>{% if title %}{{ title }} · {% endif %}{{ site.name }}</title>
|
||||
{% if description %}<meta name="description" content="{{ description }}" />{% endif %}
|
||||
<link rel="stylesheet" href="/assets/color.css" />
|
||||
<link rel="stylesheet" href="/assets/style.css" />
|
||||
{% if pageExtraCss %}<link rel="stylesheet" href="{{ pageExtraCss }}" />{% endif %}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
<script src="https://unpkg.com/lucide@{{ site.lucideVersion }}/dist/umd/lucide.min.js"></script>
|
||||
{% if pageStyle %}<style>{{ pageStyle | safe }}</style>{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{% include "nav.njk" %}
|
||||
|
||||
{{ content | safe }}
|
||||
|
||||
{% include "footer.njk" %}
|
||||
|
||||
<script src="/assets/nav.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,55 @@
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<img src="/assets/logo-full.svg" alt="岩美" />
|
||||
<p>为酒行与酒店设计的库存、审核、财务一体化管理平台。</p>
|
||||
<div class="footer-contact">
|
||||
<div>{{ site.support.email }}</div>
|
||||
<div>{{ site.support.phone }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h5>产品</h5>
|
||||
<ul>
|
||||
<li><a href="/#modules">核心模块</a></li>
|
||||
<li><a href="/#platforms">多端覆盖</a></li>
|
||||
<li><a href="/#reports">数据洞察</a></li>
|
||||
<li><a href="/#pricing">价格方案</a></li>
|
||||
<li><a href="#">版本更新</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h5>资源</h5>
|
||||
<ul>
|
||||
<li><a href="/docs/">使用手册</a></li>
|
||||
<li><a href="#">API 文档</a></li>
|
||||
<li><a href="#">视频教程</a></li>
|
||||
<li><a href="#">数据导入模板</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h5>客户支持</h5>
|
||||
<ul>
|
||||
<li><a href="/#faq">常见问题</a></li>
|
||||
<li><a href="#">提交工单</a></li>
|
||||
<li><a href="#">技术支持</a></li>
|
||||
<li><a href="#">服务等级</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h5>公司</h5>
|
||||
<ul>
|
||||
<li><a href="#">关于岩美</a></li>
|
||||
<li><a href="#">客户案例</a></li>
|
||||
<li><a href="#">招贤纳士</a></li>
|
||||
<li><a href="#">联系我们</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<div>{{ site.copyright }}</div>
|
||||
<div>{{ site.icp }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,15 @@
|
||||
<nav class="topnav">
|
||||
<div class="topnav-inner">
|
||||
<a href="/" class="topnav-brand">
|
||||
<img src="/assets/logo-full.svg" alt="岩美" />
|
||||
</a>
|
||||
<div class="topnav-links">
|
||||
<a href="/#modules">产品</a>
|
||||
<a href="/#pricing">价格</a>
|
||||
<a href="/download/">下载</a>
|
||||
<a href="/docs/">文档</a>
|
||||
<a href="/#faq">支持</a>
|
||||
</div>
|
||||
<div class="topnav-cta" id="nav-cta"></div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,261 @@
|
||||
/* =========================================================================
|
||||
岩美 Design System — Foundations
|
||||
Tokens for color, type, spacing, radius, shadow.
|
||||
Import once at root: <link rel="stylesheet" href="colors_and_type.css">
|
||||
========================================================================= */
|
||||
|
||||
:root {
|
||||
color-scheme: light;
|
||||
|
||||
/* ---------- Brand: Primary (Slate Blue) ---------- */
|
||||
/* Trustworthy enterprise blue with a slight slate cast. */
|
||||
--brand-50: #EEF4FB;
|
||||
--brand-100: #D6E5F5;
|
||||
--brand-200: #ADC9EA;
|
||||
--brand-300: #7FA8DA;
|
||||
--brand-400: #4F86C6;
|
||||
--brand-500: #2563AC; /* Primary action */
|
||||
--brand-600: #1B4F8E; /* Hover */
|
||||
--brand-700: #154072; /* Pressed */
|
||||
--brand-800: #0F3057;
|
||||
--brand-900: #0A1F3B; /* Brand ink — headers, logo on light bg */
|
||||
|
||||
/* ---------- Neutrals (cool slate gray) ---------- */
|
||||
--gray-0: #FFFFFF;
|
||||
--gray-25: #FBFCFD;
|
||||
--gray-50: #F5F7FA;
|
||||
--gray-100: #ECEFF4;
|
||||
--gray-200: #DCE2EB;
|
||||
--gray-300: #C2CAD6;
|
||||
--gray-400: #99A3B3;
|
||||
--gray-500: #6E7888;
|
||||
--gray-600: #4F5867;
|
||||
--gray-700: #353C48;
|
||||
--gray-800: #232934;
|
||||
--gray-900: #141821;
|
||||
|
||||
/* ---------- Accent (bordeaux / 酒红) ---------- */
|
||||
/* Used sparingly: brand context cue (wine), key highlights, marketing only. */
|
||||
--accent-50: #FAEEF0;
|
||||
--accent-100: #F1D2D7;
|
||||
--accent-300: #C97B86;
|
||||
--accent-500: #8B2331;
|
||||
--accent-700: #5F1621;
|
||||
|
||||
/* ---------- Semantic ---------- */
|
||||
--success-50: #E8F5EE;
|
||||
--success-500: #2E8B57;
|
||||
--success-700: #1F6B41;
|
||||
|
||||
--warning-50: #FFF4DB;
|
||||
--warning-500: #E08E00;
|
||||
--warning-700: #A66700;
|
||||
|
||||
--danger-50: #FDECEC;
|
||||
--danger-500: #D14343;
|
||||
--danger-700: #9E2A2A;
|
||||
|
||||
--info-50: #E5F1FB;
|
||||
--info-500: #2F7BD0;
|
||||
--info-700: #1F5C9F;
|
||||
|
||||
/* ---------- Semantic foreground / background ---------- */
|
||||
--bg-app: var(--gray-50);
|
||||
--bg-surface: var(--gray-0);
|
||||
--bg-raised: var(--gray-0);
|
||||
--bg-sunken: var(--gray-100);
|
||||
--bg-overlay: rgba(20, 24, 33, 0.45);
|
||||
|
||||
--fg-default: var(--gray-800);
|
||||
--fg-muted: var(--gray-600);
|
||||
--fg-subtle: var(--gray-500);
|
||||
--fg-disabled: var(--gray-400);
|
||||
--fg-on-brand: #FFFFFF;
|
||||
--fg-link: var(--brand-500);
|
||||
|
||||
--border-subtle: var(--gray-100);
|
||||
--border-default: var(--gray-200);
|
||||
--border-strong: var(--gray-300);
|
||||
--border-focus: var(--brand-500);
|
||||
|
||||
/* ---------- Typography ---------- */
|
||||
/* Chinese-primary stack with PingFang on macOS/iOS, Microsoft YaHei on Windows,
|
||||
Noto Sans SC as web fallback (loaded via Google Fonts in index files). */
|
||||
--font-sans: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
|
||||
"Source Han Sans CN", "Noto Sans SC", -apple-system,
|
||||
BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
--font-display: var(--font-sans);
|
||||
--font-mono: "JetBrains Mono", "SF Mono", "Roboto Mono", Menlo, Consolas,
|
||||
"Microsoft YaHei", monospace;
|
||||
|
||||
/* Type scale — mobile-first, scales up for desktop dashboards */
|
||||
--text-2xs: 11px;
|
||||
--text-xs: 12px;
|
||||
--text-sm: 13px;
|
||||
--text-md: 14px; /* dashboard body default */
|
||||
--text-lg: 16px;
|
||||
--text-xl: 18px;
|
||||
--text-2xl: 22px;
|
||||
--text-3xl: 28px;
|
||||
--text-4xl: 36px;
|
||||
--text-5xl: 48px;
|
||||
|
||||
--leading-tight: 1.25;
|
||||
--leading-snug: 1.4;
|
||||
--leading-normal: 1.55;
|
||||
--leading-loose: 1.75;
|
||||
|
||||
--weight-regular: 400;
|
||||
--weight-medium: 500;
|
||||
--weight-semibold: 600;
|
||||
--weight-bold: 700;
|
||||
|
||||
/* Tracking — Chinese reads better with subtle positive tracking */
|
||||
--tracking-tight: -0.01em;
|
||||
--tracking-normal: 0;
|
||||
--tracking-wide: 0.02em;
|
||||
--tracking-cn-display: 0.04em; /* Chinese display headers */
|
||||
|
||||
/* ---------- Spacing (4px base) ---------- */
|
||||
--space-0: 0;
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-5: 20px;
|
||||
--space-6: 24px;
|
||||
--space-8: 32px;
|
||||
--space-10: 40px;
|
||||
--space-12: 48px;
|
||||
--space-16: 64px;
|
||||
--space-20: 80px;
|
||||
--space-24: 96px;
|
||||
|
||||
/* ---------- Radius — restrained, enterprise-grade ---------- */
|
||||
--radius-xs: 2px;
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 6px; /* default for inputs, buttons, badges */
|
||||
--radius-lg: 10px; /* cards */
|
||||
--radius-xl: 14px;
|
||||
--radius-pill: 999px;
|
||||
|
||||
/* ---------- Elevation — soft, neutral, no colored shadows ---------- */
|
||||
--shadow-xs: 0 1px 2px rgba(20, 24, 33, 0.04);
|
||||
--shadow-sm: 0 1px 2px rgba(20, 24, 33, 0.06), 0 1px 3px rgba(20, 24, 33, 0.04);
|
||||
--shadow-md: 0 2px 4px rgba(20, 24, 33, 0.06), 0 4px 8px rgba(20, 24, 33, 0.05);
|
||||
--shadow-lg: 0 4px 12px rgba(20, 24, 33, 0.08), 0 12px 24px rgba(20, 24, 33, 0.06);
|
||||
--shadow-xl: 0 8px 20px rgba(20, 24, 33, 0.10), 0 20px 40px rgba(20, 24, 33, 0.08);
|
||||
--shadow-inset: inset 0 1px 0 rgba(255,255,255,0.6), inset 0 -1px 0 rgba(20,24,33,0.04);
|
||||
--ring-focus: 0 0 0 3px rgba(37, 99, 172, 0.22);
|
||||
|
||||
/* ---------- Motion ---------- */
|
||||
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
--ease-emphasized: cubic-bezier(0.2, 0, 0, 1.2);
|
||||
--ease-decelerate: cubic-bezier(0, 0, 0.2, 1);
|
||||
--duration-fast: 120ms;
|
||||
--duration-base: 180ms;
|
||||
--duration-slow: 240ms;
|
||||
|
||||
/* ---------- Layout ---------- */
|
||||
--layout-sidebar: 240px;
|
||||
--layout-sidebar-collapsed: 64px;
|
||||
--layout-topbar: 56px;
|
||||
--layout-content-max: 1440px;
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
Semantic element styles — apply to base elements within design system docs.
|
||||
These do NOT bleed into ui_kits / pages with their own styles.
|
||||
========================================================================= */
|
||||
.ds-typography {
|
||||
font-family: var(--font-sans);
|
||||
color: var(--fg-default);
|
||||
font-feature-settings: "tnum" 1, "ss01" 1;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.ds-typography h1,
|
||||
.ds-h1 {
|
||||
font-size: var(--text-4xl);
|
||||
font-weight: var(--weight-semibold);
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-cn-display);
|
||||
color: var(--brand-900);
|
||||
margin: 0 0 var(--space-4);
|
||||
}
|
||||
.ds-typography h2,
|
||||
.ds-h2 {
|
||||
font-size: var(--text-3xl);
|
||||
font-weight: var(--weight-semibold);
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: var(--tracking-cn-display);
|
||||
color: var(--brand-900);
|
||||
margin: 0 0 var(--space-3);
|
||||
}
|
||||
.ds-typography h3,
|
||||
.ds-h3 {
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: var(--weight-semibold);
|
||||
line-height: var(--leading-snug);
|
||||
color: var(--gray-900);
|
||||
margin: 0 0 var(--space-3);
|
||||
}
|
||||
.ds-typography h4,
|
||||
.ds-h4 {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: var(--weight-semibold);
|
||||
line-height: var(--leading-snug);
|
||||
color: var(--gray-900);
|
||||
margin: 0 0 var(--space-2);
|
||||
}
|
||||
.ds-typography h5,
|
||||
.ds-h5 {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: var(--weight-semibold);
|
||||
line-height: var(--leading-snug);
|
||||
color: var(--gray-800);
|
||||
margin: 0 0 var(--space-2);
|
||||
}
|
||||
.ds-typography p,
|
||||
.ds-body {
|
||||
font-size: var(--text-md);
|
||||
font-weight: var(--weight-regular);
|
||||
line-height: var(--leading-normal);
|
||||
color: var(--fg-default);
|
||||
margin: 0 0 var(--space-3);
|
||||
}
|
||||
.ds-typography small,
|
||||
.ds-caption {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--fg-muted);
|
||||
line-height: var(--leading-snug);
|
||||
}
|
||||
.ds-typography code,
|
||||
.ds-mono {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.93em;
|
||||
background: var(--gray-100);
|
||||
padding: 1px 6px;
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--gray-800);
|
||||
}
|
||||
.ds-num {
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-feature-settings: "tnum" 1;
|
||||
}
|
||||
.ds-label {
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--weight-medium);
|
||||
letter-spacing: var(--tracking-wide);
|
||||
text-transform: none; /* Chinese never uppercases */
|
||||
color: var(--fg-muted);
|
||||
}
|
||||
|
||||
/* Focus ring shared across the system */
|
||||
.ds-focusable:focus-visible,
|
||||
:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: var(--ring-focus);
|
||||
border-color: var(--border-focus);
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
/* ====================================================================
|
||||
DOCS SUB-HEADER
|
||||
==================================================================== */
|
||||
.docs-subnav {
|
||||
background: var(--gray-25);
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
position: sticky;
|
||||
top: 64px;
|
||||
z-index: 40;
|
||||
}
|
||||
.docs-subnav-inner {
|
||||
max-width: 1440px;
|
||||
margin: 0 auto;
|
||||
padding: 12px 32px;
|
||||
display: flex; align-items: center; gap: 24px;
|
||||
}
|
||||
.breadcrumb {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
font-size: var(--text-sm);
|
||||
color: var(--fg-muted);
|
||||
}
|
||||
.breadcrumb .sep { color: var(--gray-300); }
|
||||
.breadcrumb a { color: var(--fg-muted); }
|
||||
.breadcrumb a:hover { color: var(--brand-500); }
|
||||
.breadcrumb .current { color: var(--gray-900); font-weight: 500; }
|
||||
|
||||
.docs-search {
|
||||
flex: 1; max-width: 480px;
|
||||
position: relative;
|
||||
}
|
||||
.docs-search input {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
padding: 0 12px 0 38px;
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--gray-0);
|
||||
font-family: inherit;
|
||||
font-size: var(--text-sm);
|
||||
color: var(--gray-800);
|
||||
outline: none;
|
||||
transition: border-color var(--duration-fast) var(--ease-standard),
|
||||
box-shadow var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
.docs-search input:focus { border-color: var(--brand-500); box-shadow: var(--ring-focus); }
|
||||
.docs-search input::placeholder { color: var(--fg-subtle); }
|
||||
.docs-search .search-icon {
|
||||
position: absolute;
|
||||
left: 12px; top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 16px; height: 16px;
|
||||
color: var(--fg-subtle);
|
||||
}
|
||||
.docs-search .kbd {
|
||||
position: absolute;
|
||||
right: 8px; top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: var(--gray-100);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: 3px;
|
||||
padding: 2px 6px;
|
||||
font-size: 11px;
|
||||
color: var(--fg-muted);
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.docs-version {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
background: var(--gray-0);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 6px 12px;
|
||||
font-size: var(--text-sm);
|
||||
color: var(--gray-700);
|
||||
}
|
||||
.docs-version .icon { width: 14px; height: 14px; }
|
||||
.docs-version-label { color: var(--fg-subtle); font-size: var(--text-xs); }
|
||||
|
||||
/* ====================================================================
|
||||
DOCS LAYOUT (three-column)
|
||||
==================================================================== */
|
||||
.docs-layout {
|
||||
max-width: 1440px;
|
||||
margin: 0 auto;
|
||||
padding: 32px;
|
||||
display: grid;
|
||||
grid-template-columns: 240px 1fr 240px;
|
||||
gap: 48px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
/* ====================================================================
|
||||
LEFT TOC
|
||||
==================================================================== */
|
||||
.docs-toc {
|
||||
position: sticky;
|
||||
top: 132px;
|
||||
max-height: calc(100vh - 152px);
|
||||
overflow-y: auto;
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
.toc-section { margin-bottom: 18px; }
|
||||
.toc-section-title {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--fg-subtle);
|
||||
text-transform: uppercase;
|
||||
margin: 0 0 10px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
.toc-link {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 7px 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--gray-700);
|
||||
font-weight: 400;
|
||||
transition: background var(--duration-fast) var(--ease-standard),
|
||||
color var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
.toc-link:hover { background: var(--gray-100); color: var(--brand-900); }
|
||||
.toc-link .toc-num {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
color: var(--fg-subtle);
|
||||
min-width: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.toc-link.active {
|
||||
background: var(--brand-50);
|
||||
color: var(--brand-700);
|
||||
font-weight: 500;
|
||||
}
|
||||
.toc-link.active .toc-num { color: var(--brand-500); }
|
||||
|
||||
/* ====================================================================
|
||||
MAIN CONTENT
|
||||
==================================================================== */
|
||||
.docs-main { min-width: 0; max-width: 760px; }
|
||||
|
||||
.docs-chapter { padding-bottom: 48px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 48px; }
|
||||
.docs-chapter:last-child { border-bottom: none; margin-bottom: 0; }
|
||||
|
||||
.docs-main h2 {
|
||||
font-size: var(--text-2xl);
|
||||
font-weight: 600;
|
||||
color: var(--brand-900);
|
||||
margin: 0 0 16px;
|
||||
letter-spacing: 0.02em;
|
||||
scroll-margin-top: 132px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 2px solid var(--brand-100);
|
||||
}
|
||||
.docs-main h3 {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 600;
|
||||
color: var(--gray-900);
|
||||
margin: 32px 0 12px;
|
||||
scroll-margin-top: 132px;
|
||||
}
|
||||
.docs-main p {
|
||||
font-size: var(--text-md);
|
||||
color: var(--gray-700);
|
||||
line-height: 1.75;
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
.docs-main strong { color: var(--brand-900); font-weight: 600; }
|
||||
.docs-main em { color: var(--brand-700); font-style: normal; font-weight: 500; }
|
||||
.docs-main code {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.92em;
|
||||
background: var(--gray-100);
|
||||
color: var(--brand-700);
|
||||
padding: 1px 6px;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
.docs-main a {
|
||||
color: var(--brand-500);
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid var(--brand-200);
|
||||
}
|
||||
.docs-main a:hover { color: var(--brand-700); border-color: var(--brand-500); }
|
||||
|
||||
.docs-main ol, .docs-main ul {
|
||||
margin: 0 0 16px;
|
||||
padding-left: 24px;
|
||||
}
|
||||
.docs-main li {
|
||||
font-size: var(--text-md);
|
||||
color: var(--gray-700);
|
||||
line-height: 1.75;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.docs-main ol li::marker {
|
||||
color: var(--brand-500);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Rendered markdown tables */
|
||||
.docs-main table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0 24px;
|
||||
font-size: var(--text-sm);
|
||||
background: var(--gray-0);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
.docs-main th, .docs-main td {
|
||||
padding: 10px 14px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
line-height: 1.55;
|
||||
}
|
||||
.docs-main thead th {
|
||||
background: var(--gray-50);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
color: var(--gray-700);
|
||||
letter-spacing: 0.02em;
|
||||
text-transform: uppercase;
|
||||
border-bottom: 1px solid var(--border-default);
|
||||
}
|
||||
.docs-main tbody tr:last-child td { border-bottom: none; }
|
||||
.docs-main tbody tr:hover { background: var(--gray-25); }
|
||||
|
||||
/* Rendered markdown code blocks */
|
||||
.docs-main pre {
|
||||
background: var(--gray-25);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 16px 20px;
|
||||
overflow-x: auto;
|
||||
margin: 16px 0 24px;
|
||||
}
|
||||
.docs-main pre code {
|
||||
background: none;
|
||||
color: var(--gray-800);
|
||||
padding: 0;
|
||||
font-size: var(--text-sm);
|
||||
line-height: 1.6;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* Blockquote → callout-style */
|
||||
.docs-main blockquote {
|
||||
background: var(--info-50);
|
||||
border-left: 3px solid var(--info-500);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 14px 18px;
|
||||
margin: 16px 0 24px;
|
||||
color: var(--info-700);
|
||||
}
|
||||
.docs-main blockquote p { color: var(--gray-700); margin: 0; font-size: var(--text-sm); line-height: 1.6; }
|
||||
|
||||
/* ====================================================================
|
||||
RIGHT RAIL
|
||||
==================================================================== */
|
||||
.docs-rail {
|
||||
position: sticky;
|
||||
top: 132px;
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
.rail-title {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--fg-subtle);
|
||||
text-transform: uppercase;
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
.rail-list { display: flex; flex-direction: column; gap: 2px; list-style: none; padding: 0; margin: 0 0 24px; }
|
||||
.rail-list a {
|
||||
display: block;
|
||||
padding: 5px 10px;
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--fg-muted);
|
||||
font-size: 13px;
|
||||
border-left: 2px solid transparent;
|
||||
}
|
||||
.rail-list a:hover { color: var(--brand-700); }
|
||||
.rail-list a.active {
|
||||
color: var(--brand-700);
|
||||
border-left-color: var(--brand-500);
|
||||
font-weight: 500;
|
||||
}
|
||||
.rail-actions {
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
display: flex; flex-direction: column; gap: 6px;
|
||||
}
|
||||
.rail-action {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 6px 10px;
|
||||
font-size: 13px;
|
||||
color: var(--fg-muted);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: none;
|
||||
font-family: inherit;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
.rail-action:hover { background: var(--gray-50); color: var(--brand-700); }
|
||||
.rail-action .icon { width: 14px; height: 14px; }
|
||||
|
||||
/* ====================================================================
|
||||
FEEDBACK WIDGET
|
||||
==================================================================== */
|
||||
.docs-feedback {
|
||||
margin-top: 40px;
|
||||
padding: 24px;
|
||||
background: var(--gray-25);
|
||||
border-radius: var(--radius-lg);
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
}
|
||||
.feedback-q { font-size: var(--text-md); color: var(--gray-800); }
|
||||
.feedback-actions { display: flex; gap: 8px; }
|
||||
.feedback-btn {
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
background: var(--gray-0);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 6px 14px;
|
||||
font-size: var(--text-sm);
|
||||
color: var(--gray-700);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
}
|
||||
.feedback-btn:hover { border-color: var(--brand-500); color: var(--brand-700); }
|
||||
.feedback-btn .icon { width: 14px; height: 14px; }
|
||||
|
||||
/* ====================================================================
|
||||
RESPONSIVE
|
||||
==================================================================== */
|
||||
@media (max-width: 1200px) {
|
||||
.docs-layout { grid-template-columns: 220px 1fr; gap: 32px; }
|
||||
.docs-rail { display: none; }
|
||||
}
|
||||
@media (max-width: 880px) {
|
||||
.docs-layout { grid-template-columns: 1fr; gap: 24px; padding: 16px; }
|
||||
.docs-toc { position: static; max-height: none; border: 1px solid var(--border-subtle); border-radius: var(--radius-md); padding: 16px; margin-bottom: 8px; }
|
||||
.docs-subnav-inner { padding: 10px 16px; }
|
||||
.docs-search { max-width: none; }
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
(function() {
|
||||
var KEYS = ['access_token','refresh_token','username','real_name','shop_no','shop_id','role'];
|
||||
|
||||
function getAuthUser() {
|
||||
var token = localStorage.getItem('flutter.access_token');
|
||||
var username = localStorage.getItem('flutter.username');
|
||||
if (!token || !username) return null;
|
||||
return {
|
||||
username: username,
|
||||
realName: localStorage.getItem('flutter.real_name') || '',
|
||||
role: localStorage.getItem('flutter.role') || '',
|
||||
shopNo: localStorage.getItem('flutter.shop_no') || '',
|
||||
};
|
||||
}
|
||||
|
||||
function doLogout() {
|
||||
KEYS.forEach(function(k) { localStorage.removeItem('flutter.' + k); });
|
||||
location.reload();
|
||||
}
|
||||
|
||||
function toggleUserMenu() {
|
||||
var el = document.getElementById('userDropdown');
|
||||
if (el) el.classList.toggle('open');
|
||||
}
|
||||
|
||||
// 点击外部关闭 dropdown
|
||||
document.addEventListener('click', function(e) {
|
||||
var menu = document.getElementById('userDropdown');
|
||||
if (!menu) return;
|
||||
var navUser = menu.closest('.nav-user');
|
||||
if (navUser && !navUser.contains(e.target)) menu.classList.remove('open');
|
||||
});
|
||||
|
||||
function renderNav() {
|
||||
var cta = document.getElementById('nav-cta');
|
||||
if (!cta) return;
|
||||
var user = getAuthUser();
|
||||
if (user) {
|
||||
var display = user.realName || user.username;
|
||||
var initial = display.charAt(0).toUpperCase();
|
||||
var roleMap = { admin: '管理员', user: '成员', readonly: '只读' };
|
||||
var roleLabel = roleMap[user.role] || user.role;
|
||||
cta.innerHTML =
|
||||
'<div class="nav-user">'
|
||||
+ '<button class="nav-user-btn" onclick="toggleUserMenu()">'
|
||||
+ '<div class="nav-avatar">' + initial + '</div>'
|
||||
+ '<span>' + display + '</span>'
|
||||
+ '<i data-lucide="chevron-down" class="icon"></i>'
|
||||
+ '</button>'
|
||||
+ '<div class="nav-dropdown" id="userDropdown">'
|
||||
+ '<div style="padding:10px 14px 6px;border-bottom:1px solid var(--border-subtle);margin-bottom:4px">'
|
||||
+ '<div style="font-size:13px;font-weight:600;color:var(--brand-900)">' + display + '</div>'
|
||||
+ '<div style="font-size:11px;color:var(--fg-muted);margin-top:2px">'
|
||||
+ (user.shopNo ? user.shopNo + ' · ' : '') + roleLabel
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '<a href="/app/"><i data-lucide="layout-dashboard" class="icon"></i>进入管理端</a>'
|
||||
+ '<div class="nav-dropdown-divider"></div>'
|
||||
+ '<button class="logout" onclick="doLogout()"><i data-lucide="log-out" class="icon"></i>退出登录</button>'
|
||||
+ '</div></div>';
|
||||
} else {
|
||||
cta.innerHTML =
|
||||
'<a href="/app/" class="btn btn-ghost">登录</a>'
|
||||
+ '<a href="/app/" class="btn btn-primary">免费试用</a>';
|
||||
}
|
||||
if (window.lucide) lucide.createIcons();
|
||||
}
|
||||
|
||||
// 暴露给 onclick 调用
|
||||
window.toggleUserMenu = toggleUserMenu;
|
||||
window.doLogout = doLogout;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
renderNav();
|
||||
if (window.lucide) lucide.createIcons();
|
||||
|
||||
// 页内锚点平滑滚动
|
||||
document.querySelectorAll('a[href^="#"]').forEach(function(a) {
|
||||
a.addEventListener('click', function(e) {
|
||||
var id = a.getAttribute('href');
|
||||
if (!id || id.length < 2) return;
|
||||
var target = document.querySelector(id);
|
||||
if (target) {
|
||||
e.preventDefault();
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,183 @@
|
||||
/* ================================================================
|
||||
shared.css — 跨页面公用样式
|
||||
设计 token 由 colors_and_type.css 提供
|
||||
================================================================ */
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
html, body {
|
||||
margin: 0; padding: 0;
|
||||
font-family: var(--font-sans);
|
||||
color: var(--fg-default);
|
||||
background: var(--gray-25);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-feature-settings: "tnum" 1;
|
||||
}
|
||||
img, svg { display: block; max-width: 100%; }
|
||||
a { color: inherit; text-decoration: none; }
|
||||
button { font-family: inherit; cursor: pointer; }
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Buttons
|
||||
---------------------------------------------------------------- */
|
||||
.btn {
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
height: 40px; padding: 0 18px;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-md); font-weight: 500;
|
||||
border: 1px solid transparent;
|
||||
transition: background var(--duration-fast) var(--ease-standard),
|
||||
border-color var(--duration-fast) var(--ease-standard),
|
||||
color var(--duration-fast) var(--ease-standard);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.btn-primary { background: var(--brand-500); color: #fff; }
|
||||
.btn-primary:hover { background: var(--brand-600); }
|
||||
.btn-primary:active { background: var(--brand-700); }
|
||||
.btn-secondary { background: var(--gray-0); color: var(--brand-900); border-color: var(--border-default); }
|
||||
.btn-secondary:hover { background: var(--gray-50); border-color: var(--border-strong); }
|
||||
.btn-ghost { background: transparent; color: var(--fg-default); }
|
||||
.btn-ghost:hover { background: var(--gray-100); }
|
||||
.btn-lg { height: 48px; padding: 0 24px; font-size: var(--text-lg); }
|
||||
.btn .icon { width: 18px; height: 18px; }
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Layout helpers
|
||||
---------------------------------------------------------------- */
|
||||
.container {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 0 32px;
|
||||
}
|
||||
.section { padding: 96px 0; }
|
||||
.section-tight { padding: 64px 0; }
|
||||
.eyebrow {
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.12em;
|
||||
color: var(--brand-500);
|
||||
text-transform: uppercase;
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
.section-title {
|
||||
font-size: var(--text-4xl);
|
||||
font-weight: 600;
|
||||
line-height: 1.18;
|
||||
letter-spacing: var(--tracking-cn-display);
|
||||
color: var(--brand-900);
|
||||
margin: 0 0 16px;
|
||||
max-width: 720px;
|
||||
}
|
||||
.section-sub {
|
||||
font-size: var(--text-lg);
|
||||
line-height: 1.6;
|
||||
color: var(--fg-muted);
|
||||
margin: 0;
|
||||
max-width: 640px;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Top Nav
|
||||
---------------------------------------------------------------- */
|
||||
.topnav {
|
||||
position: sticky; top: 0; z-index: 50;
|
||||
background: rgba(255,255,255,0.85);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
.topnav-inner {
|
||||
height: 64px;
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
max-width: 1440px; margin: 0 auto; padding: 0 32px;
|
||||
}
|
||||
.topnav-brand { display: flex; align-items: center; gap: 10px; }
|
||||
.topnav-brand img { height: 32px; }
|
||||
.topnav-links {
|
||||
display: flex; align-items: center; gap: 4px;
|
||||
font-size: var(--text-md); color: var(--gray-700);
|
||||
}
|
||||
.topnav-links a {
|
||||
padding: 8px 14px;
|
||||
border-radius: var(--radius-md);
|
||||
transition: background var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
.topnav-links a:hover { background: var(--gray-100); color: var(--brand-900); }
|
||||
.topnav-cta { display: flex; gap: 10px; align-items: center; }
|
||||
|
||||
/* Nav user dropdown */
|
||||
.nav-user { position: relative; }
|
||||
.nav-user-btn {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
height: 36px; padding: 0 12px;
|
||||
background: var(--gray-0); border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-pill); cursor: pointer;
|
||||
font-size: var(--text-md); color: var(--gray-800); font-weight: 500;
|
||||
transition: border-color var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
.nav-user-btn:hover { border-color: var(--border-strong); }
|
||||
.nav-avatar {
|
||||
width: 22px; height: 22px; border-radius: 50%;
|
||||
background: var(--brand-500); color: #fff;
|
||||
display: grid; place-items: center;
|
||||
font-size: 10px; font-weight: 700; flex-shrink: 0;
|
||||
}
|
||||
.nav-user-btn .icon { width: 14px; height: 14px; color: var(--fg-muted); }
|
||||
.nav-dropdown {
|
||||
display: none; position: absolute; top: calc(100% + 8px); right: 0;
|
||||
min-width: 160px; background: var(--gray-0);
|
||||
border: 1px solid var(--border-default); border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg); overflow: hidden; z-index: 100;
|
||||
}
|
||||
.nav-dropdown.open { display: block; }
|
||||
.nav-dropdown a, .nav-dropdown button {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
width: 100%; padding: 10px 14px;
|
||||
font-size: var(--text-sm); color: var(--gray-800);
|
||||
background: none; border: none; cursor: pointer;
|
||||
text-decoration: none; font-family: inherit;
|
||||
transition: background var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
.nav-dropdown a:hover, .nav-dropdown button:hover { background: var(--gray-50); }
|
||||
.nav-dropdown .icon { width: 14px; height: 14px; color: var(--fg-muted); }
|
||||
.nav-dropdown-divider { height: 1px; background: var(--border-subtle); margin: 4px 0; }
|
||||
.nav-dropdown .logout { color: var(--danger-600); }
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Footer
|
||||
---------------------------------------------------------------- */
|
||||
footer {
|
||||
background: var(--gray-25);
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
padding: 64px 0 40px;
|
||||
}
|
||||
.footer-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr repeat(4, 1fr);
|
||||
gap: 48px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
.footer-brand img { height: 32px; margin-bottom: 16px; }
|
||||
.footer-brand p { margin: 0 0 16px; max-width: 320px; line-height: 1.6; color: var(--fg-muted); }
|
||||
.footer-contact { font-size: var(--text-sm); color: var(--gray-700); line-height: 1.8; }
|
||||
.footer-col h5 {
|
||||
font-size: var(--text-xs); font-weight: 600;
|
||||
color: var(--brand-900); letter-spacing: 0.06em;
|
||||
margin: 0 0 16px; text-transform: uppercase;
|
||||
}
|
||||
.footer-col ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
|
||||
.footer-col li a { color: var(--gray-600); }
|
||||
.footer-col li a:hover { color: var(--brand-500); }
|
||||
.footer-bottom {
|
||||
border-top: 1px solid var(--border-subtle); padding-top: 24px;
|
||||
display: flex; justify-content: space-between;
|
||||
font-size: var(--text-xs); color: var(--fg-subtle);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Responsive
|
||||
---------------------------------------------------------------- */
|
||||
@media (max-width: 1024px) {
|
||||
.footer-grid { grid-template-columns: 1fr 1fr; }
|
||||
.container { padding: 0 20px; }
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
/* ================================================================
|
||||
style.css — 全局样式
|
||||
Token 由 color.css 提供
|
||||
分三层:① Reset & 基础 ② 组件 ③ 工具类
|
||||
================================================================ */
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
① Reset & 基础
|
||||
---------------------------------------------------------------- */
|
||||
* { box-sizing: border-box; }
|
||||
html, body {
|
||||
margin: 0; padding: 0;
|
||||
font-family: var(--font-sans);
|
||||
color: var(--fg-default);
|
||||
background: var(--gray-25);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-feature-settings: "tnum" 1;
|
||||
}
|
||||
img, svg { display: block; max-width: 100%; }
|
||||
a { color: inherit; text-decoration: none; }
|
||||
button { font-family: inherit; cursor: pointer; }
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
② 组件
|
||||
---------------------------------------------------------------- */
|
||||
|
||||
/* -- Buttons -- */
|
||||
.btn {
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
height: 40px; padding: 0 18px;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-md); font-weight: 500;
|
||||
border: 1px solid transparent;
|
||||
transition: background var(--duration-fast) var(--ease-standard),
|
||||
border-color var(--duration-fast) var(--ease-standard),
|
||||
color var(--duration-fast) var(--ease-standard);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.btn-primary { background: var(--brand-500); color: #fff; }
|
||||
.btn-primary:hover { background: var(--brand-600); }
|
||||
.btn-primary:active { background: var(--brand-700); }
|
||||
.btn-secondary { background: var(--gray-0); color: var(--brand-900); border-color: var(--border-default); }
|
||||
.btn-secondary:hover { background: var(--gray-50); border-color: var(--border-strong); }
|
||||
.btn-ghost { background: transparent; color: var(--fg-default); }
|
||||
.btn-ghost:hover { background: var(--gray-100); }
|
||||
.btn-lg { height: 48px; padding: 0 24px; font-size: var(--text-lg); }
|
||||
.btn .icon { width: 18px; height: 18px; }
|
||||
|
||||
/* -- Layout helpers -- */
|
||||
.container { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
|
||||
.section { padding: 96px 0; }
|
||||
.section-tight { padding: 64px 0; }
|
||||
.eyebrow {
|
||||
font-size: var(--text-xs); font-weight: 600;
|
||||
letter-spacing: 0.12em; color: var(--brand-500);
|
||||
text-transform: uppercase; margin: 0 0 12px;
|
||||
}
|
||||
.section-title {
|
||||
font-size: var(--text-4xl); font-weight: 600;
|
||||
line-height: 1.18; letter-spacing: var(--tracking-cn-display);
|
||||
color: var(--brand-900); margin: 0 0 16px; max-width: 720px;
|
||||
}
|
||||
.section-sub {
|
||||
font-size: var(--text-lg); line-height: 1.6;
|
||||
color: var(--fg-muted); margin: 0; max-width: 640px;
|
||||
}
|
||||
|
||||
/* -- Top Nav -- */
|
||||
.topnav {
|
||||
position: sticky; top: 0; z-index: 50;
|
||||
background: rgba(255,255,255,0.85);
|
||||
backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
.topnav-inner {
|
||||
height: 64px; display: flex; align-items: center; justify-content: space-between;
|
||||
max-width: 1440px; margin: 0 auto; padding: 0 32px;
|
||||
}
|
||||
.topnav-brand { display: flex; align-items: center; gap: 10px; }
|
||||
.topnav-brand img { height: 32px; }
|
||||
.topnav-links {
|
||||
display: flex; align-items: center; gap: 4px;
|
||||
font-size: var(--text-md); color: var(--gray-700);
|
||||
}
|
||||
.topnav-links a {
|
||||
padding: 8px 14px; border-radius: var(--radius-md);
|
||||
transition: background var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
.topnav-links a:hover { background: var(--gray-100); color: var(--brand-900); }
|
||||
.topnav-cta { display: flex; gap: 10px; align-items: center; }
|
||||
|
||||
/* Nav user dropdown */
|
||||
.nav-user { position: relative; }
|
||||
.nav-user-btn {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
height: 36px; padding: 0 12px;
|
||||
background: var(--gray-0); border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-pill); cursor: pointer;
|
||||
font-size: var(--text-md); color: var(--gray-800); font-weight: 500;
|
||||
transition: border-color var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
.nav-user-btn:hover { border-color: var(--border-strong); }
|
||||
.nav-avatar {
|
||||
width: 22px; height: 22px; border-radius: 50%;
|
||||
background: var(--brand-500); color: #fff;
|
||||
display: grid; place-items: center;
|
||||
font-size: 10px; font-weight: 700; flex-shrink: 0;
|
||||
}
|
||||
.nav-user-btn .icon { width: 14px; height: 14px; color: var(--fg-muted); }
|
||||
.nav-dropdown {
|
||||
display: none; position: absolute; top: calc(100% + 8px); right: 0;
|
||||
min-width: 160px; background: var(--gray-0);
|
||||
border: 1px solid var(--border-default); border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg); overflow: hidden; z-index: 100;
|
||||
}
|
||||
.nav-dropdown.open { display: block; }
|
||||
.nav-dropdown a, .nav-dropdown button {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
width: 100%; padding: 10px 14px;
|
||||
font-size: var(--text-sm); color: var(--gray-800);
|
||||
background: none; border: none; cursor: pointer;
|
||||
text-decoration: none; font-family: inherit;
|
||||
transition: background var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
.nav-dropdown a:hover, .nav-dropdown button:hover { background: var(--gray-50); }
|
||||
.nav-dropdown .icon { width: 14px; height: 14px; color: var(--fg-muted); }
|
||||
.nav-dropdown-divider { height: 1px; background: var(--border-subtle); margin: 4px 0; }
|
||||
.nav-dropdown .logout { color: var(--danger-600); }
|
||||
|
||||
/* -- Footer -- */
|
||||
footer {
|
||||
background: var(--gray-25);
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
padding: 64px 0 40px;
|
||||
}
|
||||
.footer-grid {
|
||||
display: grid; grid-template-columns: 1.5fr repeat(4, 1fr);
|
||||
gap: 48px; margin-bottom: 48px;
|
||||
}
|
||||
.footer-brand img { height: 32px; margin-bottom: 16px; }
|
||||
.footer-brand p { margin: 0 0 16px; max-width: 320px; line-height: 1.6; color: var(--fg-muted); }
|
||||
.footer-contact { font-size: var(--text-sm); color: var(--gray-700); line-height: 1.8; }
|
||||
.footer-col h5 {
|
||||
font-size: var(--text-xs); font-weight: 600;
|
||||
color: var(--brand-900); letter-spacing: 0.06em;
|
||||
margin: 0 0 16px; text-transform: uppercase;
|
||||
}
|
||||
.footer-col ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
|
||||
.footer-col li a { color: var(--gray-600); }
|
||||
.footer-col li a:hover { color: var(--brand-500); }
|
||||
.footer-bottom {
|
||||
border-top: 1px solid var(--border-subtle); padding-top: 24px;
|
||||
display: flex; justify-content: space-between;
|
||||
font-size: var(--text-xs); color: var(--fg-subtle);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
③ 工具类
|
||||
命名规则:{属性}-{值}
|
||||
间距值直接对应像素:p-8 = padding:8px,gap-16 = gap:16px
|
||||
---------------------------------------------------------------- */
|
||||
|
||||
/* -- Display -- */
|
||||
.d-flex { display: flex }
|
||||
.d-inline-flex { display: inline-flex }
|
||||
.d-grid { display: grid }
|
||||
.d-block { display: block }
|
||||
.d-inline { display: inline }
|
||||
.d-inline-block{ display: inline-block }
|
||||
.d-none { display: none }
|
||||
.place-center { display: grid; place-items: center } /* 图标容器常用 */
|
||||
|
||||
/* -- Flex -- */
|
||||
.flex-col { flex-direction: column }
|
||||
.flex-wrap { flex-wrap: wrap }
|
||||
.flex-1 { flex: 1 }
|
||||
.flex-shrink-0 { flex-shrink: 0 }
|
||||
.items-center { align-items: center }
|
||||
.items-start { align-items: flex-start }
|
||||
.items-end { align-items: flex-end }
|
||||
.items-baseline { align-items: baseline }
|
||||
.justify-center { justify-content: center }
|
||||
.justify-between { justify-content: space-between }
|
||||
.justify-end { justify-content: flex-end }
|
||||
.justify-start { justify-content: flex-start }
|
||||
|
||||
/* -- Grid 列模板 -- */
|
||||
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr) }
|
||||
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr) }
|
||||
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr) }
|
||||
.grid-5 { display: grid; grid-template-columns: repeat(5, 1fr) }
|
||||
|
||||
/* -- Gap -- */
|
||||
.gap-2 { gap: 2px }
|
||||
.gap-4 { gap: 4px }
|
||||
.gap-6 { gap: 6px }
|
||||
.gap-8 { gap: 8px }
|
||||
.gap-10 { gap: 10px }
|
||||
.gap-12 { gap: 12px }
|
||||
.gap-14 { gap: 14px }
|
||||
.gap-16 { gap: 16px }
|
||||
.gap-18 { gap: 18px }
|
||||
.gap-24 { gap: 24px }
|
||||
.gap-32 { gap: 32px }
|
||||
.gap-48 { gap: 48px }
|
||||
.gap-64 { gap: 64px }
|
||||
|
||||
/* -- Padding(全方向) -- */
|
||||
.p-0 { padding: 0 }
|
||||
.p-4 { padding: 4px }
|
||||
.p-6 { padding: 6px }
|
||||
.p-8 { padding: 8px }
|
||||
.p-10 { padding: 10px }
|
||||
.p-12 { padding: 12px }
|
||||
.p-14 { padding: 14px }
|
||||
.p-16 { padding: 16px }
|
||||
.p-18 { padding: 18px }
|
||||
.p-20 { padding: 20px }
|
||||
.p-24 { padding: 24px }
|
||||
.p-28 { padding: 28px }
|
||||
.p-32 { padding: 32px }
|
||||
.p-48 { padding: 48px }
|
||||
.p-56 { padding: 56px }
|
||||
.p-64 { padding: 64px }
|
||||
|
||||
/* px / py */
|
||||
.px-4 { padding-left: 4px; padding-right: 4px }
|
||||
.px-6 { padding-left: 6px; padding-right: 6px }
|
||||
.px-8 { padding-left: 8px; padding-right: 8px }
|
||||
.px-10 { padding-left: 10px; padding-right: 10px }
|
||||
.px-12 { padding-left: 12px; padding-right: 12px }
|
||||
.px-14 { padding-left: 14px; padding-right: 14px }
|
||||
.px-16 { padding-left: 16px; padding-right: 16px }
|
||||
.px-20 { padding-left: 20px; padding-right: 20px }
|
||||
.px-24 { padding-left: 24px; padding-right: 24px }
|
||||
.px-28 { padding-left: 28px; padding-right: 28px }
|
||||
.px-32 { padding-left: 32px; padding-right: 32px }
|
||||
|
||||
.py-2 { padding-top: 2px; padding-bottom: 2px }
|
||||
.py-4 { padding-top: 4px; padding-bottom: 4px }
|
||||
.py-6 { padding-top: 6px; padding-bottom: 6px }
|
||||
.py-8 { padding-top: 8px; padding-bottom: 8px }
|
||||
.py-10 { padding-top: 10px; padding-bottom: 10px }
|
||||
.py-12 { padding-top: 12px; padding-bottom: 12px }
|
||||
.py-14 { padding-top: 14px; padding-bottom: 14px }
|
||||
.py-16 { padding-top: 16px; padding-bottom: 16px }
|
||||
.py-20 { padding-top: 20px; padding-bottom: 20px }
|
||||
.py-24 { padding-top: 24px; padding-bottom: 24px }
|
||||
.py-32 { padding-top: 32px; padding-bottom: 32px }
|
||||
|
||||
/* pt / pb / pl / pr */
|
||||
.pt-4 { padding-top: 4px } .pb-4 { padding-bottom: 4px }
|
||||
.pt-6 { padding-top: 6px } .pb-6 { padding-bottom: 6px }
|
||||
.pt-8 { padding-top: 8px } .pb-8 { padding-bottom: 8px }
|
||||
.pt-12 { padding-top: 12px } .pb-12 { padding-bottom: 12px }
|
||||
.pt-14 { padding-top: 14px } .pb-14 { padding-bottom: 14px }
|
||||
.pt-16 { padding-top: 16px } .pb-16 { padding-bottom: 16px }
|
||||
.pt-24 { padding-top: 24px } .pb-24 { padding-bottom: 24px }
|
||||
.pt-32 { padding-top: 32px } .pb-32 { padding-bottom: 32px }
|
||||
.pl-12 { padding-left: 12px } .pr-12 { padding-right: 12px }
|
||||
.pl-16 { padding-left: 16px } .pr-16 { padding-right: 16px }
|
||||
.pl-24 { padding-left: 24px } .pr-24 { padding-right: 24px }
|
||||
|
||||
/* -- Margin -- */
|
||||
.m-0 { margin: 0 }
|
||||
.mx-auto { margin-left: auto; margin-right: auto }
|
||||
|
||||
.mb-0 { margin-bottom: 0 }
|
||||
.mb-2 { margin-bottom: 2px }
|
||||
.mb-4 { margin-bottom: 4px }
|
||||
.mb-6 { margin-bottom: 6px }
|
||||
.mb-8 { margin-bottom: 8px }
|
||||
.mb-10 { margin-bottom: 10px }
|
||||
.mb-12 { margin-bottom: 12px }
|
||||
.mb-14 { margin-bottom: 14px }
|
||||
.mb-16 { margin-bottom: 16px }
|
||||
.mb-18 { margin-bottom: 18px }
|
||||
.mb-24 { margin-bottom: 24px }
|
||||
.mb-32 { margin-bottom: 32px }
|
||||
.mb-48 { margin-bottom: 48px }
|
||||
|
||||
.mt-2 { margin-top: 2px }
|
||||
.mt-4 { margin-top: 4px }
|
||||
.mt-6 { margin-top: 6px }
|
||||
.mt-8 { margin-top: 8px }
|
||||
.mt-12 { margin-top: 12px }
|
||||
.mt-16 { margin-top: 16px }
|
||||
.mt-24 { margin-top: 24px }
|
||||
.mt-32 { margin-top: 32px }
|
||||
.mt-48 { margin-top: 48px }
|
||||
|
||||
.ml-4 { margin-left: 4px }
|
||||
.ml-8 { margin-left: 8px }
|
||||
.mr-4 { margin-right: 4px }
|
||||
.mr-8 { margin-right: 8px }
|
||||
|
||||
/* -- Font size(复用 token) -- */
|
||||
.fs-xs { font-size: var(--text-xs) }
|
||||
.fs-sm { font-size: var(--text-sm) }
|
||||
.fs-md { font-size: var(--text-md) }
|
||||
.fs-lg { font-size: var(--text-lg) }
|
||||
.fs-xl { font-size: var(--text-xl) }
|
||||
.fs-2xl { font-size: var(--text-2xl) }
|
||||
.fs-3xl { font-size: var(--text-3xl) }
|
||||
.fs-4xl { font-size: var(--text-4xl) }
|
||||
|
||||
/* -- Font weight -- */
|
||||
.fw-4 { font-weight: 400 }
|
||||
.fw-5 { font-weight: 500 }
|
||||
.fw-6 { font-weight: 600 }
|
||||
.fw-7 { font-weight: 700 }
|
||||
|
||||
/* -- Line height -- */
|
||||
.lh-1 { line-height: 1 }
|
||||
.lh-12 { line-height: 1.2 }
|
||||
.lh-14 { line-height: 1.4 }
|
||||
.lh-15 { line-height: 1.5 }
|
||||
.lh-16 { line-height: 1.6 }
|
||||
.lh-17 { line-height: 1.7 }
|
||||
.lh-18 { line-height: 1.8 }
|
||||
|
||||
/* -- Letter spacing -- */
|
||||
.ls-1 { letter-spacing: 0.04em }
|
||||
.ls-2 { letter-spacing: 0.06em }
|
||||
.ls-3 { letter-spacing: 0.10em }
|
||||
.ls-4 { letter-spacing: 0.12em }
|
||||
.ls-disp { letter-spacing: var(--tracking-cn-display) }
|
||||
|
||||
/* -- Text color -- */
|
||||
.text-brand { color: var(--brand-500) }
|
||||
.text-brand-hi { color: var(--brand-700) }
|
||||
.text-brand-900{ color: var(--brand-900) }
|
||||
.text-default { color: var(--fg-default) }
|
||||
.text-muted { color: var(--fg-muted) }
|
||||
.text-subtle { color: var(--fg-subtle) }
|
||||
.text-gray-6 { color: var(--gray-600) }
|
||||
.text-gray-7 { color: var(--gray-700) }
|
||||
.text-gray-8 { color: var(--gray-800) }
|
||||
.text-gray-9 { color: var(--gray-900) }
|
||||
.text-white { color: #fff }
|
||||
.text-success { color: var(--success-700) }
|
||||
.text-warning { color: var(--warning-700) }
|
||||
.text-danger { color: var(--danger-700) }
|
||||
.text-info { color: var(--info-700) }
|
||||
|
||||
/* -- Background -- */
|
||||
.bg-0 { background: var(--gray-0) }
|
||||
.bg-25 { background: var(--gray-25) }
|
||||
.bg-50 { background: var(--gray-50) }
|
||||
.bg-100 { background: var(--gray-100) }
|
||||
.bg-brand { background: var(--brand-500) }
|
||||
.bg-brand-50 { background: var(--brand-50) }
|
||||
.bg-brand-900{ background: var(--brand-900) }
|
||||
.bg-success-50 { background: var(--success-50) }
|
||||
.bg-warning-50 { background: var(--warning-50) }
|
||||
.bg-danger-50 { background: var(--danger-50) }
|
||||
.bg-info-50 { background: var(--info-50) }
|
||||
|
||||
/* -- Border -- */
|
||||
.border { border: 1px solid var(--border-default) }
|
||||
.border-top { border-top: 1px solid var(--border-default) }
|
||||
.border-bottom { border-bottom: 1px solid var(--border-default) }
|
||||
.border-left { border-left: 1px solid var(--border-default) }
|
||||
.border-subtle { border-color: var(--border-subtle) }
|
||||
.border-strong { border-color: var(--border-strong) }
|
||||
.border-brand { border-color: var(--brand-500) }
|
||||
.border-0 { border: none }
|
||||
|
||||
/* -- Border radius -- */
|
||||
.rounded-sm { border-radius: var(--radius-sm) }
|
||||
.rounded-md { border-radius: var(--radius-md) }
|
||||
.rounded-lg { border-radius: var(--radius-lg) }
|
||||
.rounded-xl { border-radius: var(--radius-xl) }
|
||||
.rounded-pill { border-radius: var(--radius-pill) }
|
||||
.rounded-full { border-radius: 50% }
|
||||
|
||||
/* -- Shadow -- */
|
||||
.shadow-sm { box-shadow: var(--shadow-sm) }
|
||||
.shadow-md { box-shadow: var(--shadow-md) }
|
||||
.shadow-lg { box-shadow: var(--shadow-lg) }
|
||||
.shadow-xl { box-shadow: var(--shadow-xl) }
|
||||
|
||||
/* -- Text helpers -- */
|
||||
.text-upper { text-transform: uppercase }
|
||||
.text-center { text-align: center }
|
||||
.text-right { text-align: right }
|
||||
.text-nowrap { white-space: nowrap }
|
||||
.font-mono { font-family: var(--font-mono) }
|
||||
.tabular { font-variant-numeric: tabular-nums }
|
||||
|
||||
/* -- Sizing & position -- */
|
||||
.w-full { width: 100% }
|
||||
.h-full { height: 100% }
|
||||
.min-w-0 { min-width: 0 }
|
||||
.pos-relative { position: relative }
|
||||
.pos-absolute { position: absolute }
|
||||
.pos-sticky { position: sticky }
|
||||
.overflow-hidden { overflow: hidden }
|
||||
.overflow-x-auto { overflow-x: auto }
|
||||
|
||||
/* -- Transition(常用属性组合) -- */
|
||||
.transition {
|
||||
transition: background var(--duration-fast) var(--ease-standard),
|
||||
border-color var(--duration-fast) var(--ease-standard),
|
||||
color var(--duration-fast) var(--ease-standard),
|
||||
box-shadow var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Card & Badge 高频组合
|
||||
---------------------------------------------------------------- */
|
||||
|
||||
/* card:bg-0 + border + rounded-lg,三个页面共用 15+ 次 */
|
||||
.card {
|
||||
background: var(--gray-0);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
|
||||
/* badge:状态标签小胶囊 */
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 600;
|
||||
}
|
||||
.badge-brand { background: var(--brand-50); color: var(--brand-700) }
|
||||
.badge-success { background: var(--success-50); color: var(--success-700) }
|
||||
.badge-warning { background: var(--warning-50); color: var(--warning-700) }
|
||||
.badge-danger { background: var(--danger-50); color: var(--danger-700) }
|
||||
.badge-info { background: var(--info-50); color: var(--info-700) }
|
||||
.badge-gray { background: var(--gray-100); color: var(--gray-700) }
|
||||
.badge-solid { background: var(--brand-500); color: #fff }
|
||||
|
||||
/* icon 尺寸 */
|
||||
.icon-sm { width: 14px; height: 14px }
|
||||
.icon-md { width: 18px; height: 18px }
|
||||
.icon-lg { width: 22px; height: 22px }
|
||||
.icon-xl { width: 28px; height: 28px }
|
||||
.icon-2xl { width: 36px; height: 36px }
|
||||
|
||||
/* icon-box:方形图标容器(带背景色时使用) */
|
||||
.icon-box-sm { width: 28px; height: 28px; border-radius: var(--radius-sm); display: grid; place-items: center }
|
||||
.icon-box-md { width: 36px; height: 36px; border-radius: 8px; display: grid; place-items: center }
|
||||
.icon-box-lg { width: 40px; height: 40px; border-radius: 10px; display: grid; place-items: center }
|
||||
.icon-box-xl { width: 56px; height: 56px; border-radius: var(--radius-md); display: grid; place-items: center }
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Responsive
|
||||
---------------------------------------------------------------- */
|
||||
@media (max-width: 1024px) {
|
||||
.footer-grid { grid-template-columns: 1fr 1fr; }
|
||||
.container { padding: 0 20px; }
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.grid-3, .grid-4, .grid-5 { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
@@ -0,0 +1,487 @@
|
||||
# 岩美酒库管理系统 · 使用手册
|
||||
|
||||
> 适用版本:v1.x · 受众:酒行管理员及工作人员
|
||||
|
||||
---
|
||||
|
||||
## 1. 系统概述
|
||||
|
||||
岩美酒库管理系统专为酒行门店设计,将入库、出库、库存查询、财务往来等日常业务整合到一个平台,支持多人协同操作,数据实时同步。
|
||||
|
||||
**核心功能一览**
|
||||
|
||||
| 模块 | 主要用途 |
|
||||
|------|---------|
|
||||
| 入库管理 | 新建入库单、提交审核、审批通过后自动更新库存 |
|
||||
| 出库管理 | 新建出库单、提交审核、审批时自动扣减库存 |
|
||||
| 库存管理 | 查询实时库存、库存盘点、打印标签 |
|
||||
| 财务管理 | 查看应付款(欠供应商)和应收款(客户欠款)、标记结清 |
|
||||
| 往来单位 | 管理供应商和客户的基本信息 |
|
||||
| 基础数据 | 维护商品名称、系列、规格字典 |
|
||||
| 系统设置 | 用户管理、仓库管理、编号规则、数据导入 |
|
||||
|
||||
**支持平台**:Web 浏览器(现已上线);Windows、macOS、iOS、Android 客户端即将推出。
|
||||
|
||||
---
|
||||
|
||||
## 2. 登录与退出
|
||||
|
||||
### 2.1 登录
|
||||
|
||||
1. 打开系统,进入登录页面。
|
||||
2. 在「门店编号」栏输入酒行的门店代号(例如 `S001`)。
|
||||
3. 输入「用户名」和「密码」。
|
||||
4. 点击「登录」按钮。
|
||||
|
||||
登录成功后,系统自动跳转到「入库管理」页面。
|
||||
|
||||
**提示**:系统会记录最近登录过的用户名,点击输入框可从候选列表中快速选择。
|
||||
|
||||
### 2.2 退出登录
|
||||
|
||||
点击顶部右侧用户名旁的下拉箭头,选择「退出登录」。
|
||||
|
||||
### 2.3 查看当前登录信息
|
||||
|
||||
点击顶部左侧「岩美」标题或右侧「门店编号」区域,弹出门店信息面板,显示门店编号、登录账号、姓名、系统版本。
|
||||
|
||||
---
|
||||
|
||||
## 3. 界面说明
|
||||
|
||||
系统主界面由三个区域组成:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 顶部导航栏(标题、门店编号、用户名、退出) │
|
||||
├──────────┬───────────────────────────────────────────────┤
|
||||
│ │ │
|
||||
│ 左侧 │ 主内容区域 │
|
||||
│ 侧边栏 │ │
|
||||
│ │ │
|
||||
├──────────┴───────────────────────────────────────────────┤
|
||||
│ 状态栏(门店、用户、登录时间、当前时间、连接状态) │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**左侧侧边栏导航项**
|
||||
|
||||
| 导航项 | 功能 |
|
||||
|--------|------|
|
||||
| 入库管理 | 入库单录入与审核 |
|
||||
| 出库管理 | 出库单录入与审核 |
|
||||
| 库存管理 | 库存查询与盘点 |
|
||||
| 财务管理 | 应付款和应收款 |
|
||||
| 往来单位 | 供应商与客户 |
|
||||
| 基础数据 | 商品名称、系列、规格字典 |
|
||||
| 系统设置 | 用户、仓库、编号规则等配置 |
|
||||
|
||||
点击侧边栏顶部的菜单图标可收起或展开侧边栏,节省屏幕空间。
|
||||
|
||||
**更新提示**:有新版本时,内容区顶部会显示黄色提示横幅;如果是必须更新的版本,会弹出对话框要求立即更新。
|
||||
|
||||
**离线提示**:网络断开时,顶部显示红色横幅「网络连接已断开」,状态栏变红,此时展示上次加载的缓存数据。
|
||||
|
||||
---
|
||||
|
||||
## 4. 角色与权限
|
||||
|
||||
系统有四种角色,权限从高到低依次为:
|
||||
|
||||
| 角色 | 说明 | 可执行操作 |
|
||||
|------|------|------------|
|
||||
| 超级管理员 | 系统最高权限账号 | 全部操作,含数据清空 |
|
||||
| 管理员 | 门店管理人员 | 全部操作,含用户管理、酒行信息编辑 |
|
||||
| 操作员 | 日常录入审核人员 | 新建、编辑、提交、审核单据,查询数据 |
|
||||
| 只读 | 仅查看数据 | 只能查看,不能新建、修改、删除任何数据 |
|
||||
|
||||
**权限说明**
|
||||
|
||||
- 只读账号点击任何写操作按钮时,系统将直接提示「无权限」。
|
||||
- 新增或编辑用户、重置密码仅管理员可操作。
|
||||
- 修改酒行基本信息仅管理员可操作。
|
||||
- 数据清空仅超级管理员可操作。
|
||||
|
||||
---
|
||||
|
||||
## 5. 入库管理
|
||||
|
||||
入库管理页面包含两个标签页:**入库审核**(新建和待审核)和**入库单**(已完成记录)。
|
||||
|
||||
### 5.1 入库单状态说明
|
||||
|
||||
单据状态按以下流程流转:
|
||||
|
||||
**草稿** → **待审核** → **已审批**(库存增加)
|
||||
|
||||
待审核阶段也可被拒绝,变为**已拒绝**状态(库存不变)。
|
||||
|
||||
| 状态 | 含义 |
|
||||
|------|------|
|
||||
| 草稿 | 已保存但未提交,可继续编辑或删除 |
|
||||
| 待审核 | 已提交等待审批,不可再编辑 |
|
||||
| 已审批 | 审批通过,库存已增加,同时生成应付账款记录 |
|
||||
| 已拒绝 | 审批不通过,库存不变 |
|
||||
|
||||
### 5.2 新建入库单
|
||||
|
||||
1. 点击左侧「入库管理」,切换到「入库审核」标签页。
|
||||
2. 点击右上角「新建入库审核单」按钮。
|
||||
3. 填写入库基本信息:
|
||||
- **仓库**(必填):选择货物入库的目标仓库。
|
||||
- **供应商**(必填):选择供货的往来单位。
|
||||
- **入库日期**(必填):默认为今天,可修改。
|
||||
- **备注**(选填):填写本批次入库说明。
|
||||
4. 在商品明细区域填写每一行商品:
|
||||
- **商品名称**(必填):从字典中选择或直接输入。
|
||||
- **系列**(必填):选择商品系列。
|
||||
- **规格**(必填):选择商品规格,如 500ml×6。
|
||||
- **生产日期**(必填):点击日历图标选择。
|
||||
- **批次号**(选填):填写批次编号,用于后续追踪查询。
|
||||
- **数量**(必填):填写入库数量。
|
||||
- **单价**(必填):填写进货单价,系统自动计算总金额。
|
||||
5. 点击「添加商品」可继续增加商品行,点击行末「删除」可移除该行。
|
||||
6. 完成后选择操作:
|
||||
- **保存草稿**:保存后可以继续修改。
|
||||
- **保存并提交审核**:提交后进入待审核状态,不可再编辑。
|
||||
|
||||
### 5.3 提交审核
|
||||
|
||||
草稿状态的入库单,在列表中点击「提交」按钮,确认后单据进入「待审核」状态。
|
||||
|
||||
### 5.4 审批入库单
|
||||
|
||||
操作员及以上权限的用户均可审批。
|
||||
|
||||
1. 在「入库审核」标签页中找到待审核的入库单。
|
||||
2. 点击「通过」:弹窗确认,确认后系统自动将商品入库,库存增加,同时生成一笔应付账款记录。
|
||||
3. 点击「拒绝」:弹窗确认,拒绝后库存不变,单据进入「已拒绝」状态。
|
||||
|
||||
**注意**:审批通过后操作不可撤销,请仔细核对商品数量和单价后再确认。
|
||||
|
||||
### 5.5 查看入库单详情
|
||||
|
||||
点击入库单号(蓝色链接)可弹出详情页,显示完整的商品明细、数量、金额及审核信息。详情页右上角有打印按钮,可直接打印入库单。
|
||||
|
||||
### 5.6 打印入库单
|
||||
|
||||
在列表中点击对应行的「打印」按钮,直接调用打印机打印入库单据。
|
||||
|
||||
### 5.7 打印商品标签
|
||||
|
||||
1. 在列表中点击对应行的「打标签」按钮。
|
||||
2. 弹出商品标签打印对话框,列出本次入库的所有商品。
|
||||
3. 勾选需要打印标签的商品(默认全选)。
|
||||
4. 点击「打印选中」,系统逐张打印选中商品的标签。
|
||||
|
||||
标签内容包括:商品名称、编码、系列、规格、批次号、生产日期、酒行名称及联系方式、二维码。
|
||||
|
||||
### 5.8 标记货款结清
|
||||
|
||||
审批通过的入库单会自动生成应付账款记录。货款付清后,在列表中点击「结清」按钮,确认后将对应财务记录标记为已结清。
|
||||
|
||||
### 5.9 筛选与导出
|
||||
|
||||
- **仓库筛选**:点击列头「仓库」的筛选图标,选择仓库进行过滤。
|
||||
- **供应商筛选**:点击列头「供应商」的筛选图标,选择供应商进行过滤。
|
||||
- **日期筛选**:点击「选择日期」按钮,选择日期范围。
|
||||
- **导出**:点击「导出」按钮,将当前列表导出为 Excel 文件。
|
||||
|
||||
---
|
||||
|
||||
## 6. 出库管理
|
||||
|
||||
出库管理与入库管理操作流程类似,包含**出库审核**(待处理)和**出库单**(已完成)两个标签页。
|
||||
|
||||
### 6.1 出库单状态说明
|
||||
|
||||
出库单状态流转与入库单相同:草稿 → 待审核 → 已审批或已拒绝。
|
||||
|
||||
审批通过后:
|
||||
- 系统会先检查库存是否充足,库存不足时审批失败并给出提示,库存不变。
|
||||
- 库存充足时自动扣减库存,并生成应收账款记录。
|
||||
|
||||
### 6.2 新建出库单
|
||||
|
||||
1. 点击左侧「出库管理」,切换到「出库审核」标签页。
|
||||
2. 点击右上角「新建出库审核单」按钮。
|
||||
3. 填写基本信息:
|
||||
- **仓库**(必填):选择出货仓库。
|
||||
- **客户**(必填):选择购买方(往来单位中的客户类型)。
|
||||
- **出库日期**(必填):默认今天,可修改。
|
||||
4. 填写商品明细:商品名称、系列、规格、数量、单价(操作方式同入库单)。
|
||||
5. 保存草稿或保存并提交审核。
|
||||
|
||||
**注意**:出库数量不能超过当前库存,审批时系统会自动检查,库存不足会提示失败。
|
||||
|
||||
### 6.3 审批出库单
|
||||
|
||||
操作步骤与入库审批相同。审批通过后库存自动扣减,同时生成应收账款记录。
|
||||
|
||||
### 6.4 打印出库单
|
||||
|
||||
在列表中点击「打印」按钮,打印出库单据。
|
||||
|
||||
### 6.5 标记货款结清
|
||||
|
||||
出库单审批通过后生成应收账款。收到货款后,在列表中点击「结清」按钮,将对应财务记录标记为已结清。
|
||||
|
||||
---
|
||||
|
||||
## 7. 库存管理
|
||||
|
||||
### 7.1 查询库存
|
||||
|
||||
点击左侧「库存管理」进入库存列表。
|
||||
|
||||
列表显示每个商品的实时库存数量、所在仓库、单价、金额、生产日期、批次等信息。
|
||||
|
||||
- **搜索**:在搜索框输入商品名称关键字(也支持拼音或拼音首字母),实时过滤结果。
|
||||
- **仓库筛选**:点击列头「仓库」的筛选图标,按仓库查看库存。
|
||||
- **导出**:点击「导出」按钮,将当前库存列表导出为 Excel 文件。
|
||||
|
||||
### 7.2 修改备注
|
||||
|
||||
在库存列表中,点击「备注」列对应单元格(显示铅笔图标或现有备注内容),弹出编辑框,填写后点击「保存」即可。
|
||||
|
||||
### 7.3 打印商品标签
|
||||
|
||||
在库存列表中点击某商品行的「打印标签」按钮,可单独打印该商品的标签。
|
||||
|
||||
### 7.4 库存盘点
|
||||
|
||||
1. 在库存管理页面切换到「库存盘点」标签页。
|
||||
2. 选择要盘点的**仓库**,系统自动加载该仓库所有商品的账面库存数量。
|
||||
3. 选择盘点类型(全盘)。
|
||||
4. 逐行填写**实际盘点数量**(与账面不符时修改数量)。
|
||||
5. 点击「提交盘点」完成。
|
||||
|
||||
盘点单编号由系统自动生成。
|
||||
|
||||
### 7.5 库存流水
|
||||
|
||||
「库存流水」标签页可查看每次库存变动记录,包括入库、出库的时间、变动数量等。
|
||||
|
||||
---
|
||||
|
||||
## 8. 财务管理
|
||||
|
||||
### 8.1 财务记录说明
|
||||
|
||||
系统在以下情况自动生成财务记录:
|
||||
- 入库单审批通过 → 自动生成**应付账款**(欠供应商的货款)
|
||||
- 出库单审批通过 → 自动生成**应收账款**(客户欠的货款)
|
||||
|
||||
点击左侧「财务管理」进入财务页面,包含三个标签:
|
||||
|
||||
| 标签 | 内容 |
|
||||
|------|------|
|
||||
| 全部记录 | 所有财务流水 |
|
||||
| 应付账款 | 需要向供应商付款的记录 |
|
||||
| 应收账款 | 客户尚未付款的记录 |
|
||||
|
||||
### 8.2 查看财务记录
|
||||
|
||||
- 默认显示当前月份的记录,可通过月份选择器查看历史月份。
|
||||
- 支持按「类型」和「往来单位」列头筛选。
|
||||
- 点击「导出」可导出当月数据为 Excel 文件。
|
||||
|
||||
### 8.3 标记结清
|
||||
|
||||
**方式一**:在入库单或出库单列表中点击「结清」按钮,直接结清该单据对应的账款。
|
||||
|
||||
**方式二**:在财务管理列表中找到对应记录,点击「结清」按钮,单笔结清。
|
||||
|
||||
结清后该记录状态从「未结清」变为「已结清」。
|
||||
|
||||
### 8.4 财务汇总
|
||||
|
||||
财务管理页面显示当期应付和应收总额,便于掌握资金往来概况。
|
||||
|
||||
---
|
||||
|
||||
## 9. 往来单位
|
||||
|
||||
往来单位管理**供应商**和**客户**两类信息,新建入库单时选择供应商,新建出库单时选择客户。
|
||||
|
||||
### 9.1 查看往来单位
|
||||
|
||||
点击左侧「往来单位」,通过「供应商」和「客户」标签页分别查看。列表支持按名称搜索和导出。
|
||||
|
||||
### 9.2 新建往来单位
|
||||
|
||||
1. 在对应标签页点击右上角「新建」按钮。
|
||||
2. 填写信息:
|
||||
- **名称**(必填)
|
||||
- **联系电话**(选填)
|
||||
- **地址**(选填)
|
||||
- **卡号**(选填,如有账户绑定)
|
||||
- **初始余额**(选填,导入历史数据时填写)
|
||||
- **备注**(选填)
|
||||
3. 点击「保存」。
|
||||
|
||||
### 9.3 编辑往来单位
|
||||
|
||||
在列表中点击「编辑」按钮,修改信息后保存。
|
||||
|
||||
### 9.4 删除往来单位
|
||||
|
||||
在列表中点击「删除」按钮,确认后删除。
|
||||
|
||||
**注意**:已关联入库单或出库单的往来单位不可删除。
|
||||
|
||||
---
|
||||
|
||||
## 10. 基础数据(商品管理)
|
||||
|
||||
点击左侧「基础数据」,进入商品字典管理页面,包含三个标签:**商品名称**、**系列**、**规格**。
|
||||
|
||||
这些字典数据是新建入库或出库单时选择商品的基础,需要先在此处维护好商品信息。
|
||||
|
||||
### 10.1 商品名称管理
|
||||
|
||||
商品名称是酒品的主名称,例如「茅台飞天 53°」。
|
||||
|
||||
1. 在「商品名称」标签页,点击「新建」按钮。
|
||||
2. 填写商品名称(必填)、编号(选填)、备注(选填)。
|
||||
3. 点击「保存」。
|
||||
|
||||
支持按名称或编号搜索,支持分页浏览,支持编辑和删除。
|
||||
|
||||
### 10.2 系列管理
|
||||
|
||||
系列是商品所属的系列或品牌线,例如「飞天系列」「王子系列」。操作步骤与商品名称相同。
|
||||
|
||||
### 10.3 规格管理
|
||||
|
||||
规格用于描述包装规格,例如「500ml×6」「1000ml×1」。新建时可填写「单品数量」(即一箱包含的单瓶数量)。
|
||||
|
||||
### 10.4 商品详情与二维码
|
||||
|
||||
每个商品都有唯一的二维码,可通过扫码访问商品公开信息页面。在商品详情页可查看或上传商品图片。
|
||||
|
||||
---
|
||||
|
||||
## 11. 系统设置
|
||||
|
||||
点击左侧「系统设置」,包含七个标签页。
|
||||
|
||||
### 11.1 酒行信息
|
||||
|
||||
显示本门店的基本信息:门店编号、门店名称、地址、联系电话、负责人。
|
||||
|
||||
**编辑**(仅管理员):点击「编辑信息」按钮,修改门店名称、地址、电话、负责人后保存。门店编号不可修改。
|
||||
|
||||
### 11.2 用户管理(仅管理员)
|
||||
|
||||
**查看用户**:显示本门店所有用户的姓名、用户名、角色、启用状态。
|
||||
|
||||
**新增用户**:
|
||||
1. 点击「新增用户」按钮。
|
||||
2. 填写用户名(登录账号,不可重复)、姓名、手机号、初始密码。
|
||||
3. 选择角色(操作员、管理员、只读、超级管理员)。
|
||||
4. 点击「保存」。
|
||||
|
||||
**编辑用户**:点击用户行的「编辑」按钮,可修改姓名、手机号、角色(用户名不可修改)。
|
||||
|
||||
**重置密码**:点击「重置密码」按钮,输入新密码后确认,下次登录时使用新密码。
|
||||
|
||||
**启用或停用**:在用户列表中拨动状态开关。停用后该用户无法登录。
|
||||
|
||||
### 11.3 仓库管理
|
||||
|
||||
**查看仓库**:显示所有仓库名称、位置、是否为默认仓库。
|
||||
|
||||
**新建仓库**:
|
||||
1. 点击「新建」按钮。
|
||||
2. 填写仓库名称(必填)、位置(选填)。
|
||||
3. 可勾选「设为默认仓库」,新建单据时将自动选择此仓库。
|
||||
4. 点击「保存」。
|
||||
|
||||
**编辑或删除**:点击对应按钮操作。已有库存的仓库不可删除。
|
||||
|
||||
### 11.4 编号规则
|
||||
|
||||
系统为每类单据自动生成唯一编号,格式由前缀、日期和序号组成,例如入库单编号 `RK20260523001`。
|
||||
|
||||
**查看当前规则**:列表显示每种单据的前缀、当前序号及下一编号示例。
|
||||
|
||||
**修改规则**:
|
||||
1. 点击对应规则行的「编辑」按钮。
|
||||
2. 可修改「前缀」和「当前序号」。
|
||||
3. 点击「保存」,修改后对新建单据生效。
|
||||
|
||||
**注意**:请勿将序号调小至已使用过的范围,否则可能导致编号重复。
|
||||
|
||||
### 11.5 系统参数
|
||||
|
||||
配置系统的全局参数:
|
||||
|
||||
- **系统名称、货币单位、日期格式、时区**(通常无需修改)
|
||||
- **入库单需要审核**:关闭后提交即视为通过,无需审批
|
||||
- **出库单需要审核**:关闭后同上
|
||||
- **允许超量出库**:开启后,出库数量超过库存时仍可审批通过
|
||||
|
||||
修改后点击「保存设置」生效,点击「重置默认」恢复出厂默认值。
|
||||
|
||||
### 11.6 数据导入
|
||||
|
||||
通过 Excel 文件批量导入历史数据。支持以下数据类型:往来单位、商品名称、商品系列、商品规格、商品编码、库存。
|
||||
|
||||
各类型的 Excel 格式要求详见系统内「系统设置 → 数据导入」页面说明。
|
||||
|
||||
**操作步骤**:
|
||||
1. 在对应数据类型行点击「选择文件」,选择 Excel(.xls 或 .xlsx)文件。
|
||||
2. 全部文件选择完成后,点击「全部导入」按钮。
|
||||
3. 系统依次处理每个文件并显示导入结果(新增、跳过重复、失败数量)。
|
||||
4. 如有失败,根据错误提示修正文件后重新导入。
|
||||
|
||||
**导入规则**:以名称去重,已存在的记录不重复导入。导入过程中请勿切换页面。
|
||||
|
||||
**数据清空(仅超级管理员)**:在数据导入页面下方「危险操作」区域,选择要清空的数据表,点击确认后输入「确认清空」完成操作。**此操作不可撤销,请务必提前做好数据备份。**
|
||||
|
||||
### 11.7 关于
|
||||
|
||||
- **版本信息**:显示当前系统版本。有新版本时可点击「立即更新」。
|
||||
- **授权信息**:显示授权类型(试用、月付、年付、买断)、授权状态、到期时间。授权剩余不足 30 天时会显示倒计时提醒。
|
||||
- **意见反馈**:点击「反馈 Bug」或「功能建议」,通过邮件向开发团队反馈。
|
||||
|
||||
---
|
||||
|
||||
## 12. 常见问题
|
||||
|
||||
**Q:入库单提交后发现填错了,怎么办?**
|
||||
|
||||
单据提交(待审核状态)后不可再修改。请联系管理员将该单据拒绝,然后重新新建一张正确的入库单。
|
||||
|
||||
**Q:出库审批时提示「库存不足」,怎么处理?**
|
||||
|
||||
出库数量超过当前仓库库存时,系统会拒绝审批。请检查出库数量,或确认对应商品的入库单是否已审批通过、库存已更新。
|
||||
|
||||
**Q:结清了财务记录但发现结清错了,如何撤销?**
|
||||
|
||||
目前系统不支持撤销结清操作。如需处理,请联系技术支持。
|
||||
|
||||
**Q:如何查找某批商品是从哪张入库单入库的?**
|
||||
|
||||
在库存管理列表中查看商品的批次号,然后在入库管理中按批次号搜索对应的入库单。
|
||||
|
||||
**Q:导入数据时提示「格式错误」,怎么处理?**
|
||||
|
||||
请检查 Excel 文件的列顺序是否与「系统设置 → 数据导入」页面说明的格式一致,且第一行为数据行(无需填写表头)。如问题持续,可将文件发送给技术支持排查。
|
||||
|
||||
**Q:用户无法登录,怎么处理?**
|
||||
|
||||
请管理员在「系统设置 → 用户管理」中检查该用户是否处于启用状态,并使用「重置密码」功能为其设置新密码。
|
||||
|
||||
**Q:操作时提示「无权限」,是什么原因?**
|
||||
|
||||
当前账号角色为「只读」,不允许执行写操作。如需操作,请联系管理员调整账号角色。
|
||||
|
||||
**Q:系统显示「网络连接已断开」,数据还准确吗?**
|
||||
|
||||
网络断开时,系统展示上次加载的缓存数据,可能不是最新状态。请恢复网络连接后刷新页面获取最新数据。
|
||||
|
||||
**Q:如何联系技术支持?**
|
||||
|
||||
进入「系统设置 → 关于」查看联系邮箱和技术支持时间。工作日(周一至周五)9:00 - 18:00 可获得响应。
|
||||
@@ -0,0 +1,36 @@
|
||||
## Web 版(已上线)
|
||||
|
||||
| 要求 | 最低 | 推荐 |
|
||||
|---|---|---|
|
||||
| 浏览器 | Chrome 90 / Firefox 90 / Safari 15 / Edge 90 | 最新稳定版 |
|
||||
| 网络 | 任意宽带 | 10 Mbps+ |
|
||||
|
||||
## Windows(敬请期待)
|
||||
|
||||
| 要求 | 版本 |
|
||||
|---|---|
|
||||
| 系统 | Windows 10(64 位)及以上 |
|
||||
| 内存 | 4 GB RAM |
|
||||
| 存储 | 500 MB 可用空间 |
|
||||
|
||||
## macOS(敬请期待)
|
||||
|
||||
| 要求 | 版本 |
|
||||
|---|---|
|
||||
| 系统 | macOS 12 及以上 |
|
||||
| 内存 | 4 GB RAM |
|
||||
| 存储 | 500 MB 可用空间 |
|
||||
|
||||
## iOS(敬请期待)
|
||||
|
||||
| 要求 | 版本 |
|
||||
|---|---|
|
||||
| 系统 | iOS 15 及以上 |
|
||||
| 设备 | iPhone 8 / iPad 第 6 代及以上 |
|
||||
|
||||
## Android(敬请期待)
|
||||
|
||||
| 要求 | 版本 |
|
||||
|---|---|
|
||||
| 系统 | Android 9 及以上 |
|
||||
| 内存 | 3 GB RAM |
|
||||
-1167
File diff suppressed because it is too large
Load Diff
+194
@@ -0,0 +1,194 @@
|
||||
---
|
||||
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>
|
||||
-1218
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,506 @@
|
||||
---
|
||||
layout: base.njk
|
||||
title: 下载
|
||||
description: 下载岩美酒库管理系统,Web 版现已上线,Windows / macOS / iOS / Android 客户端即将推出。
|
||||
pageStyle: |
|
||||
/* ── Page header ── */
|
||||
.page-header {
|
||||
padding: 72px 0 56px;
|
||||
background:
|
||||
radial-gradient(700px 360px at 80% 20%, rgba(37, 99, 172, 0.06), transparent 60%),
|
||||
linear-gradient(180deg, #FBFCFD 0%, #FFFFFF 80%);
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
.ph-inner {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 64px;
|
||||
align-items: center;
|
||||
}
|
||||
.ph-eyebrow {
|
||||
font-size: var(--text-xs); font-weight: 600;
|
||||
letter-spacing: 0.12em; color: var(--brand-500);
|
||||
text-transform: uppercase;
|
||||
margin: 0 0 12px;
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.ph-eyebrow .version-badge {
|
||||
background: var(--brand-500); color: #fff;
|
||||
padding: 3px 8px; border-radius: var(--radius-sm);
|
||||
font-family: var(--font-mono);
|
||||
letter-spacing: 0.02em; font-size: 11px;
|
||||
}
|
||||
.ph-title {
|
||||
font-size: 44px; font-weight: 700; line-height: 1.15;
|
||||
letter-spacing: var(--tracking-cn-display);
|
||||
color: var(--brand-900); margin: 0 0 18px;
|
||||
}
|
||||
.ph-lead {
|
||||
font-size: var(--text-lg); color: var(--gray-600);
|
||||
line-height: 1.6; margin: 0 0 24px; max-width: 480px;
|
||||
}
|
||||
.ph-meta {
|
||||
display: flex; gap: 24px;
|
||||
font-size: var(--text-sm); color: var(--fg-muted);
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
padding-top: 16px;
|
||||
}
|
||||
.ph-meta-item { display: flex; flex-direction: column; gap: 2px; }
|
||||
.ph-meta-label { font-size: 11px; color: var(--fg-subtle); letter-spacing: 0.04em; }
|
||||
.ph-meta-val { font-size: var(--text-sm); color: var(--gray-800); font-weight: 500; }
|
||||
|
||||
/* ── Auto-detect card ── */
|
||||
.detect-card {
|
||||
background: var(--gray-0);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
.detect-card-head {
|
||||
padding: 14px 20px;
|
||||
background: var(--gray-50);
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
font-size: var(--text-xs); color: var(--fg-muted);
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
}
|
||||
.detect-card-head .head-left { display: flex; align-items: center; gap: 6px; }
|
||||
.detect-card-head .head-left svg { width: 14px; height: 14px; color: var(--success-500); }
|
||||
.detect-card-body {
|
||||
padding: 28px;
|
||||
display: flex; gap: 24px; align-items: center;
|
||||
}
|
||||
.detect-icon {
|
||||
width: 72px; height: 72px;
|
||||
background: var(--brand-50); border-radius: 16px;
|
||||
display: grid; place-items: center;
|
||||
color: var(--brand-500); flex-shrink: 0;
|
||||
}
|
||||
.detect-icon svg { width: 38px; height: 38px; }
|
||||
.detect-info { flex: 1; }
|
||||
.detect-info h3 { margin: 0 0 4px; font-size: var(--text-xl); font-weight: 600; color: var(--brand-900); }
|
||||
.detect-info p { margin: 0; font-size: var(--text-sm); color: var(--fg-muted); }
|
||||
.detect-card-actions { padding: 0 28px 28px; display: flex; gap: 8px; }
|
||||
.detect-card-actions .btn-primary { flex: 1; justify-content: center; }
|
||||
|
||||
/* ── Platform grid ── */
|
||||
.dl-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 12px;
|
||||
margin-top: 32px;
|
||||
}
|
||||
.dl-card {
|
||||
background: var(--gray-0);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 20px;
|
||||
display: flex; flex-direction: column;
|
||||
transition: border-color var(--duration-base) var(--ease-standard),
|
||||
box-shadow var(--duration-base) var(--ease-standard);
|
||||
}
|
||||
.dl-card:hover { border-color: var(--brand-300); box-shadow: var(--shadow-sm); }
|
||||
.dl-card.detected { border-color: var(--brand-400); box-shadow: var(--shadow-md); }
|
||||
.dl-card.coming-soon { opacity: 0.65; }
|
||||
.dl-card-icon {
|
||||
width: 48px; height: 48px;
|
||||
background: var(--brand-50); border-radius: var(--radius-md);
|
||||
display: grid; place-items: center; color: var(--brand-500);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.dl-card-icon svg { width: 24px; height: 24px; }
|
||||
.dl-card-name { font-size: var(--text-md); font-weight: 600; color: var(--brand-900); margin: 0 0 4px; }
|
||||
.dl-card-desc { font-size: var(--text-xs); color: var(--fg-muted); margin: 0 0 14px; line-height: 1.5; flex: 1; }
|
||||
.dl-status {
|
||||
display: inline-flex; align-items: center; gap: 4px;
|
||||
font-size: 10px; font-weight: 600; letter-spacing: 0.04em;
|
||||
padding: 3px 8px; border-radius: var(--radius-pill); margin-bottom: 12px;
|
||||
}
|
||||
.dl-status.available { background: var(--success-50); color: var(--success-700); }
|
||||
.dl-status.soon { background: var(--gray-100); color: var(--fg-muted); }
|
||||
.dl-card-btn {
|
||||
display: flex; align-items: center; justify-content: center; gap: 6px;
|
||||
height: 34px; padding: 0 14px;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm); font-weight: 500;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer; width: 100%;
|
||||
transition: background var(--duration-fast) var(--ease-standard);
|
||||
text-decoration: none;
|
||||
}
|
||||
.dl-card-btn.primary { background: var(--brand-500); color: #fff; }
|
||||
.dl-card-btn.primary:hover { background: var(--brand-600); }
|
||||
.dl-card-btn.disabled {
|
||||
background: var(--gray-100); color: var(--fg-muted);
|
||||
cursor: default; pointer-events: none;
|
||||
border-color: var(--border-subtle);
|
||||
}
|
||||
.dl-card-btn svg { width: 14px; height: 14px; }
|
||||
|
||||
/* ── System requirements (rendered markdown) ── */
|
||||
.sysreq-content h2 {
|
||||
font-size: var(--text-xl); font-weight: 600;
|
||||
color: var(--brand-900); margin: 28px 0 12px;
|
||||
letter-spacing: var(--tracking-cn-display);
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
.sysreq-content h2:first-child { margin-top: 0; }
|
||||
.sysreq-content table {
|
||||
width: 100%; border-collapse: collapse;
|
||||
font-size: var(--text-sm); color: var(--gray-800);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.sysreq-content th {
|
||||
text-align: left; font-size: 11px; font-weight: 600;
|
||||
letter-spacing: 0.04em; text-transform: uppercase;
|
||||
color: var(--fg-muted); padding: 8px 12px;
|
||||
background: var(--gray-50);
|
||||
border: 1px solid var(--border-subtle);
|
||||
}
|
||||
.sysreq-content td {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border-subtle);
|
||||
vertical-align: top;
|
||||
}
|
||||
.sysreq-content tr:hover td { background: var(--gray-25); }
|
||||
.sysreq-content p { font-size: var(--text-sm); color: var(--fg-muted); margin: 8px 0 0; }
|
||||
|
||||
/* ── Changelog timeline ── */
|
||||
.changelog {
|
||||
display: grid;
|
||||
grid-template-columns: 180px 1fr;
|
||||
gap: 0;
|
||||
margin-top: 40px;
|
||||
border-left: 1px solid var(--border-subtle);
|
||||
}
|
||||
.changelog-entry { display: contents; }
|
||||
.changelog-meta {
|
||||
padding: 28px 24px 28px 32px;
|
||||
position: relative;
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
.changelog-meta::before {
|
||||
content: '';
|
||||
position: absolute; left: -7px; top: 36px;
|
||||
width: 13px; height: 13px; border-radius: 50%;
|
||||
background: var(--gray-0); border: 3px solid var(--gray-300);
|
||||
}
|
||||
.changelog-entry.current .changelog-meta::before {
|
||||
background: var(--brand-500); border-color: var(--brand-100);
|
||||
box-shadow: 0 0 0 4px var(--brand-50);
|
||||
}
|
||||
.changelog-version {
|
||||
font-family: var(--font-mono); font-size: var(--text-md); font-weight: 600;
|
||||
color: var(--brand-900); margin-bottom: 4px;
|
||||
}
|
||||
.changelog-date { font-size: var(--text-xs); color: var(--fg-muted); }
|
||||
.changelog-tag {
|
||||
display: inline-block; font-size: 10px;
|
||||
background: var(--success-50); color: var(--success-700);
|
||||
padding: 2px 8px; border-radius: var(--radius-pill);
|
||||
font-weight: 500; margin-top: 8px;
|
||||
}
|
||||
.changelog-body {
|
||||
padding: 28px 0 28px 32px;
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
border-left: 1px solid var(--border-subtle);
|
||||
margin-left: -1px;
|
||||
}
|
||||
.changelog-entry:last-child .changelog-meta,
|
||||
.changelog-entry:last-child .changelog-body { border-bottom: none; }
|
||||
.changelog-intro {
|
||||
font-size: var(--text-sm); color: var(--gray-700);
|
||||
line-height: 1.6; margin: 0 0 16px;
|
||||
}
|
||||
.changelog-cat { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
|
||||
.changelog-cat-label {
|
||||
font-size: 11px; font-weight: 600; letter-spacing: 0.06em;
|
||||
color: var(--fg-muted); text-transform: uppercase;
|
||||
display: flex; align-items: center; gap: 6px; margin-bottom: 2px;
|
||||
}
|
||||
.changelog-cat-label .dot { width: 6px; height: 6px; border-radius: 50%; }
|
||||
.dot-feature { background: var(--brand-500); }
|
||||
.dot-improve { background: var(--success-500); }
|
||||
.dot-fix { background: var(--warning-500); }
|
||||
.changelog-cat ul {
|
||||
margin: 0; padding: 0; list-style: none;
|
||||
font-size: var(--text-sm); color: var(--gray-700); line-height: 1.6;
|
||||
}
|
||||
.changelog-cat ul li {
|
||||
padding: 3px 0 3px 16px; position: relative;
|
||||
}
|
||||
.changelog-cat ul li::before {
|
||||
content: ''; position: absolute; left: 0; top: 11px;
|
||||
width: 6px; height: 1px; background: var(--gray-400);
|
||||
}
|
||||
|
||||
/* ── Responsive ── */
|
||||
@media (max-width: 1024px) {
|
||||
.ph-inner { grid-template-columns: 1fr; gap: 32px; }
|
||||
.ph-title { font-size: 36px; }
|
||||
.dl-grid { grid-template-columns: repeat(3, 1fr); }
|
||||
.changelog { grid-template-columns: 120px 1fr; }
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.dl-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
.page-header { padding: 48px 0 40px; }
|
||||
}
|
||||
---
|
||||
|
||||
<!-- ============================== PAGE HEADER ============================== -->
|
||||
<section class="page-header">
|
||||
<div class="container ph-inner">
|
||||
<div>
|
||||
<div class="ph-eyebrow">
|
||||
<span class="version-badge">v{{ changelog[0].version }}</span>
|
||||
<span>下载岩美</span>
|
||||
</div>
|
||||
<h1 class="ph-title">随时随地,<br/>轻松管理酒库。</h1>
|
||||
<p class="ph-lead">
|
||||
Web 版已正式上线,浏览器直接访问,无需安装。Windows、macOS、iOS、Android 客户端即将推出。
|
||||
</p>
|
||||
<div class="ph-meta">
|
||||
<div class="ph-meta-item">
|
||||
<div class="ph-meta-label">最新版本</div>
|
||||
<div class="ph-meta-val version-badge">v{{ changelog[0].version }}</div>
|
||||
</div>
|
||||
<div class="ph-meta-item">
|
||||
<div class="ph-meta-label">发布日期</div>
|
||||
<div class="ph-meta-val">{{ changelog[0].date }}</div>
|
||||
</div>
|
||||
<div class="ph-meta-item">
|
||||
<div class="ph-meta-label">可用平台</div>
|
||||
<div class="ph-meta-val">Web 浏览器</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auto-detect card -->
|
||||
<div class="detect-card">
|
||||
<div class="detect-card-head">
|
||||
<span class="head-left">
|
||||
<i data-lucide="zap" class="icon"></i>
|
||||
已自动识别您的环境
|
||||
</span>
|
||||
<span style="font-family: var(--font-mono); color: var(--fg-subtle);">推荐</span>
|
||||
</div>
|
||||
<div class="detect-card-body">
|
||||
<div class="detect-icon" id="detect-icon">
|
||||
<i data-lucide="globe" class="icon"></i>
|
||||
</div>
|
||||
<div class="detect-info">
|
||||
<h3 id="detect-name">Web 版</h3>
|
||||
<p id="detect-desc">浏览器直接访问,功能完整,无需下载安装。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detect-card-actions">
|
||||
<a href="https://jiu.51yanmei.com/app/" class="btn btn-primary btn-lg" id="detect-btn">
|
||||
<i data-lucide="arrow-right" class="icon"></i>
|
||||
立即使用 Web 版
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================== PLATFORM GRID ============================== -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h2 class="fs-3xl fw-6 text-brand-900 m-0 mb-6" style="letter-spacing: var(--tracking-cn-display);">支持的平台</h2>
|
||||
<p class="fs-md text-muted m-0 mb-8">Web 版现已可用,其余平台正在开发中。</p>
|
||||
|
||||
<div class="dl-grid" id="platform-grid">
|
||||
<!-- Web -->
|
||||
<div class="dl-card" data-platform="web">
|
||||
<div class="dl-card-icon"><i data-lucide="globe" class="icon"></i></div>
|
||||
<h3 class="dl-card-name">Web 版</h3>
|
||||
<p class="dl-card-desc">浏览器直接访问,功能完整,无需安装,支持 PC 与平板。</p>
|
||||
<span class="dl-status available">✓ 已上线</span>
|
||||
<a href="https://jiu.51yanmei.com/app/" class="dl-card-btn primary">
|
||||
<i data-lucide="arrow-right" class="icon"></i>立即使用
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Windows -->
|
||||
<div class="dl-card coming-soon" data-platform="windows">
|
||||
<div class="dl-card-icon"><i data-lucide="monitor" class="icon"></i></div>
|
||||
<h3 class="dl-card-name">Windows</h3>
|
||||
<p class="dl-card-desc">原生桌面客户端,支持离线模式与本地打印。</p>
|
||||
<span class="dl-status soon">敬请期待</span>
|
||||
<span class="dl-card-btn disabled">
|
||||
<i data-lucide="clock" class="icon"></i>即将推出
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- macOS -->
|
||||
<div class="dl-card coming-soon" data-platform="macos">
|
||||
<div class="dl-card-icon"><i data-lucide="laptop" class="icon"></i></div>
|
||||
<h3 class="dl-card-name">macOS</h3>
|
||||
<p class="dl-card-desc">支持 Apple Silicon 与 Intel 芯片,通用版本。</p>
|
||||
<span class="dl-status soon">敬请期待</span>
|
||||
<span class="dl-card-btn disabled">
|
||||
<i data-lucide="clock" class="icon"></i>即将推出
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- iOS -->
|
||||
<div class="dl-card coming-soon" data-platform="ios">
|
||||
<div class="dl-card-icon"><i data-lucide="smartphone" class="icon"></i></div>
|
||||
<h3 class="dl-card-name">iOS</h3>
|
||||
<p class="dl-card-desc">iPhone 与 iPad 通用,支持扫码与推送通知。</p>
|
||||
<span class="dl-status soon">敬请期待</span>
|
||||
<span class="dl-card-btn disabled">
|
||||
<i data-lucide="clock" class="icon"></i>即将推出
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Android -->
|
||||
<div class="dl-card coming-soon" data-platform="android">
|
||||
<div class="dl-card-icon"><i data-lucide="tablet-smartphone" class="icon"></i></div>
|
||||
<h3 class="dl-card-name">Android</h3>
|
||||
<p class="dl-card-desc">手机与平板通用,支持主流应用商店及 APK 安装。</p>
|
||||
<span class="dl-status soon">敬请期待</span>
|
||||
<span class="dl-card-btn disabled">
|
||||
<i data-lucide="clock" class="icon"></i>即将推出
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================== SYSTEM REQUIREMENTS ============================== -->
|
||||
<section class="section bg-25">
|
||||
<div class="container">
|
||||
<h2 class="fs-3xl fw-6 text-brand-900 m-0 mb-6" style="letter-spacing: var(--tracking-cn-display);">系统要求</h2>
|
||||
<p class="fs-md text-muted m-0 mb-32">在以下环境中均经过测试与验证。</p>
|
||||
<div class="card p-32 sysreq-content">
|
||||
{{ sysreq | safe }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================== CHANGELOG ============================== -->
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h2 class="fs-3xl fw-6 text-brand-900 m-0 mb-6" style="letter-spacing: var(--tracking-cn-display);">版本更新日志</h2>
|
||||
<p class="fs-md text-muted m-0">最近 {{ changelog | length }} 个版本。</p>
|
||||
|
||||
<div class="changelog">
|
||||
{% for entry in changelog %}
|
||||
<div class="changelog-entry{% if loop.first %} current{% endif %}">
|
||||
<div class="changelog-meta">
|
||||
<div class="changelog-version">v{{ entry.version }}</div>
|
||||
<div class="changelog-date">{{ entry.date }}</div>
|
||||
{% if loop.first %}<span class="changelog-tag">当前版本</span>{% endif %}
|
||||
</div>
|
||||
<div class="changelog-body">
|
||||
{% if entry.intro %}
|
||||
<p class="changelog-intro">{{ entry.intro }}</p>
|
||||
{% endif %}
|
||||
{% for section in entry.sections %}
|
||||
<div class="changelog-cat">
|
||||
<div class="changelog-cat-label">
|
||||
{% if section.type == "新功能" %}
|
||||
<span class="dot dot-feature"></span>新功能
|
||||
{% elif section.type == "改进" %}
|
||||
<span class="dot dot-improve"></span>改进
|
||||
{% elif section.type == "修复" %}
|
||||
<span class="dot dot-fix"></span>问题修复
|
||||
{% else %}
|
||||
<span class="dot dot-improve"></span>{{ section.type }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<ul>
|
||||
{% for item in section.items %}
|
||||
<li>{{ item }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
var platforms = {
|
||||
web: { name: 'Web 版', desc: '浏览器直接访问,功能完整,无需下载安装。', icon: 'globe', btnText: '立即使用 Web 版', btnHref: 'https://jiu.51yanmei.com/app/', available: true },
|
||||
ios: { name: 'iOS', desc: 'iOS 客户端正在开发中,敬请期待。', icon: 'smartphone', btnText: '敬请期待', available: false },
|
||||
android: { name: 'Android', desc: 'Android 客户端正在开发中,敬请期待。', icon: 'tablet-smartphone', btnText: '敬请期待', available: false },
|
||||
windows: { name: 'Windows 桌面', desc: 'Windows 客户端正在开发中,敬请期待。', icon: 'monitor', btnText: '敬请期待', available: false },
|
||||
macos: { name: 'macOS 桌面', desc: 'macOS 客户端正在开发中,敬请期待。', icon: 'laptop', btnText: '敬请期待', available: false }
|
||||
};
|
||||
|
||||
function detectPlatform() {
|
||||
var ua = navigator.userAgent;
|
||||
if (/iPhone|iPad|iPod/.test(ua)) return 'ios';
|
||||
if (/Android/.test(ua)) return 'android';
|
||||
var platform = navigator.platform || '';
|
||||
if (/Win/.test(platform) || /Win/.test(ua)) return 'windows';
|
||||
if (/Mac/.test(platform) || /Mac/.test(ua)) return 'macos';
|
||||
return 'web';
|
||||
}
|
||||
|
||||
function updateDetectCard(p) {
|
||||
var info = platforms[p];
|
||||
var nameEl = document.getElementById('detect-name');
|
||||
var descEl = document.getElementById('detect-desc');
|
||||
var btnEl = document.getElementById('detect-btn');
|
||||
var iconEl = document.getElementById('detect-icon');
|
||||
if (nameEl) nameEl.textContent = info.name;
|
||||
if (descEl) descEl.textContent = info.desc;
|
||||
if (btnEl) {
|
||||
if (info.available) {
|
||||
btnEl.href = info.btnHref;
|
||||
btnEl.style.opacity = '';
|
||||
btnEl.style.pointerEvents = '';
|
||||
btnEl.querySelector('span') && (btnEl.querySelector('span').textContent = info.btnText);
|
||||
} else {
|
||||
btnEl.href = '#';
|
||||
btnEl.style.opacity = '0.5';
|
||||
btnEl.style.pointerEvents = 'none';
|
||||
}
|
||||
btnEl.childNodes.forEach(function(n) {
|
||||
if (n.nodeType === 3) n.textContent = ' ' + info.btnText;
|
||||
});
|
||||
}
|
||||
if (iconEl && window.lucide) {
|
||||
iconEl.innerHTML = '';
|
||||
var svg = document.createElement('i');
|
||||
svg.setAttribute('data-lucide', info.icon);
|
||||
svg.className = 'icon';
|
||||
iconEl.appendChild(svg);
|
||||
lucide.createIcons();
|
||||
}
|
||||
}
|
||||
|
||||
function highlightPlatformCard(p) {
|
||||
document.querySelectorAll('#platform-grid .dl-card').forEach(function(el) {
|
||||
el.classList.remove('detected');
|
||||
});
|
||||
var card = document.querySelector('#platform-grid [data-platform="' + p + '"]');
|
||||
if (card) card.classList.add('detected');
|
||||
}
|
||||
|
||||
function updateVersionBadges(version) {
|
||||
document.querySelectorAll('.version-badge').forEach(function(el) {
|
||||
el.textContent = 'v' + version;
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var detected = detectPlatform();
|
||||
updateDetectCard(detected);
|
||||
highlightPlatformCard(detected);
|
||||
|
||||
fetch('https://jiu.51yanmei.com/api/v1/public/release')
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) { if (data && data.version) updateVersionBadges(data.version); })
|
||||
.catch(function() {});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
-1860
File diff suppressed because it is too large
Load Diff
+627
@@ -0,0 +1,627 @@
|
||||
---
|
||||
layout: base.njk
|
||||
title: 为酒行与酒店设计的库存管理平台
|
||||
description: 岩美酒库管理系统,审核驱动业务流,库存与账款自动同步,五端无缝接入。
|
||||
---
|
||||
<style>
|
||||
/* HERO --------------------------------------------------------- */
|
||||
.hero {
|
||||
position: relative; overflow: hidden; padding: 88px 0 64px;
|
||||
background:
|
||||
radial-gradient(900px 480px at 78% 12%, rgba(37,99,172,0.06), transparent 60%),
|
||||
linear-gradient(180deg,#FBFCFD 0%,#FFFFFF 80%);
|
||||
}
|
||||
.hero-inner { display: grid; grid-template-columns: 1.05fr 1.25fr; gap: 64px; align-items: center; }
|
||||
.hero h1 { font-size: 52px; line-height: 1.12; letter-spacing: var(--tracking-cn-display); color: var(--brand-900); font-weight: 700; margin: 0 0 20px; }
|
||||
.hero h1 em { font-style: normal; color: var(--brand-500); position: relative; }
|
||||
.hero h1 em::after { content: ''; position: absolute; left: 0; right: 0; bottom: 4px; height: 10px; background: var(--brand-100); z-index: -1; border-radius: 2px; }
|
||||
.hero p.lead { font-size: var(--text-xl); line-height: 1.6; color: var(--gray-600); margin: 0 0 32px; }
|
||||
.hero-mini-item .icon { width: 14px; height: 14px; color: var(--success-500); }
|
||||
|
||||
/* Preview mock UI ---------------------------------------------- */
|
||||
.preview-shell { background: var(--gray-0); border: 1px solid var(--border-default); border-radius: 14px; box-shadow: var(--shadow-xl); overflow: hidden; }
|
||||
.preview-titlebar { height: 36px; display: flex; align-items: center; padding: 0 14px; background: var(--gray-50); border-bottom: 1px solid var(--border-subtle); gap: 8px; }
|
||||
.preview-dots { display: flex; gap: 6px; }
|
||||
.preview-dots span { width: 10px; height: 10px; border-radius: 50%; background: var(--gray-300); }
|
||||
.preview-url { flex: 1; text-align: center; font-size: var(--text-xs); color: var(--fg-subtle); font-family: var(--font-mono); }
|
||||
.mock-app { display: grid; grid-template-columns: 180px 1fr; height: 540px; }
|
||||
.mock-sidebar { background: var(--brand-900); color: #DCE2EB; padding: 20px 12px; font-size: var(--text-sm); }
|
||||
.mock-sidebar-brand { font-size: 13px; font-weight: 600; letter-spacing: 0.1em; color: #fff; padding: 0 8px 16px; border-bottom: 1px solid rgba(255,255,255,0.08); margin-bottom: 12px; }
|
||||
.mock-nav-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--radius-sm); margin-bottom: 2px; color: #ADC9EA; font-size: 13px; }
|
||||
.mock-nav-item .icon { width: 16px; height: 16px; }
|
||||
.mock-nav-item.active { background: rgba(255,255,255,0.08); color: #fff; }
|
||||
.mock-main { background: var(--gray-50); padding: 20px; overflow: hidden; }
|
||||
.mock-topbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; }
|
||||
.mock-tabs { display: flex; gap: 4px; background: var(--gray-0); padding: 4px; border-radius: var(--radius-md); border: 1px solid var(--border-default); }
|
||||
.mock-tab { padding: 6px 14px; font-size: 13px; color: var(--gray-600); border-radius: var(--radius-sm); }
|
||||
.mock-tab.active { background: var(--brand-500); color: #fff; font-weight: 500; }
|
||||
.mock-actions { display: flex; gap: 8px; }
|
||||
.mock-mini-btn { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 12px; background: var(--gray-0); border: 1px solid var(--border-default); border-radius: var(--radius-sm); font-size: 12px; color: var(--gray-700); }
|
||||
.mock-mini-btn .icon { width: 13px; height: 13px; }
|
||||
.mock-mini-btn.primary { background: var(--brand-500); color: #fff; border-color: var(--brand-500); }
|
||||
.mock-stats { display: grid; grid-template-columns: repeat(4,1fr); gap: 10px; margin-bottom: 16px; }
|
||||
.mock-stat { background: var(--gray-0); border: 1px solid var(--border-default); border-radius: var(--radius-md); padding: 12px 14px; }
|
||||
.mock-stat-label { font-size: 11px; color: var(--fg-muted); margin-bottom: 4px; }
|
||||
.mock-stat-value { font-size: 20px; font-weight: 600; color: var(--brand-900); font-variant-numeric: tabular-nums; }
|
||||
.mock-stat-delta { font-size: 11px; margin-top: 2px; font-variant-numeric: tabular-nums; }
|
||||
.mock-stat-delta.up { color: var(--success-500); }
|
||||
.mock-stat-delta.down { color: var(--danger-500); }
|
||||
.mock-table-card { background: var(--gray-0); border: 1px solid var(--border-default); border-radius: var(--radius-md); overflow: hidden; }
|
||||
.mock-table-head { display: grid; grid-template-columns: 110px 1fr 60px 70px 80px 70px; padding: 10px 14px; background: var(--gray-50); border-bottom: 1px solid var(--border-subtle); font-size: 11px; color: var(--fg-muted); font-weight: 500; }
|
||||
.mock-table-row { display: grid; grid-template-columns: 110px 1fr 60px 70px 80px 70px; padding: 10px 14px; border-bottom: 1px solid var(--border-subtle); font-size: 12px; color: var(--gray-800); align-items: center; font-variant-numeric: tabular-nums; }
|
||||
.mock-table-row:last-child { border-bottom: none; }
|
||||
.mock-table-row .sku { font-family: var(--font-mono); color: var(--brand-500); font-size: 11px; }
|
||||
.mock-pill { display: inline-block; padding: 1px 8px; border-radius: var(--radius-pill); font-size: 10px; font-weight: 500; }
|
||||
.mock-pill.ok { background: var(--success-50); color: var(--success-700); }
|
||||
.mock-pill.warn { background: var(--warning-50); color: var(--warning-700); }
|
||||
.mock-pill.pending { background: var(--info-50); color: var(--info-700); }
|
||||
.hero-toast { position: absolute; bottom: -28px; right: -36px; background: var(--gray-0); border: 1px solid var(--border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: 14px 16px; width: 260px; display: flex; gap: 12px; align-items: flex-start; z-index: 2; }
|
||||
.hero-toast-icon { width: 36px; height: 36px; border-radius: 8px; background: var(--success-50); display: grid; place-items: center; flex-shrink: 0; }
|
||||
.hero-toast-icon .icon { color: var(--success-500); }
|
||||
|
||||
/* Trust strip -------------------------------------------------- */
|
||||
.trust { border-top: 1px solid var(--border-subtle); border-bottom: 1px solid var(--border-subtle); background: var(--gray-25); padding: 32px 0; }
|
||||
.trust-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr; align-items: center; gap: 32px; }
|
||||
.trust-stat-num { font-size: 28px; font-weight: 600; color: var(--brand-900); font-variant-numeric: tabular-nums; line-height: 1; }
|
||||
.trust-stat-num sup { font-size: 14px; color: var(--brand-500); margin-left: 2px; font-weight: 500; }
|
||||
|
||||
/* Modules ------------------------------------------------------ */
|
||||
.module-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
|
||||
.module-card.feature-card { grid-column: span 2; background: linear-gradient(180deg,#FBFCFD 0%,#FFFFFF 100%); }
|
||||
.module-card.feature-card .icon-box-lg { background: var(--brand-500); color: #fff; }
|
||||
.module-card ul { margin: 16px 0 0; padding: 0; list-style: none; font-size: var(--text-sm); color: var(--gray-700); }
|
||||
.module-card ul li { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-top: 1px solid var(--border-subtle); }
|
||||
.module-card ul li:first-child { border-top: none; }
|
||||
.module-card ul li .icon { width: 14px; height: 14px; color: var(--brand-500); }
|
||||
|
||||
/* Workflow ----------------------------------------------------- */
|
||||
.workflow-grid { display: grid; grid-template-columns: 1fr 1.1fr; gap: 64px; align-items: center; margin-top: 48px; }
|
||||
.wf-step { display: grid; grid-template-columns: 32px 1fr; gap: 14px; align-items: start; }
|
||||
.wf-num { width: 32px; height: 32px; border-radius: var(--radius-pill); background: var(--brand-50); color: var(--brand-700); display: grid; place-items: center; font-size: 13px; font-weight: 600; }
|
||||
.wf-step.active .wf-num { background: var(--brand-500); color: #fff; }
|
||||
.flow-vis { background: var(--gray-0); border: 1px solid var(--border-default); border-radius: var(--radius-lg); box-shadow: var(--shadow-md); padding: 28px; }
|
||||
.flow-doc { background: var(--gray-50); border: 1px solid var(--border-default); border-radius: var(--radius-md); padding: 16px 18px; margin-bottom: 14px; }
|
||||
.flow-doc-head { display: flex; justify-content: space-between; margin-bottom: 12px; }
|
||||
.flow-doc-id { font-family: var(--font-mono); font-size: 12px; color: var(--brand-500); }
|
||||
.flow-doc-status { font-size: 11px; font-weight: 500; padding: 2px 10px; border-radius: var(--radius-pill); background: var(--info-50); color: var(--info-700); }
|
||||
.flow-doc-status.approved { background: var(--success-50); color: var(--success-700); }
|
||||
.flow-row { display: grid; grid-template-columns: 70px 1fr 70px 70px; gap: 8px; font-size: 12px; padding: 6px 0; color: var(--gray-700); font-variant-numeric: tabular-nums; }
|
||||
.flow-row.head { font-weight: 500; color: var(--fg-muted); font-size: 11px; padding: 0 0 6px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 4px; }
|
||||
.flow-row.foot { border-top: 1px solid var(--border-default); margin-top: 6px; padding-top: 8px; font-weight: 600; color: var(--brand-900); }
|
||||
.flow-arrow { display: flex; align-items: center; justify-content: center; padding: 12px 0; color: var(--gray-400); }
|
||||
.flow-arrow .icon { width: 18px; height: 18px; }
|
||||
.flow-effects { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
|
||||
.flow-effect { background: #fff; border: 1px solid var(--border-default); border-radius: var(--radius-md); padding: 12px 14px; }
|
||||
.flow-effect-label { font-size: 11px; color: var(--fg-muted); display: flex; align-items: center; gap: 6px; }
|
||||
.flow-effect-label .icon { width: 12px; height: 12px; color: var(--success-500); }
|
||||
.flow-effect-val { font-size: 18px; font-weight: 600; color: var(--brand-900); margin-top: 4px; font-variant-numeric: tabular-nums; }
|
||||
|
||||
/* Platforms ---------------------------------------------------- */
|
||||
.platform-card:hover { border-color: var(--brand-300); }
|
||||
.platforms-visual { margin-top: 56px; background: var(--brand-900); border-radius: var(--radius-xl); padding: 56px 48px; position: relative; overflow: hidden; color: #fff; display: grid; grid-template-columns: 1fr 1.2fr; gap: 48px; align-items: center; }
|
||||
.platforms-visual::before { content: ''; position: absolute; inset: 0; background: radial-gradient(600px 320px at 80% 10%,rgba(79,134,198,0.20),transparent 60%); pointer-events: none; }
|
||||
.pv-text h3 { font-size: 32px; font-weight: 600; letter-spacing: var(--tracking-cn-display); margin: 0 0 16px; }
|
||||
.pv-text p { font-size: var(--text-lg); color: #ADC9EA; margin: 0 0 24px; line-height: 1.6; }
|
||||
.pv-feature { display: flex; align-items: center; gap: 10px; font-size: var(--text-md); color: #DCE2EB; }
|
||||
.pv-feature .icon { width: 16px; height: 16px; color: var(--brand-300); }
|
||||
.device-stack { position: relative; height: 320px; z-index: 1; }
|
||||
.device-laptop { position: absolute; width: 100%; bottom: 0; background: #0A1F3B; border: 1px solid rgba(255,255,255,0.08); border-radius: 8px 8px 4px 4px; box-shadow: var(--shadow-xl); }
|
||||
.device-laptop::after { content: ''; position: absolute; bottom: -10px; left: -16px; right: -16px; height: 10px; background: linear-gradient(180deg,#232934 0%,#141821 100%); border-radius: 0 0 8px 8px; }
|
||||
.device-laptop-screen { background: var(--gray-50); margin: 8px; height: 200px; border-radius: 4px; padding: 10px; overflow: hidden; }
|
||||
.device-laptop-mock-row { height: 12px; background: var(--gray-200); border-radius: 2px; margin-bottom: 6px; }
|
||||
.device-laptop-mock-row.short { width: 60%; }
|
||||
.device-laptop-mock-row.brand { background: var(--brand-300); width: 30%; }
|
||||
.device-phone { position: absolute; right: 32px; bottom: -8px; width: 110px; height: 220px; background: #0A1F3B; border: 2px solid rgba(255,255,255,0.10); border-radius: 16px; padding: 4px; box-shadow: var(--shadow-xl); z-index: 2; }
|
||||
.device-phone-screen { background: var(--gray-50); border-radius: 12px; height: 100%; padding: 8px; overflow: hidden; font-size: 8px; }
|
||||
.device-phone-screen .top { height: 14px; background: var(--brand-500); border-radius: 4px; margin-bottom: 6px; }
|
||||
|
||||
/* Reports ------------------------------------------------------ */
|
||||
.reports-grid { display: grid; grid-template-columns: 1.05fr 1fr; gap: 64px; align-items: center; margin-top: 48px; }
|
||||
.report-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 18px; }
|
||||
.report-tabs { display: flex; gap: 4px; }
|
||||
.report-tab { padding: 4px 10px; font-size: 11px; color: var(--fg-muted); border-radius: var(--radius-sm); cursor: pointer; }
|
||||
.report-tab.active { background: var(--gray-100); color: var(--gray-900); }
|
||||
.chart { position: relative; height: 200px; margin: 8px 0 0; }
|
||||
.chart svg { width: 100%; height: 100%; }
|
||||
.chart-stats { display: grid; grid-template-columns: repeat(3,1fr); gap: 12px; border-top: 1px solid var(--border-subtle); padding-top: 18px; margin-top: 8px; }
|
||||
.chart-stat-val small { font-size: var(--text-xs); color: var(--success-500); margin-left: 4px; font-weight: 500; }
|
||||
|
||||
/* Security ----------------------------------------------------- */
|
||||
.roles-table { margin-top: 32px; background: var(--gray-0); border: 1px solid var(--border-default); border-radius: var(--radius-lg); overflow: hidden; }
|
||||
.roles-row { display: grid; grid-template-columns: 180px 1fr 80px 80px 80px 80px; align-items: center; padding: 14px 24px; border-bottom: 1px solid var(--border-subtle); font-size: var(--text-sm); }
|
||||
.roles-row:last-child { border-bottom: none; }
|
||||
.roles-row.head { background: var(--gray-50); color: var(--fg-muted); font-size: 12px; font-weight: 500; }
|
||||
.role-check { text-align: center; }
|
||||
.role-check .icon { width: 16px; height: 16px; color: var(--success-500); display: inline-block; }
|
||||
.role-check.no .icon { color: var(--gray-300); }
|
||||
|
||||
/* Pricing ------------------------------------------------------ */
|
||||
.price-card.featured { border-color: var(--brand-500); box-shadow: 0 0 0 4px rgba(37,99,172,0.08), var(--shadow-md); position: relative; }
|
||||
.price-card.featured::before { content: '推荐'; position: absolute; top: -1px; right: 24px; background: var(--brand-500); color: #fff; padding: 4px 12px; border-radius: 0 0 var(--radius-sm) var(--radius-sm); font-size: 11px; font-weight: 500; letter-spacing: 0.06em; }
|
||||
.price-amount { display: flex; align-items: baseline; gap: 4px; margin-bottom: 8px; }
|
||||
.price-amount .currency { font-size: 18px; color: var(--gray-700); font-weight: 500; }
|
||||
.price-amount .num { font-size: 42px; font-weight: 700; color: var(--brand-900); font-variant-numeric: tabular-nums; line-height: 1; }
|
||||
.price-amount .unit { font-size: 14px; color: var(--fg-muted); margin-left: 4px; }
|
||||
.price-card.custom .num { font-size: 32px; }
|
||||
|
||||
/* FAQ ---------------------------------------------------------- */
|
||||
.faq-q { display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; cursor: pointer; font-size: var(--text-lg); font-weight: 500; color: var(--brand-900); list-style: none; }
|
||||
.faq-q::-webkit-details-marker { display: none; }
|
||||
.faq-q .icon { width: 18px; height: 18px; color: var(--fg-muted); transition: transform var(--duration-base) var(--ease-standard); }
|
||||
details[open] .faq-q .icon { transform: rotate(45deg); }
|
||||
|
||||
/* CTA banner --------------------------------------------------- */
|
||||
.cta-banner {
|
||||
background: radial-gradient(800px 360px at 80% 30%,rgba(37,99,172,0.40),transparent 60%), linear-gradient(135deg,#0A1F3B 0%,#15407D 100%);
|
||||
color: #fff; border-radius: var(--radius-xl); padding: 64px 56px;
|
||||
display: grid; grid-template-columns: 1.4fr 1fr; gap: 48px; align-items: center; margin: 96px 0;
|
||||
}
|
||||
.cta-banner h2 { font-size: 36px; font-weight: 600; letter-spacing: var(--tracking-cn-display); margin: 0 0 16px; line-height: 1.25; }
|
||||
.cta-banner p { font-size: var(--text-lg); color: #ADC9EA; margin: 0; line-height: 1.6; }
|
||||
.cta-banner .btn-primary { background: #fff; color: var(--brand-700); }
|
||||
.cta-banner .btn-primary:hover { background: #DCE2EB; }
|
||||
.cta-banner .btn-secondary { background: transparent; color: #fff; border-color: rgba(255,255,255,0.30); }
|
||||
.cta-banner .btn-secondary:hover { background: rgba(255,255,255,0.10); }
|
||||
|
||||
/* Responsive --------------------------------------------------- */
|
||||
@media (max-width: 1024px) {
|
||||
.hero-inner, .workflow-grid, .reports-grid, .platforms-visual, .cta-banner { grid-template-columns: 1fr; }
|
||||
.module-card.feature-card { grid-column: span 2; }
|
||||
.hero h1 { font-size: 40px; }
|
||||
.roles-row { grid-template-columns: 140px 1fr repeat(4, 60px); padding: 12px 16px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- ====================== HERO ====================== -->
|
||||
<section class="hero">
|
||||
<div class="container hero-inner">
|
||||
<div>
|
||||
<div class="d-inline-flex items-center gap-8 bg-0 border rounded-pill fs-sm text-gray-7 mb-24" style="padding: 6px 14px 6px 8px;">
|
||||
<span class="badge badge-brand">v1.6</span>
|
||||
<span>新增多仓库联动盘点 ·</span>
|
||||
<span class="text-brand fw-5">查看更新</span>
|
||||
</div>
|
||||
<h1>从入库到出库,<br/><em>一套系统</em>管到底。</h1>
|
||||
<p class="lead">岩美酒库管理系统,为酒行与酒店设计的库存、审核、财务一体化平台。审核驱动业务流,库存与账款自动同步,五端无缝接入。</p>
|
||||
<div class="d-flex gap-12 mb-28">
|
||||
<a href="/app/" class="btn btn-primary btn-lg">免费试用 30 天<i data-lucide="arrow-right" class="icon"></i></a>
|
||||
<a href="/app/" class="btn btn-secondary btn-lg"><i data-lucide="play-circle" class="icon"></i>观看演示</a>
|
||||
</div>
|
||||
<div class="d-flex items-center gap-18 text-muted fs-sm">
|
||||
<div class="hero-mini-item d-flex items-center gap-6"><i data-lucide="check" class="icon"></i>无需安装</div>
|
||||
<div class="hero-mini-item d-flex items-center gap-6"><i data-lucide="check" class="icon"></i>30 天免费</div>
|
||||
<div class="hero-mini-item d-flex items-center gap-6"><i data-lucide="check" class="icon"></i>支持私有部署</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pos-relative">
|
||||
<div class="preview-shell">
|
||||
<div class="preview-titlebar">
|
||||
<div class="preview-dots"><span></span><span></span><span></span></div>
|
||||
<div class="preview-url">yanmei.app/inventory</div>
|
||||
</div>
|
||||
<div class="mock-app">
|
||||
<aside class="mock-sidebar">
|
||||
<div class="mock-sidebar-brand">金樽酒行 · S001</div>
|
||||
<div class="mock-nav-item"><i data-lucide="package-plus" class="icon"></i>入库管理</div>
|
||||
<div class="mock-nav-item"><i data-lucide="package-minus" class="icon"></i>出库管理</div>
|
||||
<div class="mock-nav-item active"><i data-lucide="package" class="icon"></i>库存管理</div>
|
||||
<div class="mock-nav-item"><i data-lucide="wallet" class="icon"></i>财务管理</div>
|
||||
<div class="mock-nav-item"><i data-lucide="truck" class="icon"></i>往来单位</div>
|
||||
<div class="mock-nav-item"><i data-lucide="database" class="icon"></i>基础数据</div>
|
||||
<div class="mock-nav-item"><i data-lucide="settings" class="icon"></i>系统设置</div>
|
||||
</aside>
|
||||
<main class="mock-main">
|
||||
<div class="mock-topbar">
|
||||
<div class="mock-tabs">
|
||||
<div class="mock-tab active">库存列表</div>
|
||||
<div class="mock-tab">库存盘点</div>
|
||||
<div class="mock-tab">库存流水</div>
|
||||
</div>
|
||||
<div class="mock-actions">
|
||||
<div class="mock-mini-btn"><i data-lucide="download" class="icon"></i>导出</div>
|
||||
<div class="mock-mini-btn primary"><i data-lucide="clipboard-list" class="icon"></i>新建盘点</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mock-stats">
|
||||
<div class="mock-stat">
|
||||
<div class="mock-stat-label">库存总量</div>
|
||||
<div class="mock-stat-value">2,816 <span style="font-size:12px;color:var(--fg-muted);font-weight:400">瓶</span></div>
|
||||
<div class="mock-stat-delta up">↑ 4.2% 较上月</div>
|
||||
</div>
|
||||
<div class="mock-stat">
|
||||
<div class="mock-stat-label">库存金额</div>
|
||||
<div class="mock-stat-value">¥486,290</div>
|
||||
<div class="mock-stat-delta up">↑ 2.8% 较上月</div>
|
||||
</div>
|
||||
<div class="mock-stat">
|
||||
<div class="mock-stat-label">本月入库</div>
|
||||
<div class="mock-stat-value">128 <span style="font-size:12px;color:var(--fg-muted);font-weight:400">单</span></div>
|
||||
<div class="mock-stat-delta up">↑ 12 单</div>
|
||||
</div>
|
||||
<div class="mock-stat">
|
||||
<div class="mock-stat-label">预警 SKU</div>
|
||||
<div class="mock-stat-value" style="color:var(--warning-500)">7</div>
|
||||
<div class="mock-stat-delta down">↓ 库存不足</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mock-table-card">
|
||||
<div class="mock-table-head">
|
||||
<div>SKU</div><div>商品名称</div><div>仓库</div><div>库存</div><div>金额</div><div>状态</div>
|
||||
</div>
|
||||
<div class="mock-table-row"><div class="sku">WT-501-006</div><div>茅台飞天 53° · 500ml×6</div><div>A 仓</div><div>148</div><div>¥298,400</div><div><span class="mock-pill ok">充足</span></div></div>
|
||||
<div class="mock-table-row"><div class="sku">XJ-468-001</div><div>五粮液第八代 52° · 500ml</div><div>A 仓</div><div>92</div><div>¥92,920</div><div><span class="mock-pill ok">充足</span></div></div>
|
||||
<div class="mock-table-row"><div class="sku">XJ-330-024</div><div>剑南春水晶剑 52° · 500ml×6</div><div>B 仓</div><div style="color:var(--warning-700);font-weight:500">12</div><div>¥4,560</div><div><span class="mock-pill warn">偏低</span></div></div>
|
||||
<div class="mock-table-row"><div class="sku">PJ-750-012</div><div>拉菲传奇波尔多 · 750ml</div><div>A 仓</div><div>64</div><div>¥18,560</div><div><span class="mock-pill ok">充足</span></div></div>
|
||||
<div class="mock-table-row"><div class="sku">PJ-700-008</div><div>轩尼诗 VSOP · 700ml</div><div>B 仓</div><div>38</div><div>¥22,420</div><div><span class="mock-pill pending">入库中</span></div></div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-toast">
|
||||
<div class="hero-toast-icon"><i data-lucide="check-circle-2" class="icon"></i></div>
|
||||
<div>
|
||||
<div class="fw-6 fs-sm text-gray-9 mb-2">入库单已审批</div>
|
||||
<div class="fs-sm text-muted" style="line-height:1.45">RK20260523000007 库存 +24 瓶<br/>生成应付 ¥48,400</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== TRUST ====================== -->
|
||||
<section class="trust">
|
||||
<div class="container">
|
||||
<div class="trust-grid">
|
||||
<div class="fs-sm text-muted">服务各类酒水经营场所</div>
|
||||
<div><div class="trust-stat-num">1,280<sup>+</sup></div><div class="fs-xs text-muted mt-4">酒行 / 酒店门店</div></div>
|
||||
<div><div class="trust-stat-num">8.4<sup>%</sup></div><div class="fs-xs text-muted mt-4">平均损耗下降</div></div>
|
||||
<div><div class="trust-stat-num">99.9<sup>%</sup></div><div class="fs-xs text-muted mt-4">系统可用性</div></div>
|
||||
<div><div class="trust-stat-num">5<sup>端</sup></div><div class="fs-xs text-muted mt-4">Web / iOS / Android / Win / Mac</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== MODULES ====================== -->
|
||||
<section class="section" id="modules">
|
||||
<div class="container">
|
||||
<p class="eyebrow">核心模块</p>
|
||||
<h2 class="section-title">七大模块,覆盖酒水经营全流程</h2>
|
||||
<p class="section-sub">从商品建档到入库出库、从财务结算到数据导入,岩美一站式承载日常运营。</p>
|
||||
<div class="grid-3 gap-16 mt-48">
|
||||
<div class="module-card feature-card card p-24 transition">
|
||||
<div class="icon-box-lg bg-brand-50 text-brand mb-16"><i data-lucide="package-plus" class="icon-md"></i></div>
|
||||
<h3 class="fs-xl fw-6 text-brand-900 m-0 mb-6 ls-1">入库管理</h3>
|
||||
<p class="fs-sm lh-16 text-muted m-0">审核驱动的入库流程。草稿、提交、审批、库存更新、应付账款生成 — 一气呵成。</p>
|
||||
<ul>
|
||||
<li><i data-lucide="check" class="icon"></i>多商品行明细录入,自动算金额</li>
|
||||
<li><i data-lucide="check" class="icon"></i>审批通过即同步库存与应付账款</li>
|
||||
<li><i data-lucide="check" class="icon"></i>支持单据打印、商品标签打印</li>
|
||||
<li><i data-lucide="check" class="icon"></i>批次号追踪,生产日期可追溯</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="module-card card p-24 transition">
|
||||
<div class="icon-box-lg bg-brand-50 text-brand mb-16"><i data-lucide="package-minus" class="icon-md"></i></div>
|
||||
<h3 class="fs-xl fw-6 text-brand-900 m-0 mb-6 ls-1">出库管理</h3>
|
||||
<p class="fs-sm lh-16 text-muted m-0">出库前自动校验库存,审批通过即扣减库存并生成应收。库存不足,单据无法通过。</p>
|
||||
</div>
|
||||
<div class="module-card card p-24 transition">
|
||||
<div class="icon-box-lg bg-brand-50 text-brand mb-16"><i data-lucide="package" class="icon-md"></i></div>
|
||||
<h3 class="fs-xl fw-6 text-brand-900 m-0 mb-6 ls-1">库存管理</h3>
|
||||
<p class="fs-sm lh-16 text-muted m-0">实时查询每个 SKU 的库存数量、所在仓库、批次。支持全仓盘点与库存流水。</p>
|
||||
</div>
|
||||
<div class="module-card card p-24 transition">
|
||||
<div class="icon-box-lg bg-brand-50 text-brand mb-16"><i data-lucide="wallet" class="icon-md"></i></div>
|
||||
<h3 class="fs-xl fw-6 text-brand-900 m-0 mb-6 ls-1">财务管理</h3>
|
||||
<p class="fs-sm lh-16 text-muted m-0">审批同步生成应付应收,月度汇总。结清一键完成,可按往来单位筛选导出。</p>
|
||||
</div>
|
||||
<div class="module-card card p-24 transition">
|
||||
<div class="icon-box-lg bg-brand-50 text-brand mb-16"><i data-lucide="truck" class="icon-md"></i></div>
|
||||
<h3 class="fs-xl fw-6 text-brand-900 m-0 mb-6 ls-1">往来单位</h3>
|
||||
<p class="fs-sm lh-16 text-muted m-0">供应商与客户统一档案管理。卡号、初始余额、联系信息集中维护。</p>
|
||||
</div>
|
||||
<div class="module-card card p-24 transition">
|
||||
<div class="icon-box-lg bg-brand-50 text-brand mb-16"><i data-lucide="database" class="icon-md"></i></div>
|
||||
<h3 class="fs-xl fw-6 text-brand-900 m-0 mb-6 ls-1">基础数据</h3>
|
||||
<p class="fs-sm lh-16 text-muted m-0">商品名称、系列、规格三级字典,单品数量配置。先建字典,后录单据。</p>
|
||||
</div>
|
||||
<div class="module-card card p-24 transition">
|
||||
<div class="icon-box-lg bg-brand-50 text-brand mb-16"><i data-lucide="settings" class="icon-md"></i></div>
|
||||
<h3 class="fs-xl fw-6 text-brand-900 m-0 mb-6 ls-1">系统设置</h3>
|
||||
<p class="fs-sm lh-16 text-muted m-0">用户与权限、多仓库、编号规则、参数与数据导入 — 自助配置,无需开发。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== WORKFLOW ====================== -->
|
||||
<section class="section bg-25" id="workflow">
|
||||
<div class="container">
|
||||
<p class="eyebrow">业务流程</p>
|
||||
<h2 class="section-title">审核驱动业务流,每一笔交易都可追溯</h2>
|
||||
<p class="section-sub">从单据录入到库存变动、账款生成,每一步都有清晰状态与经办人记录。</p>
|
||||
<div class="workflow-grid">
|
||||
<div>
|
||||
<h3 class="fs-2xl fw-6 text-brand-900 m-0 mb-12">一张入库单的完整生命周期</h3>
|
||||
<div class="d-flex flex-col gap-14 mt-24">
|
||||
<div class="wf-step"><div class="wf-num">1</div><div><h4 class="mt-4 mb-4 fs-md fw-6 text-gray-9">录入草稿</h4><p class="m-0 fs-sm text-muted lh-15">选择仓库、供应商、入库日期,逐行录入商品明细。系统自动算金额,可随时保存草稿。</p></div></div>
|
||||
<div class="wf-step"><div class="wf-num">2</div><div><h4 class="mt-4 mb-4 fs-md fw-6 text-gray-9">提交审核</h4><p class="m-0 fs-sm text-muted lh-15">确认无误后提交。单据进入「待审核」,此时不可再编辑,保证数据完整。</p></div></div>
|
||||
<div class="wf-step active"><div class="wf-num">3</div><div><h4 class="mt-4 mb-4 fs-md fw-6 text-gray-9">审批通过</h4><p class="m-0 fs-sm text-muted lh-15">操作员及以上权限审批。通过后库存自动 +N,同时生成一笔应付账款,账款挂在对应供应商名下。</p></div></div>
|
||||
<div class="wf-step"><div class="wf-num">4</div><div><h4 class="mt-4 mb-4 fs-md fw-6 text-gray-9">结清账款</h4><p class="m-0 fs-sm text-muted lh-15">财务结算时一键「结清」,财务记录由「未结清」变为「已结清」。账目清晰,按月汇总。</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-vis">
|
||||
<div class="flow-doc">
|
||||
<div class="flow-doc-head">
|
||||
<div class="flow-doc-id">RK20260523000007</div>
|
||||
<div class="flow-doc-status approved">已审批</div>
|
||||
</div>
|
||||
<div class="flow-row head"><div>商品</div><div>规格</div><div>数量</div><div>金额</div></div>
|
||||
<div class="flow-row"><div>茅台飞天</div><div>500ml×6</div><div>4</div><div>¥8,000</div></div>
|
||||
<div class="flow-row"><div>五粮液</div><div>500ml</div><div>20</div><div>¥18,400</div></div>
|
||||
<div class="flow-row"><div>剑南春</div><div>500ml×6</div><div>2</div><div>¥4,200</div></div>
|
||||
<div class="flow-row"><div>拉菲传奇</div><div>750ml</div><div>10</div><div>¥17,800</div></div>
|
||||
<div class="flow-row foot"><div>合计</div><div></div><div>36</div><div>¥48,400</div></div>
|
||||
</div>
|
||||
<div class="flow-arrow"><i data-lucide="arrow-down" class="icon"></i></div>
|
||||
<div class="flow-effects">
|
||||
<div class="flow-effect"><div class="flow-effect-label"><i data-lucide="check-circle-2" class="icon"></i>库存更新</div><div class="flow-effect-val">+36 瓶</div></div>
|
||||
<div class="flow-effect"><div class="flow-effect-label"><i data-lucide="check-circle-2" class="icon"></i>应付账款</div><div class="flow-effect-val">¥48,400</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== PLATFORMS ====================== -->
|
||||
<section class="section" id="platforms">
|
||||
<div class="container">
|
||||
<p class="eyebrow">多端覆盖</p>
|
||||
<h2 class="section-title">一个账号,五端同步</h2>
|
||||
<p class="section-sub">办公室开台账,仓库扫码盘点,老板出差查看实时报表。同一份数据,任意终端访问。</p>
|
||||
<div class="grid-5 gap-12 mt-48">
|
||||
<div class="platform-card card py-24 px-16 text-center transition"><i data-lucide="globe" class="icon-xl text-brand mx-auto mb-12"></i><h4 class="m-0 mb-4 fs-md fw-6 text-brand-900">Web</h4><p class="m-0 fs-xs text-muted">主流浏览器,无需安装</p></div>
|
||||
<div class="platform-card card py-24 px-16 text-center transition"><i data-lucide="monitor" class="icon-xl text-brand mx-auto mb-12"></i><h4 class="m-0 mb-4 fs-md fw-6 text-brand-900">Windows</h4><p class="m-0 fs-xs text-muted">桌面客户端</p></div>
|
||||
<div class="platform-card card py-24 px-16 text-center transition"><i data-lucide="laptop" class="icon-xl text-brand mx-auto mb-12"></i><h4 class="m-0 mb-4 fs-md fw-6 text-brand-900">macOS</h4><p class="m-0 fs-xs text-muted">原生应用</p></div>
|
||||
<div class="platform-card card py-24 px-16 text-center transition"><i data-lucide="smartphone" class="icon-xl text-brand mx-auto mb-12"></i><h4 class="m-0 mb-4 fs-md fw-6 text-brand-900">iOS</h4><p class="m-0 fs-xs text-muted">iPhone / iPad</p></div>
|
||||
<div class="platform-card card py-24 px-16 text-center transition"><i data-lucide="tablet-smartphone" class="icon-xl text-brand mx-auto mb-12"></i><h4 class="m-0 mb-4 fs-md fw-6 text-brand-900">Android</h4><p class="m-0 fs-xs text-muted">手机 / 平板</p></div>
|
||||
</div>
|
||||
<div class="platforms-visual">
|
||||
<div class="pv-text">
|
||||
<h3>仓库里也能用得顺手</h3>
|
||||
<p>移动端扫码即查库存、入库、出库,断网也能继续工作,恢复网络后自动同步。</p>
|
||||
<div class="d-flex flex-col gap-10">
|
||||
<div class="pv-feature"><i data-lucide="scan-line" class="icon"></i>扫码即查商品 · 二维码标签</div>
|
||||
<div class="pv-feature"><i data-lucide="wifi-off" class="icon"></i>离线缓存,断网继续作业</div>
|
||||
<div class="pv-feature"><i data-lucide="bell" class="icon"></i>实时推送审批与库存预警</div>
|
||||
<div class="pv-feature"><i data-lucide="printer" class="icon"></i>蓝牙连接打印商品标签</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="device-stack">
|
||||
<div class="device-laptop">
|
||||
<div class="device-laptop-screen">
|
||||
<div class="device-laptop-mock-row brand"></div>
|
||||
<div class="device-laptop-mock-row short"></div>
|
||||
<div class="device-laptop-mock-row"></div>
|
||||
<div class="device-laptop-mock-row short"></div>
|
||||
<div class="device-laptop-mock-row"></div>
|
||||
<div class="device-laptop-mock-row short"></div>
|
||||
<div class="device-laptop-mock-row"></div>
|
||||
<div class="device-laptop-mock-row short"></div>
|
||||
<div class="d-flex gap-6 mt-10">
|
||||
<div style="flex:1;height:50px;background:var(--gray-100);border-radius:3px"></div>
|
||||
<div style="flex:1;height:50px;background:var(--brand-100);border-radius:3px"></div>
|
||||
<div style="flex:1;height:50px;background:var(--gray-100);border-radius:3px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="device-phone">
|
||||
<div class="device-phone-screen">
|
||||
<div class="top"></div>
|
||||
<div style="height:8px;background:var(--gray-200);border-radius:2px;margin-bottom:4px;width:70%"></div>
|
||||
<div style="height:8px;background:var(--gray-200);border-radius:2px;margin-bottom:8px;width:50%"></div>
|
||||
<div style="background:var(--gray-0);border:1px solid var(--gray-200);border-radius:4px;padding:6px;margin-bottom:4px"><div style="height:6px;background:var(--brand-300);border-radius:1px;width:60%;margin-bottom:3px"></div><div style="height:4px;background:var(--gray-200);border-radius:1px;width:80%"></div></div>
|
||||
<div style="background:var(--gray-0);border:1px solid var(--gray-200);border-radius:4px;padding:6px;margin-bottom:4px"><div style="height:6px;background:var(--brand-300);border-radius:1px;width:50%;margin-bottom:3px"></div><div style="height:4px;background:var(--gray-200);border-radius:1px;width:70%"></div></div>
|
||||
<div style="background:var(--gray-0);border:1px solid var(--gray-200);border-radius:4px;padding:6px;margin-bottom:4px"><div style="height:6px;background:var(--brand-300);border-radius:1px;width:55%;margin-bottom:3px"></div><div style="height:4px;background:var(--gray-200);border-radius:1px;width:75%"></div></div>
|
||||
<div style="position:absolute;bottom:8px;left:8px;right:8px;background:var(--brand-500);height:22px;border-radius:4px;display:grid;place-items:center"><div style="height:6px;background:rgba(255,255,255,0.9);border-radius:1px;width:50%"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== REPORTS ====================== -->
|
||||
<section class="section bg-25" id="reports">
|
||||
<div class="container">
|
||||
<p class="eyebrow">数据洞察</p>
|
||||
<h2 class="section-title">把每一瓶酒的进出,转成可分析的数据</h2>
|
||||
<p class="section-sub">报表自动生成,可按日、按月、按往来单位维度切换。导出 Excel 一键完成。</p>
|
||||
<div class="reports-grid">
|
||||
<div class="card p-24 shadow-sm">
|
||||
<div class="report-head">
|
||||
<div><h4 class="fs-md fw-6 text-gray-9 m-0">本月财务流水</h4><p class="fs-xs text-muted mt-2 m-0">2026 年 5 月 · 应付与应收对比</p></div>
|
||||
<div class="report-tabs">
|
||||
<div class="report-tab">日</div>
|
||||
<div class="report-tab active">月</div>
|
||||
<div class="report-tab">季</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart">
|
||||
<svg viewBox="0 0 600 200" preserveAspectRatio="none">
|
||||
<line x1="0" y1="50" x2="600" y2="50" stroke="#ECEFF4" stroke-width="1"/>
|
||||
<line x1="0" y1="100" x2="600" y2="100" stroke="#ECEFF4" stroke-width="1"/>
|
||||
<line x1="0" y1="150" x2="600" y2="150" stroke="#ECEFF4" stroke-width="1"/>
|
||||
<path d="M 20 140 L 80 110 L 140 130 L 200 90 L 260 100 L 320 70 L 380 85 L 440 50 L 500 65 L 560 40 L 560 190 L 20 190 Z" fill="rgba(37,99,172,0.10)" />
|
||||
<path d="M 20 140 L 80 110 L 140 130 L 200 90 L 260 100 L 320 70 L 380 85 L 440 50 L 500 65 L 560 40" fill="none" stroke="#2563AC" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 20 160 L 80 140 L 140 145 L 200 120 L 260 130 L 320 105 L 380 115 L 440 90 L 500 95 L 560 70 L 560 190 L 20 190 Z" fill="rgba(139,35,49,0.08)" />
|
||||
<path d="M 20 160 L 80 140 L 140 145 L 200 120 L 260 130 L 320 105 L 380 115 L 440 90 L 500 95 L 560 70" fill="none" stroke="#8B2331" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="560" cy="40" r="4" fill="#2563AC" />
|
||||
<circle cx="560" cy="40" r="8" fill="rgba(37,99,172,0.20)" />
|
||||
<circle cx="560" cy="70" r="4" fill="#8B2331" />
|
||||
</svg>
|
||||
<div class="d-flex gap-16 fs-xs text-muted mt-8">
|
||||
<span class="d-flex items-center gap-4"><span style="width:8px;height:8px;background:var(--brand-500);border-radius:50%"></span>应付账款</span>
|
||||
<span class="d-flex items-center gap-4"><span style="width:8px;height:8px;background:var(--accent-500);border-radius:50%"></span>应收账款</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-stats">
|
||||
<div><div class="fs-xs text-muted mb-4">本月应付</div><div class="fs-lg fw-6 text-brand-900 tabular">¥248,600<small>↑ 12%</small></div></div>
|
||||
<div><div class="fs-xs text-muted mb-4">本月应收</div><div class="fs-lg fw-6 text-brand-900 tabular">¥182,400<small>↑ 8%</small></div></div>
|
||||
<div><div class="fs-xs text-muted mb-4">已结清率</div><div class="fs-lg fw-6 text-brand-900 tabular">86.4%<small>↑ 4%</small></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-col gap-24">
|
||||
<div class="d-grid gap-16" style="grid-template-columns:36px 1fr">
|
||||
<div class="icon-box-md bg-brand-50 text-brand"><i data-lucide="bar-chart-3" class="icon-md"></i></div>
|
||||
<div><h4 class="m-0 mb-4 fs-lg fw-6 text-brand-900">财务汇总自动生成</h4><p class="m-0 fs-sm text-muted lh-16">每月应付应收按往来单位、按时间维度自动汇总。无需手工统计,月底一键导出。</p></div>
|
||||
</div>
|
||||
<div class="d-grid gap-16" style="grid-template-columns:36px 1fr">
|
||||
<div class="icon-box-md bg-brand-50 text-brand"><i data-lucide="trending-down" class="icon-md"></i></div>
|
||||
<div><h4 class="m-0 mb-4 fs-lg fw-6 text-brand-900">损耗趋势可见</h4><p class="m-0 fs-sm text-muted lh-16">每次盘点的账实差异自动累计为损耗数据,结合周转率帮你发现异常 SKU。</p></div>
|
||||
</div>
|
||||
<div class="d-grid gap-16" style="grid-template-columns:36px 1fr">
|
||||
<div class="icon-box-md bg-brand-50 text-brand"><i data-lucide="file-spreadsheet" class="icon-md"></i></div>
|
||||
<div><h4 class="m-0 mb-4 fs-lg fw-6 text-brand-900">Excel 进出自由</h4><p class="m-0 fs-sm text-muted lh-16">历史数据可批量导入,月度报表可一键导出。与会计、税务系统无缝衔接。</p></div>
|
||||
</div>
|
||||
<div class="d-grid gap-16" style="grid-template-columns:36px 1fr">
|
||||
<div class="icon-box-md bg-brand-50 text-brand"><i data-lucide="alert-triangle" class="icon-md"></i></div>
|
||||
<div><h4 class="m-0 mb-4 fs-lg fw-6 text-brand-900">库存预警实时提醒</h4><p class="m-0 fs-sm text-muted lh-16">SKU 库存低于阈值,系统在 Web 与移动端同步推送。永远不会错过补货时机。</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== SECURITY ====================== -->
|
||||
<section class="section bg-25">
|
||||
<div class="container">
|
||||
<p class="eyebrow">安全与权限</p>
|
||||
<h2 class="section-title">企业级权限控制,操作可追溯</h2>
|
||||
<p class="section-sub">四级角色细分权限,每一次单据操作都有经办人记录。数据备份与审批留痕,按合规要求设计。</p>
|
||||
<div class="grid-4 gap-16 mt-48">
|
||||
<div class="card p-24"><i data-lucide="users" class="icon-lg text-brand mb-14"></i><h4 class="fs-lg fw-6 text-brand-900 m-0 mb-6">四级角色</h4><p class="m-0 fs-sm text-muted lh-15">超级管理员、管理员、操作员、只读。按岗位分配,最小权限原则。</p></div>
|
||||
<div class="card p-24"><i data-lucide="file-clock" class="icon-lg text-brand mb-14"></i><h4 class="fs-lg fw-6 text-brand-900 m-0 mb-6">操作审计</h4><p class="m-0 fs-sm text-muted lh-15">谁、什么时候、做了什么 — 每一笔单据都有经办人与时间戳。</p></div>
|
||||
<div class="card p-24"><i data-lucide="shield-check" class="icon-lg text-brand mb-14"></i><h4 class="fs-lg fw-6 text-brand-900 m-0 mb-6">审批留痕</h4><p class="m-0 fs-sm text-muted lh-15">审批不可撤销,单据从草稿到结清的每一步状态完整保留。</p></div>
|
||||
<div class="card p-24"><i data-lucide="hard-drive" class="icon-lg text-brand mb-14"></i><h4 class="fs-lg fw-6 text-brand-900 m-0 mb-6">每日备份</h4><p class="m-0 fs-sm text-muted lh-15">云端每日自动备份,支持私有部署。数据始终在你的控制下。</p></div>
|
||||
</div>
|
||||
<div class="roles-table">
|
||||
<div class="roles-row head">
|
||||
<div>角色</div><div>说明</div>
|
||||
<div class="text-center">查看</div><div class="text-center">录入</div>
|
||||
<div class="text-center">审批</div><div class="text-center">设置</div>
|
||||
</div>
|
||||
<div class="roles-row"><div class="fw-6 text-brand-900">超级管理员</div><div class="text-muted fs-sm">系统最高权限,含数据清空</div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check"><i data-lucide="check" class="icon"></i></div></div>
|
||||
<div class="roles-row"><div class="fw-6 text-brand-900">管理员</div><div class="text-muted fs-sm">门店管理人员,含用户与门店设置</div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check"><i data-lucide="check" class="icon"></i></div></div>
|
||||
<div class="roles-row"><div class="fw-6 text-brand-900">操作员</div><div class="text-muted fs-sm">日常录入与审核单据</div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check no"><i data-lucide="minus" class="icon"></i></div></div>
|
||||
<div class="roles-row"><div class="fw-6 text-brand-900">只读</div><div class="text-muted fs-sm">仅查看,不可修改任何数据</div><div class="role-check"><i data-lucide="check" class="icon"></i></div><div class="role-check no"><i data-lucide="minus" class="icon"></i></div><div class="role-check no"><i data-lucide="minus" class="icon"></i></div><div class="role-check no"><i data-lucide="minus" class="icon"></i></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== PRICING ====================== -->
|
||||
<section class="section" id="pricing">
|
||||
<div class="container">
|
||||
<p class="eyebrow">价格</p>
|
||||
<h2 class="section-title">按门店付费,明码标价</h2>
|
||||
<p class="section-sub">所有方案均含全功能、五端同步、无限单据、技术支持。仅在用户数、门店数、部署方式上区分。</p>
|
||||
<div class="grid-3 gap-16 mt-48">
|
||||
<div class="card d-flex flex-col" style="padding:32px 28px">
|
||||
<div class="fs-sm text-muted fw-5 mb-4">入门方案</div>
|
||||
<div class="fs-2xl fw-6 text-brand-900 mb-16">试用版</div>
|
||||
<div class="price-amount"><span class="currency">¥</span><span class="num">0</span><span class="unit">/ 30 天</span></div>
|
||||
<div class="fs-sm text-muted mb-24">体验完整功能,无需绑卡</div>
|
||||
<ul class="price-features d-flex flex-col gap-10 p-0 m-0 mb-32" style="list-style:none">
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>单门店 · 最多 3 用户</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>全部模块开放</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>Web 端 + 移动端</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>邮件技术支持</li>
|
||||
</ul>
|
||||
<a href="/app/" class="btn btn-secondary w-full justify-center mt-auto">免费开通</a>
|
||||
</div>
|
||||
<div class="price-card featured card d-flex flex-col" style="padding:32px 28px">
|
||||
<div class="fs-sm text-muted fw-5 mb-4">标准方案</div>
|
||||
<div class="fs-2xl fw-6 text-brand-900 mb-16">单店版</div>
|
||||
<div class="price-amount"><span class="currency">¥</span><span class="num">299</span><span class="unit">/ 月</span></div>
|
||||
<div class="fs-sm text-muted mb-24">年付折扣 ¥2,988 / 年(约省 ¥600)</div>
|
||||
<ul class="price-features d-flex flex-col gap-10 p-0 m-0 mb-32" style="list-style:none">
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>单门店 · 最多 10 用户</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>全部模块 + 五端同步</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>无限单据、无限商品</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>云端每日备份</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>工作日 9-18 点支持</li>
|
||||
</ul>
|
||||
<a href="/app/" class="btn btn-primary w-full justify-center mt-auto">购买</a>
|
||||
</div>
|
||||
<div class="price-card custom card d-flex flex-col" style="padding:32px 28px">
|
||||
<div class="fs-sm text-muted fw-5 mb-4">企业方案</div>
|
||||
<div class="fs-2xl fw-6 text-brand-900 mb-16">连锁版</div>
|
||||
<div class="price-amount"><span class="num">定制</span></div>
|
||||
<div class="fs-sm text-muted mb-24">多门店连锁,含私有部署</div>
|
||||
<ul class="price-features d-flex flex-col gap-10 p-0 m-0 mb-32" style="list-style:none">
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>多门店 · 总部数据汇总</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>不限用户数</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>支持私有部署 / 内网</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>SSO 单点登录</li>
|
||||
<li class="d-flex items-start gap-8 fs-sm text-gray-7"><i data-lucide="check" class="icon-sm text-brand flex-shrink-0 mt-2"></i>7×24 专属客户经理</li>
|
||||
</ul>
|
||||
<a href="/app/" class="btn btn-secondary w-full justify-center mt-auto">联系销售</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== FAQ ====================== -->
|
||||
<section class="section bg-25" id="faq">
|
||||
<div class="container">
|
||||
<p class="eyebrow">常见问题</p>
|
||||
<h2 class="section-title">购买前常见的问题</h2>
|
||||
<div class="mt-48" style="max-width:880px">
|
||||
<details class="card mb-12 overflow-hidden" open>
|
||||
<summary class="faq-q">支持哪些操作系统和设备?<i data-lucide="plus" class="icon"></i></summary>
|
||||
<div class="fs-md text-muted lh-17" style="padding:0 24px 22px">系统支持 Windows、macOS 桌面客户端,iOS 与 Android 移动 App,以及主流浏览器的 Web 版本。同一账号可在五端同步使用,数据实时更新。</div>
|
||||
</details>
|
||||
<details class="card mb-12 overflow-hidden">
|
||||
<summary class="faq-q">没有网络时还能操作吗?<i data-lucide="plus" class="icon"></i></summary>
|
||||
<div class="fs-md text-muted lh-17" style="padding:0 24px 22px">网络中断时,系统会自动切换到离线模式,展示上次加载的缓存数据。库存查询与单据录入可继续,恢复网络后自动同步至云端。审批与生成账款类操作需要网络。</div>
|
||||
</details>
|
||||
<details class="card mb-12 overflow-hidden">
|
||||
<summary class="faq-q">能否从原有 Excel / 旧系统迁移数据?<i data-lucide="plus" class="icon"></i></summary>
|
||||
<div class="fs-md text-muted lh-17" style="padding:0 24px 22px">可以。「系统设置 → 数据导入」支持往来单位、商品名称/系列/规格、库存等数据的批量 Excel 导入,按提供的模板填写即可。导入过程中会显示成功条数与失败原因。</div>
|
||||
</details>
|
||||
<details class="card mb-12 overflow-hidden">
|
||||
<summary class="faq-q">审批通过后发现错误,怎么办?<i data-lucide="plus" class="icon"></i></summary>
|
||||
<div class="fs-md text-muted lh-17" style="padding:0 24px 22px">审批通过后操作不可撤销。如发现错误,可由具备权限的用户新建反向调整单据(红冲入库 / 红冲出库)来修正库存与账款。这样可以保留完整的审计链。</div>
|
||||
</details>
|
||||
<details class="card mb-12 overflow-hidden">
|
||||
<summary class="faq-q">数据安全如何保障?<i data-lucide="plus" class="icon"></i></summary>
|
||||
<div class="fs-md text-muted lh-17" style="padding:0 24px 22px">云端版采用每日自动备份策略,数据传输全程 HTTPS 加密。企业版支持私有部署,数据存放在你自己的服务器,岩美不接触任何业务数据。</div>
|
||||
</details>
|
||||
<details class="card mb-12 overflow-hidden">
|
||||
<summary class="faq-q">可以试用多长时间?<i data-lucide="plus" class="icon"></i></summary>
|
||||
<div class="fs-md text-muted lh-17" style="padding:0 24px 22px">标准版提供 30 天免费试用,无需绑定支付方式。试用期可使用全部功能、五端访问。30 天后可继续按月或按年付费,已录入的数据完整保留。</div>
|
||||
</details>
|
||||
<details class="card mb-12 overflow-hidden">
|
||||
<summary class="faq-q">只读账号能做什么?<i data-lucide="plus" class="icon"></i></summary>
|
||||
<div class="fs-md text-muted lh-17" style="padding:0 24px 22px">只读账号可查看全部数据,包括单据、库存、财务、报表,并可导出 Excel。但不能新建、修改、审批、删除任何数据。适合财务、税务、审计岗位的查阅需求。</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== CTA ====================== -->
|
||||
<section>
|
||||
<div class="container">
|
||||
<div class="cta-banner">
|
||||
<div>
|
||||
<h2>用一杯咖啡的时间,<br/>看看你的酒库到底有多少瓶。</h2>
|
||||
<p>30 天免费试用,无需绑卡。任何时间可取消,已录入数据保留 90 天。</p>
|
||||
</div>
|
||||
<div class="d-flex flex-col gap-12 items-start">
|
||||
<a href="/app/" class="btn btn-primary btn-lg">立即开通试用<i data-lucide="arrow-right" class="icon"></i></a>
|
||||
<a href="/app/" class="btn btn-secondary btn-lg"><i data-lucide="phone" class="icon"></i>预约 1 对 1 演示</a>
|
||||
<span class="fs-sm" style="color:#99A3B3">销售热线 {{ site.support.phone }} · 工作日 9:00-18:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
Generated
+1671
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "jiu-marketing",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "eleventy",
|
||||
"dev": "eleventy --serve --port=3000"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "^3.0.0",
|
||||
"markdown-it": "^14.2.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user