feat(site): 官网全新重建(App 真相源风格)+ 四档套餐 + 在线购买流
- tokens.css/site.css 逐值对齐原型设计系统,icons 雪碧图,零外链;首页/下载/帮助/法务全站重皮肤,真实截图 - 注册与登录在官网内完成(写 shared_preferences_web 兼容 localStorage,不再跳 App) - 价格区四档:免费/标准 299/高级 599/定制;登录后标准/高级按钮变「购买 / 续费」 - 新增 /checkout/(套餐+月付年付切换)与 /license/result/(支付回跳轮询到账) - 登录页支持 ?next= 站内回跳;二维码措辞改「扫码看详情可分享」 - 下载页构建期真实下载链接+运行时 release 刷新;旧 features 页/死 CSS/dist 产物清理 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
@@ -2,8 +2,6 @@ module.exports = function(cfg) {
|
||||
// 静态资源直接复制
|
||||
cfg.addPassthroughCopy("assets");
|
||||
|
||||
// scan.html 面向消费者,独立维护,直接复制不经模板
|
||||
cfg.addPassthroughCopy("scan.html");
|
||||
// features/ 已改为 .njk 模板,不再需要 passthrough
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
scan.html
|
||||
content/
|
||||
features/approval.html
|
||||
features/inventory.html
|
||||
|
||||
@@ -3,9 +3,9 @@ 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] },
|
||||
{ group: '快速开始', nums: [1, 2] },
|
||||
{ group: '业务操作', nums: [3, 4, 5, 6, 7, 8] },
|
||||
{ group: '设置与答疑', nums: [9, 10] },
|
||||
];
|
||||
|
||||
module.exports = function() {
|
||||
|
||||
@@ -6,17 +6,16 @@
|
||||
<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" />
|
||||
{# 真相源:tokens.css = App 原型 tokens.css 主题A 拷贝;site.css 镜像 atoms.css。
|
||||
全站零外链(无 Google Fonts / unpkg):字体走系统栈(与 App 真机一致),图标走内联雪碧图。 #}
|
||||
<link rel="stylesheet" href="/assets/tokens.css" />
|
||||
<link rel="stylesheet" href="/assets/site.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>
|
||||
<link rel="icon" href="/assets/logo-mark.svg" type="image/svg+xml" />
|
||||
{% if pageStyle %}<style>{{ pageStyle | safe }}</style>{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{% include "icons.njk" %}
|
||||
{% include "nav.njk" %}
|
||||
|
||||
{{ content | safe }}
|
||||
|
||||
@@ -1,49 +1,41 @@
|
||||
<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">
|
||||
{% if site.support.wechat %}<div>客服微信:{{ site.support.wechat }}</div>{% endif %}
|
||||
<div><a href="mailto:{{ site.support.email }}">{{ site.support.email }}</a></div>
|
||||
{% if site.support.phone %}<div>{{ site.support.phone }}</div>{% endif %}
|
||||
</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="/download/">版本更新</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h5>资源</h5>
|
||||
<ul>
|
||||
<li><a href="/docs/">使用手册</a></li>
|
||||
<li><a href="/download/">下载客户端</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h5>客户支持</h5>
|
||||
<ul>
|
||||
<li><a href="/#faq">常见问题</a></li>
|
||||
<li><a href="mailto:{{ site.support.email }}">联系我们</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h5>公司</h5>
|
||||
<ul>
|
||||
<li><a href="/register/">注册门店</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<div class="footer-grid">
|
||||
<div>
|
||||
<div class="fbrand"><img src="/assets/logo-mark.svg" alt="岩美" />岩美酒库</div>
|
||||
<p class="fdesc">为酒行与酒店设计的库存、审核、财务一体化管理平台。每一瓶酒一个编号,每一笔交易可追溯。</p>
|
||||
<p class="fdesc" style="margin-top:10px">
|
||||
{% if site.support.wechat %}客服微信:{{ site.support.wechat }}<br/>{% endif %}
|
||||
<a href="mailto:{{ site.support.email }}">{{ site.support.email }}</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<div>{{ site.copyright }}</div>
|
||||
{% if site.icp %}<div>{{ site.icp }}</div>{% endif %}
|
||||
<div>
|
||||
<h4>产品</h4>
|
||||
<ul>
|
||||
<li><a href="/#modules">核心模块</a></li>
|
||||
<li><a href="/#workflow">审核驱动业务流</a></li>
|
||||
<li><a href="/#pricing">价格方案</a></li>
|
||||
<li><a href="/download/">下载客户端</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>支持</h4>
|
||||
<ul>
|
||||
<li><a href="/docs/">使用手册</a></li>
|
||||
<li><a href="/#faq">常见问题</a></li>
|
||||
<li><a href="/system-requirements/">系统要求</a></li>
|
||||
<li><a href="/register/">注册门店</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4>法务</h4>
|
||||
<ul>
|
||||
<li><a href="/privacy/">隐私政策</a></li>
|
||||
<li><a href="/terms/">服务条款</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<div>{{ site.copyright }}</div>
|
||||
{% if site.icp %}<div><a href="https://beian.miit.gov.cn" rel="noopener" target="_blank">{{ site.icp }}</a></div>{% endif %}
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
<nav class="topnav">
|
||||
<div class="topnav-inner">
|
||||
<a href="/" class="topnav-brand">
|
||||
<img src="/assets/logo-full.svg" alt="岩美" />
|
||||
<nav class="nav">
|
||||
<div class="nav-in">
|
||||
<a class="nav-logo" href="/">
|
||||
<img src="/assets/logo-mark.svg" alt="{{ site.name }}" />
|
||||
岩美酒库
|
||||
</a>
|
||||
<div class="topnav-links">
|
||||
<div class="nav-links">
|
||||
<a href="/#modules">产品</a>
|
||||
<a href="/features/inventory.html">库存</a>
|
||||
<a href="/features/approval.html">审核流</a>
|
||||
<a href="/#workflow">审核流</a>
|
||||
<a href="/#pricing">价格</a>
|
||||
<a href="/download/">下载</a>
|
||||
<a href="/docs/">文档</a>
|
||||
<a href="/#faq">支持</a>
|
||||
<a href="/docs/">帮助</a>
|
||||
</div>
|
||||
<div class="topnav-cta" id="nav-cta">
|
||||
<a href="/register/" class="btn btn-primary btn-sm">注册门店</a>
|
||||
<div class="nav-cta" id="nav-cta">
|
||||
<a class="btn ghost" href="/login/">登录</a>
|
||||
<a class="btn primary" href="/register/">注册门店</a>
|
||||
</div>
|
||||
<button class="nav-hamburger" id="nav-hamburger" aria-label="菜单" aria-expanded="false">
|
||||
<span></span><span></span><span></span>
|
||||
<button class="nav-burger" id="nav-burger" aria-label="菜单" aria-expanded="false">
|
||||
<svg class="ic" style="width:22px;height:22px"><use href="#i-menu"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="nav-mobile-menu" id="nav-mobile-menu">
|
||||
<div class="nav-mobile" id="nav-mobile-menu">
|
||||
<a href="/#modules">产品</a>
|
||||
<a href="/features/inventory.html">库存管理</a>
|
||||
<a href="/features/approval.html">审核流</a>
|
||||
<a href="/#workflow">审核流</a>
|
||||
<a href="/#pricing">价格</a>
|
||||
<a href="/download/">下载</a>
|
||||
<a href="/docs/">文档</a>
|
||||
<a href="/#faq">支持</a>
|
||||
<div class="nav-mobile-cta" id="nav-mobile-cta">
|
||||
<a href="/register/" class="btn btn-primary">注册门店</a>
|
||||
</div>
|
||||
<a href="/docs/">帮助</a>
|
||||
<a href="/register/">注册门店</a>
|
||||
<a href="/login/">登录</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -1,134 +1,42 @@
|
||||
(function() {
|
||||
var KEYS = ['access_token','refresh_token','username','real_name','shop_no','shop_id','role'];
|
||||
|
||||
/* 官网导航交互:汉堡菜单 + 登录态感知(Web 版 App 与官网同域时,
|
||||
localStorage['flutter.*'] 有登录信息 → CTA 变「进入系统」)。零依赖。 */
|
||||
(function () {
|
||||
function getAuthUser() {
|
||||
var token = localStorage.getItem('flutter.access_token');
|
||||
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') || '',
|
||||
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');
|
||||
}
|
||||
|
||||
function toggleMobileMenu() {
|
||||
var menu = document.getElementById('nav-mobile-menu');
|
||||
var btn = document.getElementById('nav-hamburger');
|
||||
if (!menu) return;
|
||||
var isOpen = menu.classList.toggle('open');
|
||||
if (btn) btn.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
||||
}
|
||||
|
||||
// 点击外部关闭 dropdown 和 mobile menu
|
||||
document.addEventListener('click', function(e) {
|
||||
var userMenu = document.getElementById('userDropdown');
|
||||
if (userMenu) {
|
||||
var navUser = userMenu.closest('.nav-user');
|
||||
if (navUser && !navUser.contains(e.target)) userMenu.classList.remove('open');
|
||||
}
|
||||
var mobileMenu = document.getElementById('nav-mobile-menu');
|
||||
var hamburger = document.getElementById('nav-hamburger');
|
||||
if (mobileMenu && hamburger) {
|
||||
var topnav = mobileMenu.closest('nav');
|
||||
if (topnav && !topnav.contains(e.target)) {
|
||||
mobileMenu.classList.remove('open');
|
||||
hamburger.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function renderNav() {
|
||||
var cta = document.getElementById('nav-cta');
|
||||
var mobileCta = document.getElementById('nav-mobile-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>';
|
||||
if (mobileCta) {
|
||||
mobileCta.innerHTML =
|
||||
'<a href="/app/" class="btn btn-ghost">进入管理端</a>'
|
||||
+ '<button class="btn btn-ghost" onclick="doLogout()">退出登录</button>';
|
||||
}
|
||||
} else {
|
||||
cta.innerHTML =
|
||||
'<a href="/app/" class="btn btn-ghost">登录</a>'
|
||||
+ '<a href="/app/" class="btn btn-primary">免费试用</a>';
|
||||
if (mobileCta) {
|
||||
mobileCta.innerHTML =
|
||||
'<a href="/app/" class="btn btn-ghost">登录</a>'
|
||||
+ '<a href="/register/" class="btn btn-primary">注册门店</a>';
|
||||
}
|
||||
}
|
||||
if (window.lucide) lucide.createIcons();
|
||||
}
|
||||
|
||||
// 暴露给 onclick 调用
|
||||
window.toggleUserMenu = toggleUserMenu;
|
||||
window.toggleMobileMenu = toggleMobileMenu;
|
||||
window.doLogout = doLogout;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
renderNav();
|
||||
if (window.lucide) lucide.createIcons();
|
||||
|
||||
var hamburger = document.getElementById('nav-hamburger');
|
||||
if (hamburger) hamburger.addEventListener('click', toggleMobileMenu);
|
||||
|
||||
// 点击 mobile menu 链接后自动收起
|
||||
var mobileMenu = document.getElementById('nav-mobile-menu');
|
||||
if (mobileMenu) {
|
||||
mobileMenu.querySelectorAll('a').forEach(function(a) {
|
||||
a.addEventListener('click', function() {
|
||||
mobileMenu.classList.remove('open');
|
||||
if (hamburger) hamburger.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 页内锚点平滑滚动
|
||||
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' });
|
||||
}
|
||||
});
|
||||
// 汉堡菜单
|
||||
var burger = document.getElementById('nav-burger');
|
||||
var mobile = document.getElementById('nav-mobile-menu');
|
||||
if (burger && mobile) {
|
||||
burger.addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
var open = mobile.classList.toggle('open');
|
||||
burger.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||
});
|
||||
});
|
||||
document.addEventListener('click', function (e) {
|
||||
if (!mobile.contains(e.target) && e.target !== burger) {
|
||||
mobile.classList.remove('open');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 登录态:CTA 换成「进入系统」
|
||||
var user = getAuthUser();
|
||||
if (user) {
|
||||
var cta = document.getElementById('nav-cta');
|
||||
if (cta) {
|
||||
cta.innerHTML =
|
||||
'<a class="btn primary" href="/app/">进入系统 · ' +
|
||||
(user.realName || user.username).replace(/[<>&"]/g, '') +
|
||||
'</a>';
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 270 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 241 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 203 KiB |
|
After Width: | Height: | Size: 199 KiB |
@@ -0,0 +1,298 @@
|
||||
/* ============================================================
|
||||
岩美酒库官网 · 组件与版式层
|
||||
原子样式一对一镜像 .superpowers/prototype/atoms.css(.btn/.card/.badge/.kpi/.chip),
|
||||
营销版式(nav/hero/section/footer)用同一批 token 组合。
|
||||
============================================================ */
|
||||
|
||||
*{box-sizing:border-box;}
|
||||
html{scroll-behavior:smooth;}
|
||||
body{margin:0; font-family:var(--font); color:var(--text); background:var(--bg); font-size:var(--mk-body); line-height:1.7; -webkit-font-smoothing:antialiased;}
|
||||
img{max-width:100%; display:block;}
|
||||
a{color:var(--primary); text-decoration:none;}
|
||||
a:hover{text-decoration:underline;}
|
||||
h1,h2,h3{color:var(--heading); line-height:1.3; margin:0;}
|
||||
.container{max-width:var(--mk-maxw); margin:0 auto; padding:0 24px;}
|
||||
.ic{width:18px; height:18px; stroke:currentColor; stroke-width:1.8; fill:none; stroke-linecap:round; stroke-linejoin:round; flex:none;}
|
||||
|
||||
/* ---------- 原子:按钮(镜像 atoms .btn / .primary / .ghost / .lg / .sm) ---------- */
|
||||
.btn{height:38px; padding:0 16px; border-radius:var(--r-md); font-size:var(--fs-body); font-weight:600; display:inline-flex; align-items:center; justify-content:center; gap:7px; cursor:pointer; border:1px solid transparent; transition:background-color .15s,border-color .15s,color .15s; font-family:var(--font); text-decoration:none !important;}
|
||||
.btn .ic{width:16px; height:16px;}
|
||||
.btn.ghost{background:var(--surface); border-color:var(--border); color:var(--text);}
|
||||
.btn.ghost:hover{background:var(--bg);}
|
||||
.btn.primary{background:var(--primary); color:var(--on-primary);}
|
||||
.btn.primary:hover{background:var(--primary-dark);}
|
||||
.btn.lg{height:46px; padding:0 26px; font-size:15px; border-radius:var(--r-md);}
|
||||
.btn.sm{height:32px; padding:0 12px; font-size:var(--fs-sm);}
|
||||
.btn.onhero{background:var(--hero-glass-strong); color:var(--on-accent); border-color:transparent;}
|
||||
.btn.onhero:hover{background:var(--hero-glass);}
|
||||
.btn.wine{background:var(--accent); color:var(--on-accent);}
|
||||
.btn.wine:hover{background:var(--brand-wine);}
|
||||
|
||||
/* ---------- 原子:卡片 / 徽章 / chip(镜像 atoms) ---------- */
|
||||
.card{background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); padding:22px;}
|
||||
.badge{display:inline-flex; align-items:center; gap:5px; height:22px; padding:0 9px; border-radius:var(--r-pill); font-size:var(--fs-sm); font-weight:600;}
|
||||
.badge::before{content:''; width:6px; height:6px; border-radius:50%; background:currentColor;}
|
||||
.badge.ok{background:var(--success-bg); color:var(--success);}
|
||||
.badge.warn{background:var(--warn-bg); color:var(--warn);}
|
||||
.badge.info{background:var(--info-soft); color:var(--primary);}
|
||||
.badge.wine{background:var(--accent-soft); color:var(--accent);}
|
||||
.chip{display:inline-flex; align-items:center; gap:7px; height:34px; padding:0 12px; border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface); font-size:var(--fs-sm); color:var(--text);}
|
||||
|
||||
/* ---------- 原子:KPI 卡(镜像 .kpi + .ic 色块) ---------- */
|
||||
.kpi{background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); padding:15px 16px;}
|
||||
.kpi .khead{display:flex; align-items:flex-start; justify-content:space-between;}
|
||||
.kpi .t{font-size:var(--fs-sm); color:var(--muted); padding-top:2px;}
|
||||
.kpi .icbox{width:30px; height:30px; border-radius:var(--r-md); display:flex; align-items:center; justify-content:center;}
|
||||
.kpi .icbox .ic{width:17px; height:17px;}
|
||||
.kpi .v{font-size:24px; font-weight:700; color:var(--heading); margin-top:7px; letter-spacing:.3px; font-family:var(--font-mono);}
|
||||
.kpi .d{font-size:var(--fs-xs); color:var(--muted); margin-top:5px;}
|
||||
.ic-info{background:var(--info-soft); color:var(--primary);}
|
||||
.ic-ok{background:var(--ok-soft); color:var(--success);}
|
||||
.ic-warn{background:var(--warn-bg); color:var(--warn);}
|
||||
.ic-wine{background:var(--accent-soft); color:var(--accent);}
|
||||
|
||||
/* ---------- 顶部导航 ---------- */
|
||||
.nav{position:sticky; top:0; z-index:40; background:rgba(255,255,255,.92); backdrop-filter:blur(10px); border-bottom:1px solid var(--border);}
|
||||
.nav-in{max-width:var(--mk-maxw); margin:0 auto; padding:0 24px; height:60px; display:flex; align-items:center; gap:26px;}
|
||||
.nav-logo{display:flex; align-items:center; gap:10px; font-weight:800; font-size:17px; color:var(--heading); text-decoration:none !important; letter-spacing:.5px;}
|
||||
.nav-logo img{width:30px; height:30px; border-radius:7px;}
|
||||
.nav-links{display:flex; gap:22px; margin-left:6px;}
|
||||
.nav-links a{color:var(--muted); font-size:14px; font-weight:500; text-decoration:none !important;}
|
||||
.nav-links a:hover{color:var(--primary);}
|
||||
.nav-cta{margin-left:auto; display:flex; gap:10px; align-items:center;}
|
||||
.nav-burger{display:none; margin-left:auto; background:none; border:none; color:var(--heading); cursor:pointer; padding:6px;}
|
||||
.nav-mobile{display:none; border-top:1px solid var(--border); background:var(--surface); padding:10px 24px 16px;}
|
||||
.nav-mobile a{display:block; padding:10px 0; color:var(--text); font-size:15px; border-bottom:1px solid var(--border-subtle); text-decoration:none !important;}
|
||||
.nav-mobile.open{display:block;}
|
||||
|
||||
/* ---------- Hero(品牌渐变 = 登录页品牌面板同源) ---------- */
|
||||
.hero{background:var(--mk-hero-grad); color:var(--on-accent); padding:84px 0 0; overflow:hidden;}
|
||||
.hero-in{max-width:var(--mk-maxw); margin:0 auto; padding:0 24px; text-align:center;}
|
||||
.hero .badge-line{display:inline-flex; align-items:center; gap:8px; background:var(--hero-glass); border-radius:var(--r-pill); padding:6px 14px; font-size:var(--fs-sm); color:var(--on-accent-faint);}
|
||||
.hero .badge-line b{color:var(--on-accent); font-weight:600;}
|
||||
.hero h1{color:var(--on-accent); font-size:var(--mk-display); font-weight:800; letter-spacing:1px; margin:26px auto 18px; max-width:17em;}
|
||||
.hero .lead{color:var(--on-accent-faint); font-size:var(--mk-lead); max-width:36em; margin:0 auto 30px; line-height:1.8;}
|
||||
.hero .cta-row{display:flex; gap:14px; justify-content:center; flex-wrap:wrap;}
|
||||
.hero .mini{display:flex; gap:22px; justify-content:center; margin-top:22px; font-size:var(--fs-sm); color:var(--on-accent-faint); flex-wrap:wrap;}
|
||||
.hero .mini span{display:inline-flex; align-items:center; gap:6px;}
|
||||
.hero .shot{max-width:980px; margin:52px auto -2px; border-radius:var(--r-xl) var(--r-xl) 0 0; overflow:hidden; box-shadow:var(--sh-3); border:1px solid rgba(255,255,255,.18); border-bottom:none;}
|
||||
.hero .shot img{width:100%;}
|
||||
|
||||
/* ---------- 区块 ---------- */
|
||||
.section{padding:84px 0;}
|
||||
.section.alt{background:var(--page);}
|
||||
.sec-head{text-align:center; max-width:44em; margin:0 auto 46px;}
|
||||
.sec-head .eyebrow{display:inline-flex; align-items:center; gap:7px; color:var(--accent); font-size:var(--fs-sm); font-weight:700; letter-spacing:2px; margin-bottom:12px;}
|
||||
.sec-head .eyebrow::before,.sec-head .eyebrow::after{content:''; width:22px; height:1px; background:var(--accent); opacity:.5;}
|
||||
.sec-head h2{font-size:var(--mk-h2); font-weight:800;}
|
||||
.sec-head p{color:var(--muted); margin:14px 0 0;}
|
||||
|
||||
/* 模块卡网格 */
|
||||
.grid{display:grid; gap:16px;}
|
||||
.grid.c4{grid-template-columns:repeat(4,1fr);}
|
||||
.grid.c3{grid-template-columns:repeat(3,1fr);}
|
||||
.grid.c2{grid-template-columns:repeat(2,1fr);}
|
||||
.feature .icbox{width:38px; height:38px; border-radius:var(--r-md); display:flex; align-items:center; justify-content:center; margin-bottom:14px;}
|
||||
.feature .icbox .ic{width:20px; height:20px;}
|
||||
.feature h3{font-size:var(--mk-h3); font-weight:700; margin-bottom:8px;}
|
||||
.feature p{color:var(--muted); font-size:14px; margin:0; line-height:1.75;}
|
||||
|
||||
/* 截图对开区块 */
|
||||
.split{display:grid; grid-template-columns:1fr 1fr; gap:48px; align-items:center;}
|
||||
.split .shot{border-radius:var(--r-lg); overflow:hidden; border:1px solid var(--border); box-shadow:var(--sh-2);}
|
||||
.split h2{font-size:var(--mk-h2); font-weight:800; margin-bottom:16px;}
|
||||
.split .pts{display:flex; flex-direction:column; gap:14px; margin-top:22px;}
|
||||
.split .pt{display:flex; gap:12px; align-items:flex-start;}
|
||||
.split .pt .icbox{width:30px; height:30px; border-radius:var(--r-md); flex:none; display:flex; align-items:center; justify-content:center;}
|
||||
.split .pt .icbox .ic{width:16px;height:16px;}
|
||||
.split .pt b{display:block; color:var(--heading); font-size:15px;}
|
||||
.split .pt span{color:var(--muted); font-size:14px;}
|
||||
|
||||
/* 审核流状态机 */
|
||||
.flow{display:flex; align-items:stretch; gap:0; justify-content:center; flex-wrap:wrap;}
|
||||
.flow .step{background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); padding:18px 20px; width:200px; text-align:center;}
|
||||
.flow .arrow{align-self:center; color:var(--faint); padding:0 10px; font-size:20px;}
|
||||
.flow .step .num{width:28px; height:28px; border-radius:50%; background:var(--info-soft); color:var(--primary); font-weight:700; display:flex; align-items:center; justify-content:center; margin:0 auto 10px; font-size:var(--fs-body);}
|
||||
.flow .step b{display:block; color:var(--heading); font-size:15px; margin-bottom:5px;}
|
||||
.flow .step span{color:var(--muted); font-size:var(--fs-sm);}
|
||||
|
||||
/* 角色权限表 */
|
||||
table.roles{width:100%; border-collapse:collapse; background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); overflow:hidden; font-size:14px;}
|
||||
table.roles th{background:var(--th-bg); color:var(--muted); font-size:var(--fs-sm); font-weight:600; text-align:left; padding:11px 14px; border-bottom:1px solid var(--border);}
|
||||
table.roles td{padding:11px 14px; border-bottom:1px solid var(--border-subtle);}
|
||||
table.roles tr:last-child td{border-bottom:none;}
|
||||
table.roles .y{color:var(--success); font-weight:700;}
|
||||
table.roles .n{color:var(--faint);}
|
||||
|
||||
/* 定价卡 */
|
||||
.plans{display:grid; grid-template-columns:repeat(3,1fr); gap:18px; align-items:stretch;}
|
||||
.plans.p4{grid-template-columns:repeat(4,1fr); gap:16px;}
|
||||
.plans.p4 .plan{padding:26px 22px;}
|
||||
.plans.p4 .plan .price{font-size:30px;}
|
||||
.plan{background:var(--surface); border:1px solid var(--border); border-radius:var(--r-xl); padding:28px 26px; display:flex; flex-direction:column;}
|
||||
.plan.hot{border-color:var(--primary); box-shadow:var(--sh-2); position:relative;}
|
||||
.plan.hot::before{content:'推荐'; position:absolute; top:-11px; left:50%; transform:translateX(-50%); background:var(--primary); color:var(--on-primary); font-size:var(--fs-xs); font-weight:700; padding:3px 12px; border-radius:var(--r-pill);}
|
||||
.plan .pname{font-size:var(--fs-title); font-weight:700; color:var(--heading);}
|
||||
.plan .price{font-size:34px; font-weight:800; color:var(--heading); margin:12px 0 2px; font-family:var(--font-mono);}
|
||||
.plan .price small{font-size:14px; color:var(--muted); font-weight:400; font-family:var(--font);}
|
||||
.plan .psub{color:var(--muted); font-size:var(--fs-sm); margin-bottom:18px;}
|
||||
.plan ul{list-style:none; padding:0; margin:0 0 22px; display:flex; flex-direction:column; gap:9px; color:var(--text); font-size:14px;}
|
||||
.plan ul li{display:flex; gap:8px; align-items:flex-start;}
|
||||
.plan ul li .ic{width:15px; height:15px; color:var(--success); margin-top:4px;}
|
||||
.plan .btn{margin-top:auto;}
|
||||
|
||||
/* FAQ */
|
||||
.faq{max-width:760px; margin:0 auto; display:flex; flex-direction:column; gap:10px;}
|
||||
.faq details{background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); padding:0 20px;}
|
||||
.faq summary{cursor:pointer; font-weight:600; color:var(--heading); padding:16px 0; font-size:15px; list-style:none; display:flex; justify-content:space-between; align-items:center;}
|
||||
.faq summary::after{content:'+'; color:var(--faint); font-size:18px;}
|
||||
.faq details[open] summary::after{content:'−';}
|
||||
.faq details p{color:var(--muted); font-size:14px; margin:0 0 16px; line-height:1.8;}
|
||||
|
||||
/* CTA 横幅 */
|
||||
.cta-banner{background:var(--mk-hero-grad); border-radius:var(--r-xl); padding:56px 32px; text-align:center; color:var(--on-accent);}
|
||||
.cta-banner h2{color:var(--on-accent); font-size:var(--mk-h2); font-weight:800; margin-bottom:12px;}
|
||||
.cta-banner p{color:var(--on-accent-faint); margin:0 0 26px;}
|
||||
|
||||
/* ---------- 页脚 ---------- */
|
||||
.footer{background:var(--side-bg); color:var(--side-fg); padding:56px 0 30px; margin-top:84px;}
|
||||
.footer a{color:var(--side-fg); text-decoration:none !important;}
|
||||
.footer a:hover{color:#fff;}
|
||||
.footer-grid{display:grid; grid-template-columns:2fr 1fr 1fr 1fr; gap:32px; max-width:var(--mk-maxw); margin:0 auto; padding:0 24px;}
|
||||
.footer .fbrand{display:flex; align-items:center; gap:10px; color:#fff; font-weight:800; font-size:16px; margin-bottom:12px;}
|
||||
.footer .fbrand img{width:28px; height:28px; border-radius:6px;}
|
||||
.footer .fdesc{font-size:var(--fs-sm); line-height:1.8; max-width:26em;}
|
||||
.footer h4{color:#fff; font-size:var(--fs-body); font-weight:700; margin:0 0 14px;}
|
||||
.footer ul{list-style:none; padding:0; margin:0; display:flex; flex-direction:column; gap:9px; font-size:var(--fs-sm);}
|
||||
.footer-bottom{max-width:var(--mk-maxw); margin:40px auto 0; padding:22px 24px 0; border-top:1px solid rgba(255,255,255,.12); display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap; font-size:var(--fs-xs); color:var(--side-fg);}
|
||||
|
||||
/* ---------- 响应式 ---------- */
|
||||
@media (max-width:1024px){
|
||||
.grid.c4{grid-template-columns:repeat(2,1fr);}
|
||||
.plans,.plans.p4{grid-template-columns:repeat(2,1fr);}
|
||||
.split{grid-template-columns:1fr;}
|
||||
.footer-grid{grid-template-columns:1fr 1fr;}
|
||||
}
|
||||
@media (max-width:640px){
|
||||
.plans,.plans.p4{grid-template-columns:1fr; max-width:440px; margin:0 auto;}
|
||||
}
|
||||
@media (max-width:720px){
|
||||
.nav-links,.nav-cta .btn.ghost{display:none;}
|
||||
.nav-burger{display:block;}
|
||||
.grid.c4,.grid.c3,.grid.c2{grid-template-columns:1fr;}
|
||||
.section{padding:56px 0;}
|
||||
.hero{padding-top:56px;}
|
||||
.flow{flex-direction:column; align-items:center;}
|
||||
.flow .arrow{transform:rotate(90deg); padding:6px 0;}
|
||||
.flow .step{width:100%; max-width:320px;}
|
||||
}
|
||||
|
||||
/* 五端网格 */
|
||||
.grid.plat5{grid-template-columns:repeat(5,1fr);}
|
||||
@media (max-width:1024px){ .grid.plat5{grid-template-columns:repeat(3,1fr);} }
|
||||
@media (max-width:720px){ .grid.plat5{grid-template-columns:repeat(2,1fr);} }
|
||||
|
||||
/* ---------- Auth 两栏卡片(镜像 App login.html/register.html 版式) ---------- */
|
||||
.auth-wrap{min-height:calc(100vh - 60px); display:flex; align-items:center; justify-content:center; padding:40px 24px; background:var(--page);}
|
||||
.auth{display:grid; grid-template-columns:minmax(0,1fr) 420px; width:100%; max-width:880px; background:var(--surface); border:1px solid var(--border); border-radius:var(--r-xl); overflow:hidden; box-shadow:var(--sh-3);}
|
||||
.auth.reg{grid-template-columns:minmax(0,380px) minmax(0,1fr); max-width:940px;}
|
||||
.auth-brand{background:var(--mk-hero-grad); color:var(--side-active-fg); padding:48px 40px; display:flex; flex-direction:column; min-height:480px;}
|
||||
.auth-brand .mk{width:64px; height:64px; border-radius:15px;}
|
||||
.auth-brand .bname{font-size:var(--fs-display); font-weight:800; letter-spacing:1px; margin:24px 0 8px; color:var(--side-active-fg);}
|
||||
.auth-brand .btag{font-size:var(--fs-body); color:var(--side-fg); line-height:1.7; max-width:280px;}
|
||||
.auth-brand .pts{margin-top:auto; display:flex; flex-direction:column; gap:14px;}
|
||||
.auth-brand .pt{display:flex; align-items:center; gap:11px; font-size:var(--fs-sm); color:var(--side-fg);}
|
||||
.auth-brand .pt .pi{width:30px; height:30px; border-radius:var(--r-md); background:var(--hero-glass); display:flex; align-items:center; justify-content:center; flex:none; color:var(--side-active-fg);}
|
||||
.auth-brand .pt .ic{width:16px; height:16px;}
|
||||
.auth-brand .steps{margin-top:36px; display:flex; flex-direction:column;}
|
||||
.auth-brand .step{display:flex; gap:13px; position:relative; padding-bottom:22px;}
|
||||
.auth-brand .step:last-child{padding-bottom:0;}
|
||||
.auth-brand .step:not(:last-child)::before{content:''; position:absolute; left:14px; top:30px; bottom:0; width:2px; background:var(--hero-glass);}
|
||||
.auth-brand .step .si{width:29px; height:29px; border-radius:50%; background:var(--hero-glass); color:var(--side-active-fg); display:flex; align-items:center; justify-content:center; font-weight:700; font-size:var(--fs-body); flex:none; z-index:1;}
|
||||
.auth-brand .step.done .si{background:var(--side-active-fg); color:var(--side-active-bg);}
|
||||
.auth-brand .step .st{font-size:var(--fs-sm); line-height:1.45; color:var(--side-fg);}
|
||||
.auth-brand .step .st b{display:block; color:var(--side-active-fg); font-weight:600; font-size:var(--fs-body);}
|
||||
.auth-form{padding:44px 40px; display:flex; flex-direction:column; justify-content:center;}
|
||||
.auth-form h1{font-size:var(--fs-h1); color:var(--heading); font-weight:700; margin:0 0 6px;}
|
||||
.auth-form .alead{font-size:var(--fs-sm); color:var(--muted); margin:0 0 24px;}
|
||||
.field{margin-bottom:14px;}
|
||||
.field label{display:block; font-size:var(--fs-sm); color:var(--muted); margin-bottom:6px;}
|
||||
.field label .req{color:var(--danger); margin-left:2px;}
|
||||
.input{height:38px; width:100%; background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md); padding:0 11px; font-size:var(--fs-body); color:var(--text); outline:none; font-family:var(--font);}
|
||||
.input:focus{border-color:var(--primary); box-shadow:0 0 0 3px var(--brand50);}
|
||||
.input::placeholder{color:var(--faint);}
|
||||
textarea.input{height:auto; min-height:64px; padding:9px 11px; resize:vertical;}
|
||||
.grid2f{display:grid; grid-template-columns:1fr 1fr; gap:14px;}
|
||||
.field .hint{font-size:var(--fs-xs); color:var(--faint); margin-top:5px;}
|
||||
.field .ferr{font-size:var(--fs-xs); color:var(--danger); margin-top:5px; display:none;}
|
||||
.field.error .input{border-color:var(--danger);}
|
||||
.field.error .ferr{display:block;}
|
||||
.auth-form .btn.primary{width:100%; justify-content:center;}
|
||||
.auth-foot{margin-top:20px; text-align:center; font-size:var(--fs-sm); color:var(--muted);}
|
||||
.auth-alert{display:none; background:var(--danger-bg); border:1px solid var(--danger); color:var(--danger); border-radius:var(--r-md); padding:10px 12px; font-size:var(--fs-body); margin-bottom:14px;}
|
||||
.auth-alert.show{display:block;}
|
||||
.auth-ok{background:var(--success-bg); border:1px solid var(--success); color:var(--success); border-radius:var(--r-md); padding:14px; font-size:var(--fs-body); margin-bottom:14px;}
|
||||
.auth-ok code{font-family:var(--font-mono); font-weight:700; font-size:17px;}
|
||||
@media (max-width:860px){ .auth,.auth.reg{grid-template-columns:1fr; max-width:480px;} .auth-brand{min-height:auto; padding:34px 32px;} .auth-brand .pts,.auth-brand .steps{display:none;} .auth-form{padding:32px 28px;} .grid2f{grid-template-columns:1fr;} }
|
||||
|
||||
/* ---------- Checkout(确认订单,仿原型 screens/checkout.html) ---------- */
|
||||
.crumb{display:flex; align-items:center; gap:7px; font-size:var(--fs-sm); color:var(--muted); margin-bottom:12px;}
|
||||
.crumb a{color:var(--muted); text-decoration:none !important;}
|
||||
.crumb a:hover{color:var(--primary);}
|
||||
.co-title{font-size:var(--fs-h1); font-weight:700; color:var(--heading); margin:0 0 20px;}
|
||||
.checkout{display:grid; grid-template-columns:minmax(0,1fr) 360px; gap:22px; align-items:start; max-width:1020px;}
|
||||
.co-card{background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); padding:20px 22px; margin-bottom:18px;}
|
||||
.co-card h2{margin:0 0 14px; font-size:var(--fs-h2); color:var(--heading);}
|
||||
|
||||
.seg{display:inline-flex; background:var(--bg); border:1px solid var(--border); border-radius:var(--r-md); padding:3px; gap:3px; margin-bottom:6px;}
|
||||
.seg-btn{border:none; background:transparent; padding:8px 18px; border-radius:calc(var(--r-md) - 3px); font-size:var(--fs-body); color:var(--muted); cursor:pointer; font-family:var(--font); display:inline-flex; align-items:center; gap:7px;}
|
||||
.seg-btn.on{background:var(--surface); color:var(--heading); font-weight:600; box-shadow:var(--sh-1);}
|
||||
.seg-tip{font-size:var(--fs-xs); color:var(--success); background:var(--ok-soft); padding:1px 8px; border-radius:var(--r-pill); font-weight:600;}
|
||||
.seg-label{font-size:var(--fs-sm); color:var(--muted); margin:14px 0 8px;}
|
||||
.co-feats{list-style:none; padding:0; margin:12px 0 4px; display:flex; flex-direction:column; gap:8px; font-size:14px; color:var(--text);}
|
||||
.co-feats li{display:flex; gap:8px; align-items:flex-start;}
|
||||
.co-feats li .ic{width:15px; height:15px; color:var(--success); margin-top:3px; flex:none;}
|
||||
|
||||
.co-item{display:flex; align-items:center; gap:14px; padding:4px 0;}
|
||||
.co-item .co-ic{width:46px; height:46px; border-radius:var(--r-md); background:var(--brand50); color:var(--primary); display:flex; align-items:center; justify-content:center; flex:none;}
|
||||
.co-item .co-ic .ic{width:24px; height:24px;}
|
||||
.co-item .co-meta b{display:block; font-size:var(--fs-body); color:var(--heading); font-weight:600;}
|
||||
.co-item .co-meta span{font-size:var(--fs-sm); color:var(--muted);}
|
||||
.co-item .co-amt{margin-left:auto; font-size:18px; font-weight:700; color:var(--heading); font-family:var(--font-mono);}
|
||||
|
||||
.co-pay{display:flex; flex-direction:column; gap:10px;}
|
||||
.co-pay .pm{display:flex; align-items:center; gap:12px; border:1.5px solid var(--border); border-radius:var(--r-md); padding:13px 15px;}
|
||||
.co-pay .pm.on{border-color:var(--primary); box-shadow:0 0 0 3px var(--brand50);}
|
||||
.co-pay .pm.off{opacity:.62;}
|
||||
.co-pay .pic{width:34px; height:34px; border-radius:8px; display:flex; align-items:center; justify-content:center; flex:none; color:#fff;}
|
||||
.co-pay .pic .ic{width:19px; height:19px;}
|
||||
.co-pay .nm b{display:block; font-size:var(--fs-body); color:var(--heading); font-weight:600;}
|
||||
.co-pay .nm span{font-size:var(--fs-xs); color:var(--muted);}
|
||||
.co-pay .radio{margin-left:auto; width:18px; height:18px; border-radius:50%; border:2px solid var(--border); flex:none; position:relative;}
|
||||
.co-pay .pm.on .radio{border-color:var(--primary);}
|
||||
.co-pay .pm.on .radio::after{content:''; position:absolute; inset:3px; border-radius:50%; background:var(--primary);}
|
||||
|
||||
.co-summary{position:sticky; top:84px; margin-bottom:0;}
|
||||
.sum-row{display:flex; justify-content:space-between; font-size:var(--fs-body); color:var(--text); padding:7px 0;}
|
||||
.sum-row.muted{color:var(--muted); font-size:var(--fs-sm);}
|
||||
.sum-div{height:1px; background:var(--border-subtle); margin:8px 0;}
|
||||
.sum-total{display:flex; justify-content:space-between; align-items:baseline; padding-top:6px;}
|
||||
.sum-total .lab{font-size:var(--fs-body); color:var(--heading); font-weight:600;}
|
||||
.sum-total .val{font-size:var(--fs-display); font-weight:800; color:var(--primary); font-family:var(--font-mono); letter-spacing:-.5px;}
|
||||
.co-summary .fine{font-size:var(--fs-xs); color:var(--faint); text-align:center; margin-top:12px; line-height:1.6;}
|
||||
|
||||
/* ---------- 支付结果页 ---------- */
|
||||
.result{text-align:center; max-width:520px; margin:0 auto; padding:24px 16px;}
|
||||
.result .ring{width:72px; height:72px; border-radius:50%; display:flex; align-items:center; justify-content:center; margin:0 auto 18px;}
|
||||
.result .ring .ic{width:36px; height:36px;}
|
||||
.result .ring.good{background:var(--ok-soft); color:var(--success);}
|
||||
.result .ring.wait{background:var(--brand50); color:var(--primary);}
|
||||
.result h2{margin:0 0 10px; font-size:var(--fs-h1); color:var(--heading);}
|
||||
.result p{margin:0 0 22px; font-size:var(--fs-body); color:var(--muted); line-height:1.8;}
|
||||
.result .ono{display:inline-flex; align-items:center; gap:8px; font-family:var(--font-mono); font-size:var(--fs-body); background:var(--bg); border:1px dashed var(--border); border-radius:var(--r-md); padding:10px 16px; color:var(--heading); margin-bottom:22px;}
|
||||
.result .acts{display:flex; gap:10px; justify-content:center; flex-wrap:wrap;}
|
||||
|
||||
@media (max-width:900px){
|
||||
.checkout{grid-template-columns:1fr;}
|
||||
.co-summary{position:static;}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/* ============================================================
|
||||
岩美酒库官网 · 令牌层
|
||||
单一真相源:.superpowers/prototype/tokens.css 主题 A(经典蓝)1:1 拷贝
|
||||
+ 「营销扩展」段(仅官网用的大字号/容器宽,App 无此场景)。
|
||||
规则:页面与组件只引用 var(--token),禁硬编码 hex。
|
||||
同步纪律:App 原型 token 变更时,此文件对应值需同步。
|
||||
============================================================ */
|
||||
|
||||
:root{
|
||||
/* —— 与原型 :root 完全一致 —— */
|
||||
--sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-8:32px; --sp-10:40px;
|
||||
--r-sm:4px; --r-md:6px; --r-lg:10px; --r-xl:14px; --r-pill:999px;
|
||||
--fs-display:28px; --fs-h1:21px; --fs-h2:17px; --fs-title:15px; --fs-body:13px; --fs-sm:12px; --fs-xs:11px;
|
||||
--font:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei","Inter",sans-serif;
|
||||
--font-mono:"JetBrains Mono","SF Mono",ui-monospace,monospace;
|
||||
--sh-1:0 1px 3px var(--shadow); --sh-2:0 4px 14px var(--shadow); --sh-3:0 18px 50px var(--shadow);
|
||||
--scrim:rgba(15,20,30,.42); --hero-glass:rgba(255,255,255,.16); --hero-glass-strong:rgba(255,255,255,.24);
|
||||
--brand-deep:#0F3057; --brand-mid:#1B4F8E; --brand-wine:#8B2331; --brand-dot:#C97B86;
|
||||
--on-accent:#FFFFFF; --on-accent-faint:rgba(255,255,255,.72);
|
||||
--toast-bg:#1F2330;
|
||||
|
||||
/* —— 主题 A(经典蓝)—— */
|
||||
--page:#E7EBF1; --bg:#F5F7FA; --surface:#FFFFFF; --border:#DCE2EB; --border-subtle:#ECEFF4;
|
||||
--text:#232934; --heading:#1B2430; --title:#1B2430; --muted:#6E7888; --faint:#99A3B3;
|
||||
--primary:#2563AC; --primary-dark:#154072; --on-primary:#FFFFFF; --brand400:#4F86C6; --brand50:#EEF4FB; --accent:#8B2331;
|
||||
--success:#2E8B57; --danger:#D14343; --warn:#E08E00;
|
||||
--info-soft:#EEF4FB; --ok-soft:#E8F5EE; --accent-soft:#FAEEF0;
|
||||
--success-bg:#E8F5EE; --danger-bg:#FDECEC; --warn-bg:#FFF4DB;
|
||||
--th-bg:#F7F9FC; --row-hover:#EEF4FB; --shadow:rgba(20,40,70,.20);
|
||||
--side-bg:#163A6C; --side-fg:#C4D6ED; --side-active-bg:#2C6BB3; --side-active-fg:#FFFFFF;
|
||||
|
||||
/* —— 营销扩展(官网独有场景;App 端无对应 token)—— */
|
||||
--mk-display:clamp(34px, 5vw, 54px); /* hero 大标题 */
|
||||
--mk-h2:clamp(24px, 3.2vw, 34px); /* 区块标题 */
|
||||
--mk-h3:19px;
|
||||
--mk-lead:clamp(15px, 1.6vw, 18px); /* hero/区块引言 */
|
||||
--mk-body:15px; /* 营销正文(App fs-body 13 在长文场景过小) */
|
||||
--mk-maxw:1120px; /* 内容容器宽 */
|
||||
--mk-hero-grad:linear-gradient(150deg, var(--side-bg), var(--side-active-bg)); /* 与登录页品牌面板同源 */
|
||||
}
|
||||
|
||||
/* ---------- 兼容别名层:旧 color.css 词汇 → 真相源 token ----------
|
||||
仅供 docs.css / legal.css 等二级页面样式过渡使用;新样式禁止引用这些别名。 */
|
||||
:root{
|
||||
--brand-50:var(--brand50); --brand-100:#DDE9F7; --brand-200:#C3D8F0; --brand-300:#9FC0E4;
|
||||
--brand-400:var(--brand400); --brand-500:var(--primary); --brand-600:#1B4F8E; --brand-700:var(--primary-dark); --brand-900:#0A1F3B;
|
||||
--gray-0:#FFFFFF; --gray-25:var(--bg); --gray-50:#EEF1F5; --gray-100:#E3E7ED; --gray-300:#C6CDD8;
|
||||
--gray-500:var(--faint); --gray-700:var(--muted); --gray-800:var(--text); --gray-900:var(--heading);
|
||||
--fg-default:var(--text); --fg-muted:var(--muted); --fg-subtle:var(--faint); --fg-link:var(--primary);
|
||||
--border-default:var(--border); --info-50:var(--info-soft); --info-500:#2F7BD0; --info-700:#1D5A9E;
|
||||
--radius-sm:var(--r-sm); --radius-md:var(--r-md); --radius-lg:var(--r-lg);
|
||||
--text-xs:12px; --text-sm:13px; --text-md:15px; --text-lg:17px; --text-xl:19px; --text-2xl:24px;
|
||||
--duration-fast:.15s; --ease-standard:ease; --ring-focus:0 0 0 3px var(--brand50);
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
---
|
||||
layout: base.njk
|
||||
title: 确认订单
|
||||
description: 选择套餐与计费周期,在线支付开通或续费门店授权。
|
||||
permalink: /checkout/
|
||||
---
|
||||
{# 官网内购买/续费(需登录):套餐+周期联动汇总 → POST /api/v1/license/purchase
|
||||
拿 pay_url 跳收银台(契约 pay-contract v1.0.0)。版式仿原型 screens/checkout.html。 #}
|
||||
<div class="container" style="padding:40px 24px 72px">
|
||||
<div class="crumb"><a href="/#pricing">购买授权</a><span>/</span><span>确认订单</span></div>
|
||||
<h1 class="co-title">确认订单</h1>
|
||||
|
||||
<div class="checkout">
|
||||
<div>
|
||||
<div class="co-card">
|
||||
<h2>选择套餐</h2>
|
||||
<div class="seg" id="planSeg">
|
||||
<button class="seg-btn on" data-v="standard">标准版</button>
|
||||
<button class="seg-btn" data-v="pro">高级版</button>
|
||||
</div>
|
||||
<ul class="co-feats" id="planFeats"></ul>
|
||||
<div class="seg-label">计费周期</div>
|
||||
<div class="seg" id="cycleSeg">
|
||||
<button class="seg-btn on" data-v="annual">年付 <span class="seg-tip">省两个月</span></button>
|
||||
<button class="seg-btn" data-v="monthly">月付</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="co-card">
|
||||
<h2>订单内容</h2>
|
||||
<div class="co-item">
|
||||
<div class="co-ic"><svg class="ic"><use href="#i-ic07"/></svg></div>
|
||||
<div class="co-meta"><b id="itName">标准版授权</b><span id="itDur">365 天授权 · 到期时间自动叠加</span></div>
|
||||
<div class="co-amt" id="itAmt">¥2,999</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="co-card">
|
||||
<h2>付款方式</h2>
|
||||
<div class="co-pay">
|
||||
<div class="pm on">
|
||||
<div class="pic" style="background:#1677FF"><svg class="ic"><use href="#i-ic08"/></svg></div>
|
||||
<div class="nm"><b>支付宝</b><span>电脑扫码 / 手机拉起支付宝,即时到账</span></div>
|
||||
<div class="radio"></div>
|
||||
</div>
|
||||
<div class="pm off">
|
||||
<div class="pic" style="background:#8A94A6"><svg class="ic"><use href="#i-ic11"/></svg></div>
|
||||
<div class="nm"><b>对公转账</b><span>需要合同与对公收款请<a href="mailto:{{ site.support.email }}">联系我们</a></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="co-card co-summary">
|
||||
<h2>费用汇总</h2>
|
||||
<div class="sum-row"><span id="sumName">标准版 · 年付</span><span id="sumBase">¥2,999</span></div>
|
||||
<div class="sum-row muted"><span>优惠</span><span>− ¥0</span></div>
|
||||
<div class="sum-div"></div>
|
||||
<div class="sum-total"><span class="lab">应付总额</span><span class="val" id="sumTotal">¥2,999</span></div>
|
||||
<div class="auth-alert" id="coErr" style="margin-top:12px"></div>
|
||||
<button class="btn primary lg" id="coBtn" style="width:100%;margin-top:16px">提交订单</button>
|
||||
<div class="fine">提交后跳转支付宝收银台,支付成功即时续期到当前门店。时长在现有到期时间上叠加,不覆盖。</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var API = '{{ site.appBaseUrl }}';
|
||||
function $(id) { return document.getElementById(id); }
|
||||
function token() {
|
||||
var raw = localStorage.getItem('flutter.access_token');
|
||||
if (!raw) return null;
|
||||
try { return JSON.parse(raw); } catch (e) { return raw; }
|
||||
}
|
||||
function gotoLogin() { location.href = '/login/?next=' + encodeURIComponent('/checkout/' + location.search); }
|
||||
if (!token()) { gotoLogin(); return; }
|
||||
|
||||
/* 套餐目录:价格仅前端展示,实付金额以 pay 套餐表为准(下单响应回传) */
|
||||
var PLANS = {
|
||||
standard: {
|
||||
name: '标准版',
|
||||
feats: ['单门店 · 单仓库', '2 台客户端同时使用', '1,000 张商品图片分享'],
|
||||
monthly: { biz: 'monthly_standard', price: 299 },
|
||||
annual: { biz: 'annual_standard', price: 2999 },
|
||||
},
|
||||
pro: {
|
||||
name: '高级版',
|
||||
feats: ['单门店 · 多仓库', '5 台客户端同时使用', '10,000 张商品图片分享', '免费 AI 周度 / 月度商业数据分析'],
|
||||
monthly: { biz: 'monthly_pro', price: 599 },
|
||||
annual: { biz: 'annual_pro', price: 5999 },
|
||||
},
|
||||
};
|
||||
var q = new URLSearchParams(location.search);
|
||||
var plan = PLANS[q.get('plan')] ? q.get('plan') : 'standard';
|
||||
var cycle = 'annual';
|
||||
|
||||
function fmt(n) { return '¥' + n.toLocaleString('zh-CN'); }
|
||||
function render() {
|
||||
var p = PLANS[plan], c = p[cycle];
|
||||
var days = cycle === 'annual' ? 365 : 30;
|
||||
$('planFeats').innerHTML = p.feats.map(function (f) {
|
||||
return '<li><svg class="ic"><use href="#i-check"/></svg>' + f + '</li>';
|
||||
}).join('');
|
||||
$('itName').textContent = p.name + '授权 · ' + (cycle === 'annual' ? '年付' : '月付');
|
||||
$('itDur').textContent = days + ' 天授权 · 到期时间自动叠加';
|
||||
$('itAmt').textContent = fmt(c.price);
|
||||
$('sumName').textContent = p.name + ' · ' + (cycle === 'annual' ? '年付' : '月付');
|
||||
$('sumBase').textContent = fmt(c.price);
|
||||
$('sumTotal').textContent = fmt(c.price);
|
||||
document.querySelectorAll('#planSeg .seg-btn').forEach(function (b) { b.classList.toggle('on', b.dataset.v === plan); });
|
||||
document.querySelectorAll('#cycleSeg .seg-btn').forEach(function (b) { b.classList.toggle('on', b.dataset.v === cycle); });
|
||||
}
|
||||
document.querySelectorAll('#planSeg .seg-btn').forEach(function (b) {
|
||||
b.addEventListener('click', function () { plan = b.dataset.v; render(); });
|
||||
});
|
||||
document.querySelectorAll('#cycleSeg .seg-btn').forEach(function (b) {
|
||||
b.addEventListener('click', function () { cycle = b.dataset.v; render(); });
|
||||
});
|
||||
render();
|
||||
|
||||
function showErr(msg) { var el = $('coErr'); el.textContent = msg; el.classList.add('show'); }
|
||||
$('coBtn').addEventListener('click', function () {
|
||||
$('coErr').classList.remove('show');
|
||||
var btn = $('coBtn'); btn.disabled = true; btn.textContent = '正在创建订单…';
|
||||
fetch(API + '/api/v1/license/purchase', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token() },
|
||||
body: JSON.stringify({ biz_code: PLANS[plan][cycle].biz }),
|
||||
})
|
||||
.then(function (r) {
|
||||
if (r.status === 401) { gotoLogin(); throw new Error('登录已过期'); }
|
||||
return r.json().then(function (j) { return { ok: r.ok, j: j }; });
|
||||
})
|
||||
.then(function (res) {
|
||||
if (!res.ok) throw new Error((res.j && res.j.error) || '下单失败,请稍后重试');
|
||||
var d = res.j.data || {};
|
||||
if (!d.pay_url) throw new Error('下单响应异常');
|
||||
location.href = d.pay_url;
|
||||
})
|
||||
.catch(function (e) {
|
||||
showErr(e && e.message ? e.message : '无法连接服务器,请稍后重试');
|
||||
btn.disabled = false; btn.textContent = '提交订单';
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@@ -1,487 +1,165 @@
|
||||
# 岩美酒库管理系统 · 使用手册
|
||||
# 岩美酒库 · 使用手册
|
||||
|
||||
> 适用版本:v1.x · 受众:酒行管理员及工作人员
|
||||
> 适用版本:客户端 v1.1.1 · 受众:酒行店员 / 店长
|
||||
|
||||
---
|
||||
|
||||
## 1. 系统概述
|
||||
## 1. 快速上手
|
||||
|
||||
岩美酒库管理系统专为酒行门店设计,将入库、出库、库存查询、财务往来等日常业务整合到一个平台,支持多人协同操作,数据实时同步。
|
||||
**注册新门店**:登录页点「注册新门店」,三步开通——①填门店信息(编号自动分配)②创建管理员账号(密码至少 6 位)③激活授权。新门店自带 **30 天免费试用**,有兑换券登录后在「系统设置 → 授权兑换券」输入短码续期。
|
||||
|
||||
**核心功能一览**
|
||||
**登录**:输入门店编号、登录账号、密码。「记住我」会自动填入最近登录的门店和账号;账号框带历史下拉,多人共用电脑时点箭头切换。忘记密码请找本店管理员在「用户管理」中重置。
|
||||
|
||||
| 模块 | 主要用途 |
|
||||
|------|---------|
|
||||
| 入库管理 | 新建入库单、提交审核、审批通过后自动更新库存 |
|
||||
| 出库管理 | 新建出库单、提交审核、审批时自动扣减库存 |
|
||||
| 库存管理 | 查询实时库存、库存盘点、打印标签 |
|
||||
| 财务管理 | 查看应付款(欠供应商)和应收款(客户欠款)、标记结清 |
|
||||
| 往来单位 | 管理供应商和客户的基本信息 |
|
||||
| 基础数据 | 维护商品名称、系列、规格字典 |
|
||||
| 系统设置 | 用户管理、仓库管理、编号规则、数据导入 |
|
||||
**五端支持**:
|
||||
|
||||
**支持平台**:Web 浏览器(现已上线);Windows、macOS、iOS、Android 客户端即将推出。
|
||||
|
||||
---
|
||||
|
||||
## 2. 登录与退出
|
||||
|
||||
### 2.1 登录
|
||||
|
||||
1. 打开系统,进入登录页面。
|
||||
2. 在「门店编号」栏输入酒行的门店代号(例如 `S001`)。
|
||||
3. 输入「用户名」和「密码」。
|
||||
4. 点击「登录」按钮。
|
||||
|
||||
登录成功后,系统自动跳转到「入库管理」页面。
|
||||
|
||||
**提示**:系统会记录最近登录过的用户名,点击输入框可从候选列表中快速选择。
|
||||
|
||||
### 2.2 退出登录
|
||||
|
||||
点击顶部右侧用户名旁的下拉箭头,选择「退出登录」。
|
||||
|
||||
### 2.3 查看当前登录信息
|
||||
|
||||
点击顶部左侧「岩美」标题或右侧「门店编号」区域,弹出门店信息面板,显示门店编号、登录账号、姓名、系统版本。
|
||||
|
||||
---
|
||||
|
||||
## 3. 界面说明
|
||||
|
||||
系统主界面由三个区域组成:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 顶部导航栏(标题、门店编号、用户名、退出) │
|
||||
├──────────┬───────────────────────────────────────────────┤
|
||||
│ │ │
|
||||
│ 左侧 │ 主内容区域 │
|
||||
│ 侧边栏 │ │
|
||||
│ │ │
|
||||
├──────────┴───────────────────────────────────────────────┤
|
||||
│ 状态栏(门店、用户、登录时间、当前时间、连接状态) │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**左侧侧边栏导航项**
|
||||
|
||||
| 导航项 | 功能 |
|
||||
|--------|------|
|
||||
| 入库管理 | 入库单录入与审核 |
|
||||
| 出库管理 | 出库单录入与审核 |
|
||||
| 库存管理 | 库存查询与盘点 |
|
||||
| 财务管理 | 应付款和应收款 |
|
||||
| 往来单位 | 供应商与客户 |
|
||||
| 基础数据 | 商品名称、系列、规格字典 |
|
||||
| 系统设置 | 用户、仓库、编号规则等配置 |
|
||||
|
||||
点击侧边栏顶部的菜单图标可收起或展开侧边栏,节省屏幕空间。
|
||||
|
||||
**更新提示**:有新版本时,内容区顶部会显示黄色提示横幅;如果是必须更新的版本,会弹出对话框要求立即更新。
|
||||
|
||||
**离线提示**:网络断开时,顶部显示红色横幅「网络连接已断开」,状态栏变红,此时展示上次加载的缓存数据。
|
||||
|
||||
---
|
||||
|
||||
## 4. 角色与权限
|
||||
|
||||
系统有四种角色,权限从高到低依次为:
|
||||
|
||||
| 角色 | 说明 | 可执行操作 |
|
||||
|------|------|------------|
|
||||
| 超级管理员 | 系统最高权限账号 | 全部操作,含数据清空 |
|
||||
| 管理员 | 门店管理人员 | 全部操作,含用户管理、酒行信息编辑 |
|
||||
| 操作员 | 日常录入审核人员 | 新建、编辑、提交、审核单据,查询数据 |
|
||||
| 只读 | 仅查看数据 | 只能查看,不能新建、修改、删除任何数据 |
|
||||
|
||||
**权限说明**
|
||||
|
||||
- 只读账号点击任何写操作按钮时,系统将直接提示「无权限」。
|
||||
- 新增或编辑用户、重置密码仅管理员可操作。
|
||||
- 修改酒行基本信息仅管理员可操作。
|
||||
- 数据清空仅超级管理员可操作。
|
||||
|
||||
---
|
||||
|
||||
## 5. 入库管理
|
||||
|
||||
入库管理页面包含两个标签页:**入库审核**(新建和待审核)和**入库单**(已完成记录)。
|
||||
|
||||
### 5.1 入库单状态说明
|
||||
|
||||
单据状态按以下流程流转:
|
||||
|
||||
**草稿** → **待审核** → **已审批**(库存增加)
|
||||
|
||||
待审核阶段也可被拒绝,变为**已拒绝**状态(库存不变)。
|
||||
|
||||
| 状态 | 含义 |
|
||||
| 平台 | 说明 |
|
||||
|------|------|
|
||||
| 草稿 | 已保存但未提交,可继续编辑或删除 |
|
||||
| 待审核 | 已提交等待审批,不可再编辑 |
|
||||
| 已审批 | 审批通过,库存已增加,同时生成应付账款记录 |
|
||||
| 已拒绝 | 审批不通过,库存不变 |
|
||||
| Windows / macOS | 官网下载安装包(macOS 已通过 Apple 公证) |
|
||||
| Web 网页版 | 浏览器直接打开,免安装 |
|
||||
| Android | 官网下载 APK |
|
||||
| iOS | 通过 TestFlight 安装 |
|
||||
|
||||
### 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 文件。
|
||||
**主题切换**:点右上角的小衣服图标,三套配色随意换——A 经典蓝(浅色·默认)、B 琥珀(深色)、C 酒窖(暖浅色),也可在「系统设置 → 偏好设置」里选。
|
||||
|
||||
---
|
||||
|
||||
## 6. 出库管理
|
||||
## 2. 核心概念(必读)
|
||||
|
||||
出库管理与入库管理操作流程类似,包含**出库审核**(待处理)和**出库单**(已完成)两个标签页。
|
||||
**每瓶酒 = 一个独立编号**。系统按「件」记账:入库每录一行,就生成一个新的商品编号和专属二维码标签。字段含义:名称=品牌(茅台)、系列=型号(飞天 53°)、规格=版本(500ml)。库存里同一款酒出现多行是正常的——每行是不同批次的货,各自可追溯。
|
||||
|
||||
### 6.1 出库单状态说明
|
||||
**审核流**:草稿 → 提交 → 待审核 → 审核通过(此刻才增减库存、生成账款)/ 拒绝(什么都不变)。待审核的单可「撤回」退回草稿修改;已审核的单只能走「退单」。
|
||||
|
||||
出库单状态流转与入库单相同:草稿 → 待审核 → 已审批或已拒绝。
|
||||
**四级角色**:
|
||||
|
||||
审批通过后:
|
||||
- 系统会先检查库存是否充足,库存不足时审批失败并给出提示,库存不变。
|
||||
- 库存充足时自动扣减库存,并生成应收账款记录。
|
||||
| 角色 | 权限要点 |
|
||||
|------|---------|
|
||||
| 超级管理员 | 全部操作 |
|
||||
| 管理员 | 全部业务 + 用户管理;**可见成本价与利润** |
|
||||
| 操作员 | 录单、审核、查询;看不到成本和利润,只能撤回自己的单 |
|
||||
| 只读 | 只能查看,所有操作按钮隐藏 |
|
||||
|
||||
### 6.2 新建出库单
|
||||
|
||||
1. 点击左侧「出库管理」,切换到「出库审核」标签页。
|
||||
2. 点击右上角「新建出库审核单」按钮。
|
||||
3. 填写基本信息:
|
||||
- **仓库**(必填):选择出货仓库。
|
||||
- **客户**(必填):选择购买方(往来单位中的客户类型)。
|
||||
- **出库日期**(必填):默认今天,可修改。
|
||||
4. 填写商品明细:商品名称、系列、规格、数量、单价(操作方式同入库单)。
|
||||
5. 保存草稿或保存并提交审核。
|
||||
|
||||
**注意**:出库数量不能超过当前库存,审批时系统会自动检查,库存不足会提示失败。
|
||||
|
||||
### 6.3 审批出库单
|
||||
|
||||
操作步骤与入库审批相同。审批通过后库存自动扣减,同时生成应收账款记录。
|
||||
|
||||
### 6.4 打印出库单
|
||||
|
||||
在列表中点击「打印」按钮,打印出库单据。
|
||||
|
||||
### 6.5 标记货款结清
|
||||
|
||||
出库单审批通过后生成应收账款。收到货款后,在列表中点击「结清」按钮,将对应财务记录标记为已结清。
|
||||
成本与利润由服务器按角色控制,操作员端不下发数字。
|
||||
|
||||
---
|
||||
|
||||
## 7. 库存管理
|
||||
## 3. 入库管理
|
||||
|
||||
### 7.1 查询库存
|
||||
顶部四张统计卡:近 30 天笔数 / 金额、待审核单数、草稿单数——后两张**点击即筛选列表**。
|
||||
|
||||
点击左侧「库存管理」进入库存列表。
|
||||
**新建入库单**:选仓库、供应商、日期 → 明细表格逐行录(一行 = 一件独立编号商品):名称/系列/规格可搜索、没有的直接新增;生产日期滚轮选择;**批次号必填**;**进价(单瓶)可留空 = 待定价**;**参考售价**会存入商品档案、出库时自动带出;总进价自动合计。键盘:`Enter` 跳格、`⌘D / Ctrl+D` 复制上一行、`⌘Enter / Ctrl+Enter` 提交。
|
||||
|
||||
列表显示每个商品的实时库存数量、所在仓库、单价、金额、生产日期、批次等信息。
|
||||
**审核**:通过 → 库存增加、生成应付账款;拒绝 → 不变。审核前核对好数量和进价。
|
||||
|
||||
- **搜索**:在搜索框输入商品名称关键字(也支持拼音或拼音首字母),实时过滤结果。
|
||||
- **仓库筛选**:点击列头「仓库」的筛选图标,按仓库查看库存。
|
||||
- **导出**:点击「导出」按钮,将当前库存列表导出为 Excel 文件。
|
||||
**退单**(管理员):已审核单点红色「退单」,逐行退或全部退;库存删除、冲减应付,列表显示「部分退单 / 已退单」徽章。
|
||||
|
||||
### 7.2 修改备注
|
||||
**确认进价**:待定价的单在详情点「确认进价」补真实进价,成本与应付自动回填,售价/应收不受影响。
|
||||
|
||||
在库存列表中,点击「备注」列对应单元格(显示铅笔图标或现有备注内容),弹出编辑框,填写后点击「保存」即可。
|
||||
|
||||
### 7.3 打印商品标签
|
||||
|
||||
在库存列表中点击某商品行的「打印标签」按钮,可单独打印该商品的标签。
|
||||
|
||||
### 7.4 库存盘点
|
||||
|
||||
1. 在库存管理页面切换到「库存盘点」标签页。
|
||||
2. 选择要盘点的**仓库**,系统自动加载该仓库所有商品的账面库存数量。
|
||||
3. 选择盘点类型(全盘)。
|
||||
4. 逐行填写**实际盘点数量**(与账面不符时修改数量)。
|
||||
5. 点击「提交盘点」完成。
|
||||
|
||||
盘点单编号由系统自动生成。
|
||||
|
||||
### 7.5 库存流水
|
||||
|
||||
「库存流水」标签页可查看每次库存变动记录,包括入库、出库的时间、变动数量等。
|
||||
**找单**:搜索框支持单号、供应商、酒名(拼音);「详细搜索」可按商品编码、批次号、系列、规格、录单人、审核员、状态、日期区间等组合查询。打印带预览,针式打印机版式已优化。
|
||||
|
||||
---
|
||||
|
||||
## 8. 财务管理
|
||||
## 4. 出库管理
|
||||
|
||||
### 8.1 财务记录说明
|
||||
**新建出库单**:选仓库、客户、日期 → 「添加商品」从库存选货(按编码/名称/系列搜索,分页加载)。选中后**数量自动填可用数量、售价自动带入库时的参考售价**。管理员可见每行实时利润 =(售价 − 进价)× 数量,底栏显示合计金额与合计利润。
|
||||
|
||||
系统在以下情况自动生成财务记录:
|
||||
- 入库单审批通过 → 自动生成**应付账款**(欠供应商的货款)
|
||||
- 出库单审批通过 → 自动生成**应收账款**(客户欠的货款)
|
||||
**待定价出库**:售价可留空先发货,事后在详情点「确认售价」补填,自动补应收。
|
||||
|
||||
点击左侧「财务管理」进入财务页面,包含三个标签:
|
||||
**详情**:管理员见成本价 / 售价 / 总售价 / 利润列;操作员只见售价和小计。
|
||||
|
||||
**审核**:出库数量不能超过库存,不足会拦下。通过后扣减库存、生成应收账款。
|
||||
|
||||
**退单**:客户退货点「退单」,商品加回库存、按售价冲减应收。可打印单据(带预览)和带二维码的商品标签。
|
||||
|
||||
---
|
||||
|
||||
## 5. 库存管理
|
||||
|
||||
库存按**批次维度**展示,同款酒不同批次分行。搜索支持商品名(汉字/全拼/首字母)和编码;「显示字段」可自定义列且会被记住。
|
||||
|
||||
主要列:商品/系列/规格/批次号、库存、成本价与总价(=库存×成本,仅管理员)、生产日期、入库日期、供应商、状态(在售/预警/缺货,「缺货预警」卡点击即筛选)。
|
||||
|
||||
**商品编辑抽屉**:点击库存行打开——上传商品图片(双击全屏预览、可缩放翻页)、从介绍库选择商品介绍、查看成本价(单瓶)/总成本价。
|
||||
|
||||
**盘点**:库存盘点页选仓库(账面自动加载)→ 选全盘/循环盘点 → 填实盘数量 → 提交。
|
||||
|
||||
**标签与扫码分享**:每件商品唯一二维码,标签含品名、编码、批次、生产日期、店名和二维码;扫码打开商品详情公开页,链接可直接分享给顾客与同行。
|
||||
|
||||
---
|
||||
|
||||
## 6. 财务管理
|
||||
|
||||
页面自上而下:时间范围筛选 → KPI 四卡(本月销售、本月采购、应收、应付,带未结清笔数)→ 收支趋势图 → 应收/应付按往来单位汇总(点击行看该单位流水和近期单据)→ 收支流水表(按收款/付款/应收/应付筛选)。
|
||||
|
||||
账款来源:入库审核通过自动生成**应付**,出库审核通过自动生成**应收**。「登记收支」可手动记一笔收付款(类型 + 往来单位 + 金额 + 日期 + 备注)。
|
||||
|
||||
**结清**:流水行单笔结清,或在往来单位抽屉整体处理;入库/出库列表也有结清入口。结清不可撤销,操作前确认款项已到。
|
||||
|
||||
---
|
||||
|
||||
## 7. 往来单位
|
||||
|
||||
供应商和客户统一管理,录单时的供应商/客户下拉来源于此。列表含名称、类型徽章、联系人、电话、**应收、应付**,类型 chips 一键筛选,搜索支持拼音。
|
||||
|
||||
新建/编辑:名称必填;**期初余额**用于把老账本上的旧欠款带进系统。点击任意行打开详情抽屉:联系信息、应收应付余额、近期单据(含入库应付、出库应收、收付款),可打对账单。已关联单据的单位不可删除。
|
||||
|
||||
---
|
||||
|
||||
## 8. 基础数据
|
||||
|
||||
五个标签页:
|
||||
|
||||
| 标签 | 内容 |
|
||||
|------|------|
|
||||
| 全部记录 | 所有财务流水 |
|
||||
| 应付账款 | 需要向供应商付款的记录 |
|
||||
| 应收账款 | 客户尚未付款的记录 |
|
||||
| 商品档案 | 全店商品编号档案,由入库单自动建立(无手动新增),只查看和编辑 |
|
||||
| 商品介绍 | 介绍库,供库存页商品编辑抽屉「从介绍库选择」 |
|
||||
| 系列 | 型号/产品线字典 |
|
||||
| 规格 | 版本/包装字典 |
|
||||
| 仓库 | 仓库维护(默认仓库在「偏好设置」里选) |
|
||||
|
||||
### 8.2 查看财务记录
|
||||
|
||||
- 默认显示当前月份的记录,可通过月份选择器查看历史月份。
|
||||
- 支持按「类型」和「往来单位」列头筛选。
|
||||
- 点击「导出」可导出当月数据为 Excel 文件。
|
||||
|
||||
### 8.3 标记结清
|
||||
|
||||
**方式一**:在入库单或出库单列表中点击「结清」按钮,直接结清该单据对应的账款。
|
||||
|
||||
**方式二**:在财务管理列表中找到对应记录,点击「结清」按钮,单笔结清。
|
||||
|
||||
结清后该记录状态从「未结清」变为「已结清」。
|
||||
|
||||
### 8.4 财务汇总
|
||||
|
||||
财务管理页面显示当期应付和应收总额,便于掌握资金往来概况。
|
||||
字典维护直接影响录单下拉候选;录单时输入新名字选「新增」也会自动进字典,这里主要做事后整理。
|
||||
|
||||
---
|
||||
|
||||
## 9. 往来单位
|
||||
## 9. 设备与设置
|
||||
|
||||
往来单位管理**供应商**和**客户**两类信息,新建入库单时选择供应商,新建出库单时选择客户。
|
||||
**设备管理**:登录设备(本店所有在线会话,管理员可「强制下线」)、外设登记(打印机、扫码枪存档)、打印模板。
|
||||
|
||||
### 9.1 查看往来单位
|
||||
**系统设置**五个面板:
|
||||
|
||||
点击左侧「往来单位」,通过「供应商」和「客户」标签页分别查看。列表支持按名称搜索和导出。
|
||||
| 面板 | 说明 |
|
||||
|------|------|
|
||||
| 门店信息 | 店名/地址/电话/负责人,管理员可编辑,编号不可改 |
|
||||
| 用户管理 | 新增/编辑/重置密码/启停用户,仅管理员 |
|
||||
| 编号规则 | 单号前缀与序号;序号切勿调小,会撞号 |
|
||||
| 授权兑换券 | 输入 `JIUKU-XXXX-XXXX` 短码兑换续期,时长叠加;新店 30 天试用 |
|
||||
| 偏好设置 | 主题切换 + 默认仓库 |
|
||||
|
||||
### 9.2 新建往来单位
|
||||
授权过期:7 天内宽限照常用,7–15 天只读,满 15 天锁定;兑换新券立即恢复,数据不丢。
|
||||
|
||||
1. 在对应标签页点击右上角「新建」按钮。
|
||||
2. 填写信息:
|
||||
- **名称**(必填)
|
||||
- **联系电话**(选填)
|
||||
- **地址**(选填)
|
||||
- **卡号**(选填,如有账户绑定)
|
||||
- **初始余额**(选填,导入历史数据时填写)
|
||||
- **备注**(选填)
|
||||
3. 点击「保存」。
|
||||
|
||||
### 9.3 编辑往来单位
|
||||
|
||||
在列表中点击「编辑」按钮,修改信息后保存。
|
||||
|
||||
### 9.4 删除往来单位
|
||||
|
||||
在列表中点击「删除」按钮,确认后删除。
|
||||
|
||||
**注意**:已关联入库单或出库单的往来单位不可删除。
|
||||
「关于我们」页可查版本更新、授权状态、更新日志,并提交反馈。
|
||||
|
||||
---
|
||||
|
||||
## 10. 基础数据(商品管理)
|
||||
## 10. 常见问题
|
||||
|
||||
点击左侧「基础数据」,进入商品字典管理页面,包含三个标签:**商品名称**、**系列**、**规格**。
|
||||
**忘记密码?** 找管理员在「用户管理」重置;管理员本人忘记请联系技术支持。
|
||||
|
||||
这些字典数据是新建入库或出库单时选择商品的基础,需要先在此处维护好商品信息。
|
||||
**单据录错了?** 待审核 → 「撤回」回草稿修改;已审核 → 「退单」退掉错的行再补单。
|
||||
|
||||
### 10.1 商品名称管理
|
||||
**库存对不上?** 记下商品编码,到入库/出库「详细搜索」按编码查所有相关单据核对,再做一次盘点调平。
|
||||
|
||||
商品名称是酒品的主名称,例如「茅台飞天 53°」。
|
||||
**同款酒库存好多行?** 设计如此:按件记账,每行是一个独立编号/批次,各自可追溯。
|
||||
|
||||
1. 在「商品名称」标签页,点击「新建」按钮。
|
||||
2. 填写商品名称(必填)、编号(选填)、备注(选填)。
|
||||
3. 点击「保存」。
|
||||
**打印没反应/发糊?** 先升级到最新版;用「打印预览」确认;针打版式已做纯黑加粗优化。
|
||||
|
||||
支持按名称或编号搜索,支持分页浏览,支持编辑和删除。
|
||||
**扫码打不开商品页?** 早期版本的扫码报错已修复;确认手机联网,很旧的标签可重打。
|
||||
|
||||
### 10.2 系列管理
|
||||
**授权到期变只读?** 「系统设置 → 授权兑换券」输入 JIUKU 兑换码立即恢复;过期 15 天内数据都在。
|
||||
|
||||
系列是商品所属的系列或品牌线,例如「飞天系列」「王子系列」。操作步骤与商品名称相同。
|
||||
**进价/售价还没谈好?** 价格留空即「待定价」,事后在单据详情「确认进价 / 确认售价」补填,账自动补齐。
|
||||
|
||||
### 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 可获得响应。
|
||||
**员工离职/电脑丢失?** 「设备管理」强制下线该设备 + 「用户管理」停用账号或重置密码。
|
||||
|
||||
@@ -1,397 +1,113 @@
|
||||
---
|
||||
layout: base.njk
|
||||
title: 下载
|
||||
description: 下载岩美酒库管理系统,Web 版现已上线,Windows / macOS / iOS / Android 客户端即将推出。
|
||||
description: 下载岩美酒库管理系统客户端:Windows、macOS、Android、iOS 与免安装 Web 版。
|
||||
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; }
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.ph-meta { flex-wrap: wrap; gap: 12px; }
|
||||
.dl-grid { grid-template-columns: 1fr; }
|
||||
.changelog { grid-template-columns: 1fr; }
|
||||
.changelog-version { font-size: 13px; }
|
||||
}
|
||||
.dl-hero{background:var(--mk-hero-grad); color:var(--on-accent); padding:64px 0 72px; text-align:center;}
|
||||
.dl-hero h1{color:var(--on-accent); font-size:var(--mk-h2); font-weight:800;}
|
||||
.dl-hero p{color:var(--on-accent-faint); margin:12px auto 0; max-width:36em;}
|
||||
.detect{max-width:640px; margin:-40px auto 0; position:relative; z-index:2;}
|
||||
.detect .card{display:flex; align-items:center; gap:18px; box-shadow:var(--sh-2); padding:20px 22px;}
|
||||
.detect .icbox{width:44px; height:44px; border-radius:var(--r-lg); flex:none; display:flex; align-items:center; justify-content:center;}
|
||||
.detect .icbox .ic{width:22px; height:22px;}
|
||||
.detect b{display:block; color:var(--heading); font-size:16px;}
|
||||
.detect span{color:var(--muted); font-size:var(--fs-sm);}
|
||||
.detect .btn{margin-left:auto; flex:none;}
|
||||
.dl-grid{display:grid; grid-template-columns:repeat(5,1fr); gap:14px; margin-top:46px;}
|
||||
.dl-card{background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); padding:20px 18px; display:flex; flex-direction:column; text-align:center;}
|
||||
.dl-card.detected{border-color:var(--primary); box-shadow:var(--sh-1);}
|
||||
.dl-card .icbox{width:38px; height:38px; border-radius:var(--r-md); margin:0 auto 12px; display:flex; align-items:center; justify-content:center;}
|
||||
.dl-card h3{font-size:15px; font-weight:700; margin-bottom:4px;}
|
||||
.dl-card .req{color:var(--faint); font-size:var(--fs-xs); margin-bottom:14px;}
|
||||
.dl-card .dl-status{font-size:var(--fs-xs); color:var(--success); margin-bottom:8px;}
|
||||
.dl-card .dl-status.soon{color:var(--warn);}
|
||||
.dl-card .btn{margin-top:auto; width:100%;}
|
||||
.btn.disabled{opacity:.55; pointer-events:none; background:var(--bg); border:1px solid var(--border); color:var(--muted);}
|
||||
/* 更新日志时间线 */
|
||||
.changelog{max-width:820px; margin:0 auto;}
|
||||
.changelog-entry{display:grid; grid-template-columns:150px 1fr; gap:20px; padding:22px 0; border-bottom:1px solid var(--border-subtle);}
|
||||
.changelog-version{font-family:var(--font-mono); font-weight:700; color:var(--heading); font-size:16px;}
|
||||
.changelog-date{color:var(--faint); font-size:var(--fs-sm); margin-top:3px;}
|
||||
.changelog-tag{display:inline-block; margin-top:8px; background:var(--info-soft); color:var(--primary); font-size:var(--fs-xs); font-weight:700; padding:2px 9px; border-radius:var(--r-pill);}
|
||||
.changelog-cat-label{display:flex; align-items:center; gap:7px; font-size:var(--fs-sm); font-weight:700; color:var(--heading); margin:10px 0 6px;}
|
||||
.changelog-cat-label .dot{width:7px; height:7px; border-radius:50%;}
|
||||
.dot-feature{background:var(--primary);} .dot-improve{background:var(--success);} .dot-fix{background:var(--warn);}
|
||||
.changelog-body ul{margin:0; padding-left:20px; color:var(--muted); font-size:14px; line-height:1.8;}
|
||||
.changelog-intro{color:var(--muted); font-size:14px; margin:0 0 4px;}
|
||||
@media (max-width:900px){ .dl-grid{grid-template-columns:repeat(2,1fr);} }
|
||||
@media (max-width:600px){ .dl-grid{grid-template-columns:1fr;} .detect .card{flex-wrap:wrap;} .changelog-entry{grid-template-columns:1fr;} }
|
||||
---
|
||||
|
||||
<!-- ============================== PAGE HEADER ============================== -->
|
||||
<section class="page-header">
|
||||
<div class="container ph-inner">
|
||||
<header class="dl-hero">
|
||||
<div class="container">
|
||||
<h1>下载岩美酒库</h1>
|
||||
<p>当前版本 <b class="version-badge">v{{ changelog[0].version }}</b> · 一个账号五端同步 · 客户端内置自动更新</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="detect container">
|
||||
<div class="card">
|
||||
<div class="icbox ic-info" id="detect-icon"><svg class="ic"><use href="#i-ic01"/></svg></div>
|
||||
<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 桌面版与 Android 客户端均已上线,iOS 客户端即将推出。
|
||||
</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 / Windows / macOS / Android</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="{{ site.appBaseUrl }}/app/" class="btn btn-primary btn-lg" id="detect-btn">
|
||||
<i data-lucide="arrow-right" class="icon"></i>
|
||||
立即使用 Web 版
|
||||
</a>
|
||||
</div>
|
||||
<b id="detect-name">Web 版</b>
|
||||
<span id="detect-desc">已自动识别你的设备,推荐以下版本。</span>
|
||||
</div>
|
||||
<a class="btn primary" id="detect-btn" href="{{ site.appBaseUrl }}/app/"><span>立即使用</span></a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- ============================== 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 版、Windows / macOS 桌面版与 Android 客户端现已可用,iOS 正在开发中。</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="{{ site.appBaseUrl }}/app/" class="dl-card-btn primary">
|
||||
<i data-lucide="arrow-right" class="icon"></i>立即使用
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Windows -->
|
||||
<div class="dl-card" 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">原生桌面客户端,支持 Win 10/11(64 位),离线模式与本地打印。</p>
|
||||
<span class="dl-status available">✓ 已支持</span>
|
||||
<a href="#" class="dl-card-btn primary" id="windows-dl-btn">
|
||||
<i data-lucide="download" class="icon"></i>下载 Windows 版
|
||||
</a>
|
||||
<div class="icbox ic-info"><svg class="ic"><use href="#i-ic63"/></svg></div>
|
||||
<h3>Windows</h3>
|
||||
<div class="req">Win 10 / 11(64 位)</div>
|
||||
<div class="dl-status">✓ 安装包</div>
|
||||
<a class="btn primary" id="windows-dl-btn" href="{{ site.appBaseUrl }}/downloads/jiu-windows-x64-setup.exe"><svg class="ic" style="width:15px;height:15px"><use href="#i-download"/></svg>下载</a>
|
||||
</div>
|
||||
|
||||
<!-- macOS -->
|
||||
<div class="dl-card" 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 available">✓ 已支持</span>
|
||||
<a href="#" class="dl-card-btn primary" id="macos-dl-btn">
|
||||
<i data-lucide="download" class="icon"></i>下载 macOS 版
|
||||
</a>
|
||||
<div class="icbox ic-info"><svg class="ic"><use href="#i-ic25"/></svg></div>
|
||||
<h3>macOS</h3>
|
||||
<div class="req">Apple Silicon / Intel</div>
|
||||
<div class="dl-status">✓ 已签名公证</div>
|
||||
<a class="btn primary" id="macos-dl-btn" href="{{ site.appBaseUrl }}/downloads/jiu-macos-x64.zip"><svg class="ic" style="width:15px;height:15px"><use href="#i-download"/></svg>下载</a>
|
||||
</div>
|
||||
|
||||
<!-- iOS -->
|
||||
<div class="dl-card coming-soon" data-platform="ios" id="ios-card">
|
||||
<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 通用,通过 TestFlight 安装。</p>
|
||||
<span class="dl-status soon" id="ios-status">敬请期待</span>
|
||||
<a href="#" class="dl-card-btn disabled" id="ios-dl-btn">
|
||||
<i data-lucide="clock" class="icon"></i><span>即将推出</span>
|
||||
</a>
|
||||
<div class="dl-card" data-platform="web">
|
||||
<div class="icbox ic-ok"><svg class="ic"><use href="#i-ic01"/></svg></div>
|
||||
<h3>Web 版</h3>
|
||||
<div class="req">现代浏览器均可</div>
|
||||
<div class="dl-status">✓ 免安装</div>
|
||||
<a class="btn primary" href="{{ site.appBaseUrl }}/app/">立即使用</a>
|
||||
</div>
|
||||
|
||||
<!-- Android -->
|
||||
<div class="dl-card" 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 直接安装,支持 Android 6.0 及以上。</p>
|
||||
<span class="dl-status available">✓ 已支持</span>
|
||||
<a href="#" class="dl-card-btn primary" id="android-dl-btn">
|
||||
<i data-lucide="download" class="icon"></i>下载 Android 版
|
||||
</a>
|
||||
<div class="icbox ic-warn"><svg class="ic"><use href="#i-ic43"/></svg></div>
|
||||
<h3>Android</h3>
|
||||
<div class="req">Android 6.0 及以上</div>
|
||||
<div class="dl-status">✓ APK 直装</div>
|
||||
<a class="btn primary" id="android-dl-btn" href="{{ site.appBaseUrl }}/downloads/jiu-android.apk"><svg class="ic" style="width:15px;height:15px"><use href="#i-download"/></svg>下载</a>
|
||||
</div>
|
||||
<div class="dl-card" data-platform="ios" id="ios-card">
|
||||
<div class="icbox ic-wine"><svg class="ic"><use href="#i-ic22"/></svg></div>
|
||||
<h3>iOS</h3>
|
||||
<div class="req">iPhone / iPad</div>
|
||||
<div class="dl-status soon" id="ios-status">TestFlight 内测中</div>
|
||||
<a class="btn ghost disabled" id="ios-dl-btn" href="#">敬请期待</a>
|
||||
</div>
|
||||
</div>
|
||||
<p style="text-align:center;color:var(--faint);font-size:var(--fs-sm);margin-top:18px">
|
||||
桌面与移动客户端内置自动更新 · 各端详细配置见<a href="/system-requirements/">系统要求</a>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================== SYSTEM REQUIREMENTS ============================== -->
|
||||
<section class="section bg-25">
|
||||
<section class="section alt" id="changelog">
|
||||
<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 class="sec-head">
|
||||
<div class="eyebrow">更新日志</div>
|
||||
<h2>最近更新</h2>
|
||||
<p id="changelog-count">最近 {{ changelog | length }} 个版本。</p>
|
||||
</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" id="changelog-count">最近 {{ changelog | length }} 个版本。</p>
|
||||
|
||||
<div class="changelog" id="changelog-list">
|
||||
{% for entry in changelog %}
|
||||
<div class="changelog-entry{% if loop.first %} current{% endif %}">
|
||||
@@ -401,27 +117,14 @@ pageStyle: |
|
||||
{% 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 %}
|
||||
{% 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 %}
|
||||
<span class="dot {% if section.type == '新功能' %}dot-feature{% elif section.type == '修复' %}dot-fix{% else %}dot-improve{% endif %}"></span>
|
||||
{{ section.type }}
|
||||
</div>
|
||||
<ul>
|
||||
{% for item in section.items %}
|
||||
<li>{{ item }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<ul>{% for item in section.items %}<li>{{ item }}</li>{% endfor %}</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -434,12 +137,13 @@ pageStyle: |
|
||||
<script>
|
||||
(function() {
|
||||
var APP_BASE = '{{ site.appBaseUrl }}';
|
||||
var SPRITE = { web:'#i-ic01', ios:'#i-ic22', android:'#i-ic43', windows:'#i-ic63', macos:'#i-ic25' };
|
||||
var platforms = {
|
||||
web: { name: 'Web 版', desc: '浏览器直接访问,功能完整,无需下载安装。', icon: 'globe', btnText: '立即使用 Web 版', btnHref: APP_BASE + '/app/', available: true },
|
||||
ios: { name: 'iOS', desc: 'iPhone 与 iPad 通用,通过 TestFlight 安装。', icon: 'smartphone', btnText: '敬请期待', available: false },
|
||||
android: { name: 'Android', desc: '手机与平板通用,APK 直接安装,支持 Android 6.0 及以上。', icon: 'tablet-smartphone', btnText: '下载 Android 版', btnHref: '#', available: true },
|
||||
windows: { name: 'Windows 桌面', desc: '原生桌面客户端,支持 Win 10/11(64 位),离线模式与本地打印。', icon: 'monitor', btnText: '下载 Windows 版', btnHref: '#', available: true },
|
||||
macos: { name: 'macOS 桌面', desc: '支持 Apple Silicon 与 Intel,解压即用,首次运行右键→打开。', icon: 'laptop', btnText: '下载 macOS 版', btnHref: '#', available: true }
|
||||
web: { name: 'Web 版', desc: '浏览器直接访问,功能完整,无需下载安装。', btnText: '立即使用 Web 版', btnHref: APP_BASE + '/app/', available: true },
|
||||
ios: { name: 'iOS', desc: 'iPhone 与 iPad 通用,通过 TestFlight 安装。', btnText: '敬请期待', available: false },
|
||||
android: { name: 'Android', desc: '手机与平板通用,APK 直接安装。', btnText: '下载 Android 版', btnHref: APP_BASE + '/downloads/jiu-android.apk', available: true },
|
||||
windows: { name: 'Windows 桌面', desc: '原生桌面客户端,支持 Win 10/11(64 位)与本地打印。', btnText: '下载 Windows 版', btnHref: APP_BASE + '/downloads/jiu-windows-x64-setup.exe', available: true },
|
||||
macos: { name: 'macOS 桌面', desc: '支持 Apple Silicon 与 Intel,解压即用。', btnText: '下载 macOS 版', btnHref: APP_BASE + '/downloads/jiu-macos-x64.zip', available: true }
|
||||
};
|
||||
|
||||
function detectPlatform() {
|
||||
@@ -461,27 +165,18 @@ pageStyle: |
|
||||
if (nameEl) nameEl.textContent = info.name;
|
||||
if (descEl) descEl.textContent = info.desc;
|
||||
if (btnEl) {
|
||||
if (info.available) {
|
||||
if (info.available && info.btnHref && info.btnHref !== '#') {
|
||||
btnEl.href = info.btnHref;
|
||||
btnEl.style.opacity = '';
|
||||
btnEl.style.pointerEvents = '';
|
||||
btnEl.querySelector('span') && (btnEl.querySelector('span').textContent = info.btnText);
|
||||
} else {
|
||||
btnEl.classList.remove('disabled');
|
||||
btnEl.innerHTML = '<span>' + info.btnText + '</span>';
|
||||
} else if (!info.available) {
|
||||
btnEl.href = '#';
|
||||
btnEl.style.opacity = '0.5';
|
||||
btnEl.style.pointerEvents = 'none';
|
||||
btnEl.classList.add('disabled');
|
||||
btnEl.innerHTML = '<span>' + info.btnText + '</span>';
|
||||
}
|
||||
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();
|
||||
if (iconEl) {
|
||||
iconEl.innerHTML = '<svg class="ic"><use href="' + (SPRITE[p] || '#i-ic01') + '"/></svg>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,13 +194,11 @@ pageStyle: |
|
||||
});
|
||||
}
|
||||
|
||||
// 用 /api/v1/public/release 返回的 changelog 重渲染更新日志时间线,使客户端
|
||||
// 发版无需重建官网即可同步。结构与构建时 web/_data/changelog.js 一致;接口
|
||||
// 不可达或字段缺失时保留构建时静态时间线作 fallback。
|
||||
// 用 /api/v1/public/release 的 changelog 重渲染时间线:客户端发版无需重建官网。
|
||||
// 接口不可达或字段缺失时保留构建时静态时间线作 fallback。
|
||||
function renderChangelog(entries) {
|
||||
if (!Array.isArray(entries) || entries.length === 0) return;
|
||||
var dotClass = { '新功能': 'dot-feature', '改进': 'dot-improve', '修复': 'dot-fix' };
|
||||
var label = { '修复': '问题修复' };
|
||||
function esc(s) {
|
||||
return String(s == null ? '' : s).replace(/[&<>"]/g, function(c) {
|
||||
return { '&': '&', '<': '<', '>': '>', '"': '"' }[c];
|
||||
@@ -513,22 +206,16 @@ pageStyle: |
|
||||
}
|
||||
var html = '';
|
||||
entries.forEach(function(entry, i) {
|
||||
var current = i === 0;
|
||||
html += '<div class="changelog-entry' + (current ? ' current' : '') + '">';
|
||||
html += '<div class="changelog-meta">';
|
||||
html += '<div class="changelog-version">v' + esc(entry.version) + '</div>';
|
||||
html += '<div class="changelog-entry' + (i === 0 ? ' current' : '') + '">';
|
||||
html += '<div class="changelog-meta"><div class="changelog-version">v' + esc(entry.version) + '</div>';
|
||||
html += '<div class="changelog-date">' + esc(entry.date) + '</div>';
|
||||
if (current) html += '<span class="changelog-tag">当前版本</span>';
|
||||
if (i === 0) html += '<span class="changelog-tag">当前版本</span>';
|
||||
html += '</div><div class="changelog-body">';
|
||||
if (entry.intro) html += '<p class="changelog-intro">' + esc(entry.intro) + '</p>';
|
||||
(entry.sections || []).forEach(function(section) {
|
||||
var dot = dotClass[section.type] || 'dot-improve';
|
||||
var name = label[section.type] || section.type;
|
||||
html += '<div class="changelog-cat"><div class="changelog-cat-label">';
|
||||
html += '<span class="dot ' + dot + '"></span>' + esc(name) + '</div><ul>';
|
||||
(section.items || []).forEach(function(item) {
|
||||
html += '<li>' + esc(item) + '</li>';
|
||||
});
|
||||
html += '<div class="changelog-cat"><div class="changelog-cat-label"><span class="dot ' + dot + '"></span>' + esc(section.type) + '</div><ul>';
|
||||
(section.items || []).forEach(function(item) { html += '<li>' + esc(item) + '</li>'; });
|
||||
html += '</ul></div>';
|
||||
});
|
||||
html += '</div></div>';
|
||||
@@ -544,63 +231,50 @@ pageStyle: |
|
||||
updateDetectCard(detected);
|
||||
highlightPlatformCard(detected);
|
||||
|
||||
fetch('{{ site.appBaseUrl }}/api/v1/public/release')
|
||||
fetch(APP_BASE + '/api/v1/public/release')
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
if (data && data.version) updateVersionBadges(data.version);
|
||||
if (data && data.changelog) renderChangelog(data.changelog);
|
||||
if (data && data.download_urls && data.download_urls.macos) {
|
||||
platforms.macos.btnHref = data.download_urls.macos;
|
||||
var macBtn = document.getElementById('macos-dl-btn');
|
||||
if (macBtn) macBtn.href = data.download_urls.macos;
|
||||
if (detected === 'macos') updateDetectCard(detected);
|
||||
}
|
||||
if (data && data.download_urls && data.download_urls.windows) {
|
||||
platforms.windows.btnHref = data.download_urls.windows;
|
||||
var btn = document.getElementById('windows-dl-btn');
|
||||
if (btn) btn.href = data.download_urls.windows;
|
||||
if (detected === 'windows') updateDetectCard(detected);
|
||||
}
|
||||
if (data && data.download_urls && data.download_urls.android) {
|
||||
platforms.android.btnHref = data.download_urls.android;
|
||||
var andBtn = document.getElementById('android-dl-btn');
|
||||
if (andBtn) andBtn.href = data.download_urls.android;
|
||||
if (detected === 'android') updateDetectCard(detected);
|
||||
}
|
||||
// iOS 走 TestFlight:仅当配置了公开 TestFlight 链接时激活卡片
|
||||
if (data && data.download_urls && data.download_urls.ios) {
|
||||
var urls = (data && data.download_urls) || {};
|
||||
[['macos','macos-dl-btn'],['windows','windows-dl-btn'],['android','android-dl-btn']].forEach(function(pair) {
|
||||
if (urls[pair[0]]) {
|
||||
platforms[pair[0]].btnHref = urls[pair[0]];
|
||||
var btn = document.getElementById(pair[1]);
|
||||
if (btn) btn.href = urls[pair[0]];
|
||||
if (detected === pair[0]) updateDetectCard(detected);
|
||||
}
|
||||
});
|
||||
// iOS 走 TestFlight:仅当返回公开链接时激活
|
||||
if (urls.ios) {
|
||||
platforms.ios.available = true;
|
||||
platforms.ios.btnHref = data.download_urls.ios;
|
||||
platforms.ios.btnHref = urls.ios;
|
||||
platforms.ios.btnText = '通过 TestFlight 安装';
|
||||
var iosCard = document.getElementById('ios-card');
|
||||
var iosStatus = document.getElementById('ios-status');
|
||||
var iosBtn = document.getElementById('ios-dl-btn');
|
||||
if (iosCard) iosCard.classList.remove('coming-soon');
|
||||
if (iosStatus) { iosStatus.className = 'dl-status available'; iosStatus.textContent = '✓ 已上线'; }
|
||||
if (iosStatus) { iosStatus.className = 'dl-status'; iosStatus.textContent = '✓ 已上线'; }
|
||||
if (iosBtn) {
|
||||
iosBtn.className = 'dl-card-btn primary';
|
||||
iosBtn.href = data.download_urls.ios;
|
||||
iosBtn.className = 'btn primary';
|
||||
iosBtn.href = urls.ios;
|
||||
iosBtn.target = '_blank';
|
||||
iosBtn.rel = 'noopener';
|
||||
iosBtn.innerHTML = '<i data-lucide="download" class="icon"></i>通过 TestFlight 安装';
|
||||
if (window.lucide) lucide.createIcons();
|
||||
iosBtn.textContent = 'TestFlight 安装';
|
||||
}
|
||||
if (detected === 'ios') updateDetectCard(detected);
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
// API 不可达时,将仍为 href="#" 的下载按钮改为禁用态
|
||||
['windows-dl-btn', 'macos-dl-btn', 'android-dl-btn'].forEach(function(id) {
|
||||
var btn = document.getElementById(id);
|
||||
if (btn && btn.getAttribute('href') === '#') {
|
||||
btn.className = 'dl-card-btn disabled';
|
||||
btn.innerHTML = '暂时无法获取下载地址';
|
||||
btn.className = 'btn ghost disabled';
|
||||
btn.textContent = '暂时无法获取下载地址';
|
||||
}
|
||||
});
|
||||
var detectBtn = document.getElementById('detect-btn');
|
||||
if (detectBtn && detectBtn.getAttribute('href') === '#') {
|
||||
detectBtn.className = 'btn btn-secondary btn-lg';
|
||||
detectBtn.innerHTML = '暂时无法连接服务器';
|
||||
detectBtn.classList.add('disabled');
|
||||
detectBtn.innerHTML = '<span>暂时无法连接服务器</span>';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,646 +1,291 @@
|
||||
---
|
||||
layout: base.njk
|
||||
title: 为酒行与酒店设计的库存管理平台
|
||||
description: 岩美酒库管理系统,审核驱动业务流,库存与账款自动同步,五端无缝接入。
|
||||
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; }
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
/* Hide decorative app preview on mobile to prevent overflow */
|
||||
.preview-shell { display: none; }
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.hero h1 { font-size: 28px; }
|
||||
.hero p.lead { font-size: var(--text-md); }
|
||||
.hero-cta { flex-direction: column; }
|
||||
.hero-cta .btn { width: 100%; justify-content: center; }
|
||||
.module-card.feature-card { grid-column: span 1; }
|
||||
.roles-row { grid-template-columns: 1fr; }
|
||||
.roles-table .roles-row > *:nth-child(n+3) { display: none; }
|
||||
}
|
||||
</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">v{{ changelog[0].version }}</span>
|
||||
<span>{{ changelog[0].date }} 更新 ·</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="/register/" class="btn btn-primary btn-lg">免费试用 30 天<i data-lucide="arrow-right" class="icon"></i></a>
|
||||
<a href="/docs/" class="btn btn-secondary btn-lg"><i data-lucide="book-open" 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>
|
||||
{# ============ Hero(品牌渐变 = App 登录页品牌面板同源,真实截图) ============ #}
|
||||
<header class="hero">
|
||||
<div class="hero-in">
|
||||
<div class="badge-line">
|
||||
<b>v{{ changelog[0].version }}</b> · {{ changelog[0].date }} 更新
|
||||
<a href="/download/#changelog" style="color:inherit;text-decoration:underline">查看更新日志</a>
|
||||
</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>
|
||||
<h1>每一瓶酒一个编号,<br/>从入库到利润一套系统管到底。</h1>
|
||||
<p class="lead">岩美酒库管理系统,为酒行与酒店设计的库存、审核、财务一体化平台。序列号级追溯、审核驱动业务流、成本售价利润实时可见,五端无缝接入。</p>
|
||||
<div class="cta-row">
|
||||
<a class="btn primary lg" href="/register/">免费试用 30 天</a>
|
||||
<a class="btn onhero lg" href="/docs/">查看使用手册</a>
|
||||
</div>
|
||||
<div class="mini">
|
||||
<span><svg class="ic" style="width:14px;height:14px"><use href="#i-check"/></svg>无需绑卡</span>
|
||||
<span><svg class="ic" style="width:14px;height:14px"><use href="#i-check"/></svg>Web 版免安装</span>
|
||||
<span><svg class="ic" style="width:14px;height:14px"><use href="#i-check"/></svg>数据多租户隔离</span>
|
||||
<span><svg class="ic" style="width:14px;height:14px"><use href="#i-check"/></svg>HTTPS 全程加密</span>
|
||||
</div>
|
||||
<div class="shot"><img src="/assets/shots/inventory_list.png" alt="库存管理界面 — 真实产品截图" loading="eager" /></div>
|
||||
</div>
|
||||
</section>
|
||||
</header>
|
||||
|
||||
<!-- ====================== TRUST ====================== -->
|
||||
<section class="trust">
|
||||
<div class="container">
|
||||
<div class="trust-grid">
|
||||
<div class="fs-sm text-muted">专为酒水经营场所设计</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 class="trust-stat-num">多<sup>仓</sup></div><div class="fs-xs text-muted mt-4">支持多仓库独立管理</div></div>
|
||||
<div><div class="trust-stat-num">FIFO</div><div class="fs-xs text-muted mt-4">批次先进先出追溯</div></div>
|
||||
<div><div class="trust-stat-num">0</div><div class="fs-xs text-muted mt-4">需安装依赖,Web 即用</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>
|
||||
<a href="/features/approval.html" class="fs-xs text-brand mt-12 d-inline-block">了解审核流详情 →</a>
|
||||
<div class="sec-head">
|
||||
<div class="eyebrow">核心模块</div>
|
||||
<h2>全流程覆盖酒水经营的每一个环节</h2>
|
||||
<p>从供应商进货到客户出库,从批次库存到应收应付,一个系统闭环。</p>
|
||||
</div>
|
||||
<div class="grid c4">
|
||||
<div class="card feature">
|
||||
<div class="icbox ic-info"><svg class="ic"><use href="#i-download"/></svg></div>
|
||||
<h3>入库管理</h3>
|
||||
<p>键盘流内联录单,名称/系列/规格边搜边建;进价可暂估、事后确认自动回填成本与应付。</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-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 class="card feature">
|
||||
<div class="icbox ic-info"><svg class="ic"><use href="#i-upload"/></svg></div>
|
||||
<h3>出库管理</h3>
|
||||
<p>从库存选货自动带出可用数量与参考售价,每行利润实时计算;支持先出库后定价。</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>
|
||||
<a href="/features/inventory.html" class="fs-xs text-brand mt-12 d-inline-block">了解更多 →</a>
|
||||
<div class="card feature">
|
||||
<div class="icbox ic-ok"><svg class="ic"><use href="#i-box"/></svg></div>
|
||||
<h3>批次库存</h3>
|
||||
<p>每瓶酒独立编号、每批独立成本,库存货值实时汇总;盘点单一键对平账实差异。</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 class="card feature">
|
||||
<div class="icbox ic-ok"><svg class="ic"><use href="#i-ic47"/></svg></div>
|
||||
<h3>财务管理</h3>
|
||||
<p>应收应付按往来单位自动挂账,收支趋势一图看清;结清、退单自动冲账。</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 class="card feature">
|
||||
<div class="icbox ic-wine"><svg class="ic"><use href="#i-ic56"/></svg></div>
|
||||
<h3>往来单位</h3>
|
||||
<p>供应商与客户统一管理,拼音首字母秒搜;每家单位的历史单据与欠款一屏尽览。</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 class="card feature">
|
||||
<div class="icbox ic-wine"><svg class="ic"><use href="#i-ic57"/></svg></div>
|
||||
<h3>基础数据</h3>
|
||||
<p>品牌/型号/版本字典化维护,录单下拉即选;商品图片、介绍库集中管理。</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 class="card feature">
|
||||
<div class="icbox ic-warn"><svg class="ic"><use href="#i-ic31"/></svg></div>
|
||||
<h3>扫码看详情</h3>
|
||||
<p>每瓶酒可打印专属二维码标签,扫码直达商品详情页,链接随手分享给顾客与同行。</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="qr-code" 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 class="card feature">
|
||||
<div class="icbox ic-warn"><svg class="ic"><use href="#i-gear"/></svg></div>
|
||||
<h3>门店设置</h3>
|
||||
<p>四级角色权限、在线设备管理与强制下线、单号规则、三套界面主题随心切换。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== WORKFLOW ====================== -->
|
||||
<section class="section bg-25" id="workflow">
|
||||
{# ============ 审核驱动业务流 ============ #}
|
||||
<section class="section alt" 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 class="sec-head">
|
||||
<div class="eyebrow">审核驱动</div>
|
||||
<h2>每一笔出入库,都要过审核这道关</h2>
|
||||
<p>草稿随便改,审核过了才动库存与账款——录错不怕,责任清晰。</p>
|
||||
</div>
|
||||
<div class="flow">
|
||||
<div class="step"><div class="num">1</div><b>草稿</b><span>操作员录单,可反复修改、复制行、暂估价</span></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="step"><div class="num">2</div><b>提交审核</b><span>单据锁定进入待审核,支持撤回修改</span></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="step"><div class="num">3</div><b>审核通过</b><span>同一事务更新库存并写入流水、挂应收应付</span></div>
|
||||
<div class="arrow">→</div>
|
||||
<div class="step"><div class="num">4</div><b>事后可纠</b><span>退单自动回滚库存与账款,确认进价/售价按差额补账</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# ============ 定价与利润 ============ #}
|
||||
<section class="section">
|
||||
<div class="container split">
|
||||
<div>
|
||||
<div class="sec-head" style="text-align:left;margin:0 0 8px">
|
||||
<div class="eyebrow" style="justify-content:flex-start">经营看得清</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>
|
||||
<h2>成本、售价、利润,<br/>每一单算得明明白白</h2>
|
||||
<div class="pts">
|
||||
<div class="pt"><div class="icbox ic-ok"><svg class="ic"><use href="#i-ic47"/></svg></div>
|
||||
<div><b>建单即见利润</b><span>出库录单时每行利润实时计算,合计利润随手可见。</span></div></div>
|
||||
<div class="pt"><div class="icbox ic-info"><svg class="ic"><use href="#i-ic03"/></svg></div>
|
||||
<div><b>成本仅管理员可见</b><span>操作员只看到售价,成本与利润在服务端就被隔离。</span></div></div>
|
||||
<div class="pt"><div class="icbox ic-warn"><svg class="ic"><use href="#i-ic04"/></svg></div>
|
||||
<div><b>先出库后定价</b><span>急单先走货,售价确定后一键补录,应收自动按差额调整。</span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="shot"><img src="/assets/shots/stock_out_list.png" alt="出库管理 — 真实产品截图" loading="lazy" /></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# ============ 财务 ============ #}
|
||||
<section class="section alt">
|
||||
<div class="container split">
|
||||
<div class="shot"><img src="/assets/shots/finance.png" alt="财务管理 — 真实产品截图" loading="lazy" /></div>
|
||||
<div>
|
||||
<div class="sec-head" style="text-align:left;margin:0 0 8px">
|
||||
<div class="eyebrow" style="justify-content:flex-start">账款不再靠记</div>
|
||||
</div>
|
||||
<h2>应收应付自动挂账,<br/>收支趋势一图看清</h2>
|
||||
<div class="pts">
|
||||
<div class="pt"><div class="icbox ic-info"><svg class="ic"><use href="#i-ic07"/></svg></div>
|
||||
<div><b>出入库自动记账</b><span>审核通过即挂应收/应付,退单自动冲账,无需二次录入。</span></div></div>
|
||||
<div class="pt"><div class="icbox ic-ok"><svg class="ic"><use href="#i-ic08"/></svg></div>
|
||||
<div><b>按往来单位对账</b><span>每家供应商、每个客户的未结清金额与流水随点随查。</span></div></div>
|
||||
<div class="pt"><div class="icbox ic-wine"><svg class="ic"><use href="#i-ic16"/></svg></div>
|
||||
<div><b>近 30 天滚动口径</b><span>销售、采购、待审核、草稿等经营指标环比一望即知。</span></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">TestFlight 内测中</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 class="sec-head">
|
||||
<div class="eyebrow">多端同步</div>
|
||||
<h2>一个账号,五端同步</h2>
|
||||
<p>店里用 Windows 收银机、仓库用手机、老板在家用 Mac——数据实时一致。</p>
|
||||
</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="layout-grid" class="icon"></i>窄屏自动切换卡片流布局</div>
|
||||
<div class="pv-feature"><i data-lucide="camera" 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 class="grid plat5">
|
||||
<div class="card feature" style="text-align:center"><div class="icbox ic-info" style="margin:0 auto 12px"><svg class="ic"><use href="#i-ic63"/></svg></div><h3>Windows</h3><p>安装包一键装机</p></div>
|
||||
<div class="card feature" style="text-align:center"><div class="icbox ic-info" style="margin:0 auto 12px"><svg class="ic"><use href="#i-ic25"/></svg></div><h3>macOS</h3><p>已签名公证</p></div>
|
||||
<div class="card feature" style="text-align:center"><div class="icbox ic-ok" style="margin:0 auto 12px"><svg class="ic"><use href="#i-ic01"/></svg></div><h3>Web 版</h3><p>浏览器直接用,零安装</p></div>
|
||||
<div class="card feature" style="text-align:center"><div class="icbox ic-warn" style="margin:0 auto 12px"><svg class="ic"><use href="#i-ic43"/></svg></div><h3>Android</h3><p>APK 直装</p></div>
|
||||
<div class="card feature" style="text-align:center"><div class="icbox ic-wine" style="margin:0 auto 12px"><svg class="ic"><use href="#i-ic22"/></svg></div><h3>iOS</h3><p>TestFlight 内测中</p></div>
|
||||
</div>
|
||||
<div style="text-align:center;margin-top:28px"><a class="btn primary" href="/download/">前往下载 <svg class="ic" style="width:15px;height:15px"><use href="#i-chevron-right"/></svg></a></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== REPORTS ====================== -->
|
||||
<section class="section bg-25" id="reports">
|
||||
{# ============ 安全与权限 ============ #}
|
||||
<section class="section alt" id="security">
|
||||
<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。</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sec-head">
|
||||
<div class="eyebrow">安全与权限</div>
|
||||
<h2>四级角色,数据各归其位</h2>
|
||||
<p>多租户隔离、HTTPS 全程加密、登录设备可管控,敏感经营数据只给该看的人。</p>
|
||||
</div>
|
||||
<table class="roles">
|
||||
<thead><tr><th>能力</th><th>超级管理员</th><th>管理员</th><th>操作员</th><th>只读</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>录单 / 提交审核</td><td class="y">✓</td><td class="y">✓</td><td class="y">✓</td><td class="n">—</td></tr>
|
||||
<tr><td>审核 / 退单 / 确认价格</td><td class="y">✓</td><td class="y">✓</td><td class="n">—</td><td class="n">—</td></tr>
|
||||
<tr><td>查看成本与利润</td><td class="y">✓</td><td class="y">✓</td><td class="n">—</td><td class="n">—</td></tr>
|
||||
<tr><td>用户与设备管理</td><td class="y">✓</td><td class="y">✓</td><td class="n">—</td><td class="n">—</td></tr>
|
||||
<tr><td>查看单据与库存</td><td class="y">✓</td><td class="y">✓</td><td class="y">✓</td><td class="y">✓</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</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>
|
||||
<div class="sec-head">
|
||||
<div class="eyebrow">价格方案</div>
|
||||
<h2>按门店付费,明码标价</h2>
|
||||
<p>先免费试用,再按需选档;时长兑换券续期,无隐藏费用、无自动扣款。</p>
|
||||
</div>
|
||||
<div class="plans p4">
|
||||
<div class="plan">
|
||||
<div class="pname">免费版</div>
|
||||
<div class="price">¥0<small> / 30 天</small></div>
|
||||
<div class="psub">注册即开通,无需绑卡</div>
|
||||
<ul>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>全功能试用 30 天</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>五端同步</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>到期数据保留 90 天</li>
|
||||
</ul>
|
||||
<a href="/register/" class="btn btn-secondary w-full justify-center mt-auto">免费开通</a>
|
||||
<a class="btn ghost" data-plan="free" href="/register/">立即试用</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>
|
||||
<div class="plan hot">
|
||||
<div class="pname">标准版</div>
|
||||
<div class="price">¥299<small> / 月</small></div>
|
||||
<div class="psub">年付 ¥2,999,立省两个月</div>
|
||||
<ul>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>单门店 · 单仓库</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>2 台客户端同时使用</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>1,000 张商品图片分享</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>扫码详情分享 + 标签打印</li>
|
||||
</ul>
|
||||
<a href="/register/" class="btn btn-primary w-full justify-center mt-auto">免费试用 30 天</a>
|
||||
<a class="btn primary" data-plan="standard" href="/register/">开通门店</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>专属实施与培训服务</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>
|
||||
<div class="plan">
|
||||
<div class="pname">高级版</div>
|
||||
<div class="price">¥599<small> / 月</small></div>
|
||||
<div class="psub">年付 ¥5,999,立省两个月</div>
|
||||
<ul>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>单门店 · 多仓库</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>5 台客户端同时使用</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>10,000 张商品图片分享</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>免费 AI 周度 / 月度商业数据分析</li>
|
||||
</ul>
|
||||
{% if site.support.wechat %}<a href="#" class="btn btn-secondary w-full justify-center mt-auto">微信咨询:{{ site.support.wechat }}</a>{% else %}<a href="mailto:{{ site.support.email }}" class="btn btn-secondary w-full justify-center mt-auto">联系销售</a>{% endif %}
|
||||
<a class="btn primary" data-plan="pro" href="/register/">开通门店</a>
|
||||
</div>
|
||||
<div class="plan">
|
||||
<div class="pname">定制版</div>
|
||||
<div class="price">定制</div>
|
||||
<div class="psub">连锁多店、私有部署、专属支持</div>
|
||||
<ul>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>多门店数据隔离</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>客户端与图片配额按需扩展</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>可私有化部署</li>
|
||||
<li><svg class="ic"><use href="#i-check"/></svg>一对一迁移协助</li>
|
||||
</ul>
|
||||
<a class="btn ghost" href="mailto:{{ site.support.email }}">联系我们</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== FAQ ====================== -->
|
||||
<section class="section bg-25" id="faq">
|
||||
{# ============ FAQ ============ #}
|
||||
<section class="section alt" 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">审批通过后操作不可撤销。如发现录入错误,可由具备权限的用户新建一张反向单据(如:误入 10 箱则再出库 10 箱)来修正库存与应收应付,审批链完整保留。</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 天到期后,升级到单店版(¥299/月)即可继续使用,已录入的数据完整保留。</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 class="sec-head">
|
||||
<div class="eyebrow">常见问题</div>
|
||||
<h2>你可能想问</h2>
|
||||
</div>
|
||||
<div class="faq">
|
||||
<details><summary>支持哪些设备和系统?</summary><p>Windows、macOS、Android、iOS(TestFlight 内测)以及免安装的 Web 版,一个账号五端数据实时同步。详见<a href="/system-requirements/">系统要求</a>。</p></details>
|
||||
<details><summary>老系统的数据能搬过来吗?</summary><p>支持 Excel 批量导入商品、往来单位、历史出入库单与库存;定制版提供一对一迁移协助。</p></details>
|
||||
<details><summary>录错单怎么办?</summary><p>草稿随时改;已提交可撤回;审核通过后支持整单或按行退单,库存与账款自动回滚——不需要手工冲账。</p></details>
|
||||
<details><summary>进货价还没谈妥能先入库吗?</summary><p>可以。进价留空按暂估入库,价格确定后用「确认进价」补录,系统自动回填库存成本、已出库成本快照与应付差额。出库同理支持先出货后定价。</p></details>
|
||||
<details><summary>店员能看到我的进货成本吗?</summary><p>不能。成本价与利润仅管理员可见,操作员的界面和接口数据都不包含成本——这是服务端级别的隔离,不是前端隐藏。</p></details>
|
||||
<details><summary>数据安全吗?</summary><p>每家门店数据完全隔离,全程 HTTPS 加密传输,登录设备可管控、可强制下线;数据库每日备份。</p></details>
|
||||
<details><summary>试用到期后数据会丢吗?</summary><p>不会。到期后进入只读模式,数据保留 90 天,兑换续期后立即恢复完整功能。</p></details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ====================== CTA ====================== -->
|
||||
<section>
|
||||
{# ============ CTA ============ #}
|
||||
<section class="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="/register/" class="btn btn-primary btn-lg">立即开通试用<i data-lucide="arrow-right" class="icon"></i></a>
|
||||
{% if site.support.wechat %}<a href="#" class="btn btn-secondary btn-lg"><i data-lucide="message-circle" class="icon"></i>微信咨询:{{ site.support.wechat }}</a>{% else %}<a href="mailto:{{ site.support.email }}?subject=咨询岩美连锁版" class="btn btn-secondary btn-lg"><i data-lucide="mail" class="icon"></i>邮件咨询</a>{% endif %}
|
||||
</div>
|
||||
<h2>用一杯咖啡的时间,看清你的酒库到底值多少钱。</h2>
|
||||
<p>30 天免费试用 · 无需绑卡 · 任何时间可取消,已录入数据保留 90 天</p>
|
||||
<a class="btn lg" style="background:#fff;color:var(--primary-dark)" href="/register/">免费注册门店</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
/* 价格区登录态:已登录(与 Web 版 App 共享 localStorage flutter.*)时,
|
||||
标准/高级按钮 → 「购买 / 续费」进 /checkout/;免费版按钮 → 「进入系统」。 */
|
||||
(function () {
|
||||
if (!localStorage.getItem('flutter.access_token')) return;
|
||||
document.querySelectorAll('[data-plan]').forEach(function (a) {
|
||||
var plan = a.dataset.plan;
|
||||
if (plan === 'free') {
|
||||
a.textContent = '进入系统';
|
||||
a.href = '/app/';
|
||||
} else {
|
||||
a.textContent = '购买 / 续费';
|
||||
a.href = '/checkout/?plan=' + plan;
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
layout: base.njk
|
||||
title: 支付结果
|
||||
description: 支付宝支付完成后的到账确认页。
|
||||
permalink: /license/result/
|
||||
---
|
||||
{# pay 回跳页(return_url,pay 拼 out_trade_no):轮询购买单状态,到账以 webhook 续期为准。 #}
|
||||
<div class="container" style="padding:64px 24px 96px">
|
||||
<div class="result" id="waiting">
|
||||
<div class="ring wait"><svg class="ic"><use href="#i-ic11"/></svg></div>
|
||||
<h2>确认到账中…</h2>
|
||||
<p>支付完成后到账通常在数秒内确认,请稍候。<br/>本页会自动刷新结果,无需手动操作。</p>
|
||||
</div>
|
||||
|
||||
<div class="result" id="ok" style="display:none">
|
||||
<div class="ring good"><svg class="ic"><use href="#i-check"/></svg></div>
|
||||
<h2>支付成功,授权已续期</h2>
|
||||
<p id="okDetail">门店授权已更新。</p>
|
||||
<div class="ono">订单号 <b id="orderNo">—</b></div>
|
||||
<div class="acts">
|
||||
<a class="btn primary lg" href="/app/">进入系统</a>
|
||||
<a class="btn ghost lg" href="/#pricing">返回套餐</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="result" id="slow" style="display:none">
|
||||
<div class="ring wait"><svg class="ic"><use href="#i-ic11"/></svg></div>
|
||||
<h2>到账确认中</h2>
|
||||
<p>付款已提交,但到账确认比平时慢一些。<br/>授权会在到账后自动续期——稍后可在 App「系统设置 → 授权」查看,无需重复付款。</p>
|
||||
<div class="acts">
|
||||
<a class="btn primary lg" href="/app/">进入系统</a>
|
||||
<a class="btn ghost lg" href="mailto:{{ site.support.email }}">联系支持</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var API = '{{ site.appBaseUrl }}';
|
||||
function $(id) { return document.getElementById(id); }
|
||||
function token() {
|
||||
var raw = localStorage.getItem('flutter.access_token');
|
||||
if (!raw) return null;
|
||||
try { return JSON.parse(raw); } catch (e) { return raw; }
|
||||
}
|
||||
var otn = new URLSearchParams(location.search).get('out_trade_no');
|
||||
if (!otn || !token()) { $('waiting').style.display = 'none'; $('slow').style.display = 'block'; return; }
|
||||
|
||||
var tries = 0, maxTries = 30; // 2s × 30 = 60s
|
||||
function poll() {
|
||||
tries++;
|
||||
fetch(API + '/api/v1/license/purchase/' + encodeURIComponent(otn), {
|
||||
headers: { 'Authorization': 'Bearer ' + token() },
|
||||
})
|
||||
.then(function (r) { return r.ok ? r.json() : null; })
|
||||
.then(function (j) {
|
||||
var d = j && j.data;
|
||||
if (d && d.status === 'paid') {
|
||||
$('orderNo').textContent = otn;
|
||||
if (d.expires_at) {
|
||||
$('okDetail').textContent = '门店授权已续期至 ' + new Date(d.expires_at).toLocaleDateString('zh-CN') + '。';
|
||||
}
|
||||
$('waiting').style.display = 'none';
|
||||
$('ok').style.display = 'block';
|
||||
return;
|
||||
}
|
||||
next();
|
||||
})
|
||||
.catch(next);
|
||||
}
|
||||
function next() {
|
||||
if (tries >= maxTries) { $('waiting').style.display = 'none'; $('slow').style.display = 'block'; return; }
|
||||
setTimeout(poll, 2000);
|
||||
}
|
||||
poll();
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
layout: base.njk
|
||||
title: 登录
|
||||
description: 登录岩美酒库管理系统。
|
||||
permalink: /login/
|
||||
---
|
||||
{# 官网内登录(不跳 App):POST /api/v1/auth/login,成功后把凭证写入与
|
||||
Web 版 App(shared_preferences_web)共享的 localStorage['flutter.*']
|
||||
(值为 JSON 编码,与插件格式一致),再进入 /app/ 即已登录。 #}
|
||||
<div class="auth-wrap">
|
||||
<div class="auth">
|
||||
<div class="auth-brand">
|
||||
<img class="mk" src="/assets/logo-mark.svg" alt="岩美酒库" />
|
||||
<div class="bname">岩美酒库</div>
|
||||
<div class="btag">酒水进销存 · 审核驱动业务流</div>
|
||||
<div class="pts">
|
||||
<div class="pt"><span class="pi"><svg class="ic"><use href="#i-box"/></svg></span>入库出库 · 审核后实时改库存</div>
|
||||
<div class="pt"><span class="pi"><svg class="ic"><use href="#i-ic08"/></svg></span>往来对账 · 财务一目了然</div>
|
||||
<div class="pt"><span class="pi"><svg class="ic"><use href="#i-ic23"/></svg></span>多端协同 · 多租户安全隔离</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="auth-form">
|
||||
<h1>登录</h1>
|
||||
<p class="alead">欢迎回来,请输入账号信息</p>
|
||||
<div class="auth-alert" id="loginErr"></div>
|
||||
<div class="field"><label>门店编号<span class="req">*</span></label><input class="input" id="shop" placeholder="例如 S000001" autocomplete="organization" /></div>
|
||||
<div class="field"><label>登录账号<span class="req">*</span></label><input class="input" id="user" placeholder="请输入登录账号" autocomplete="username" /></div>
|
||||
<div class="field"><label>密码<span class="req">*</span></label><input class="input" id="pass" type="password" placeholder="请输入密码" autocomplete="current-password" /></div>
|
||||
<button class="btn primary lg" id="loginBtn" style="margin-top:8px">登 录</button>
|
||||
<div class="auth-foot">还没有门店账号?<a href="/register/" style="font-weight:600">注册新门店 →</a></div>
|
||||
<div class="auth-foot" style="margin-top:6px;color:var(--faint);font-size:var(--fs-xs)">岩美酒库 © 2026 · 仅授权门店可登录</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var API = '{{ site.appBaseUrl }}';
|
||||
function $(id) { return document.getElementById(id); }
|
||||
function showErr(msg) { var el = $('loginErr'); el.textContent = msg; el.classList.add('show'); }
|
||||
|
||||
// 与 shared_preferences_web 同格式(值 JSON 编码),Web 版 App 可直接恢复会话
|
||||
function persist(data, shopNo) {
|
||||
var u = data.user || {};
|
||||
var kv = {
|
||||
access_token: data.access_token, refresh_token: data.refresh_token,
|
||||
user_id: u.id || 0, username: u.username || '', real_name: u.real_name || '',
|
||||
shop_no: shopNo, shop_id: String(data.shop_id || ''), role: u.role || 'operator',
|
||||
};
|
||||
Object.keys(kv).forEach(function (k) {
|
||||
localStorage.setItem('flutter.' + k, JSON.stringify(kv[k]));
|
||||
});
|
||||
}
|
||||
|
||||
function doLogin() {
|
||||
var shop = $('shop').value.trim(), user = $('user').value.trim(), pass = $('pass').value;
|
||||
if (!shop) return showErr('请输入门店编号');
|
||||
if (!user) return showErr('请输入登录账号');
|
||||
if (!pass) return showErr('请输入密码');
|
||||
$('loginErr').classList.remove('show');
|
||||
var btn = $('loginBtn'); btn.disabled = true; btn.textContent = '登录中…';
|
||||
fetch(API + '/api/v1/auth/login', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ shop_code: shop, username: user, password: pass }),
|
||||
})
|
||||
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); })
|
||||
.then(function (res) {
|
||||
if (!res.ok) throw new Error((res.j && res.j.error) || '登录失败,请检查账号信息');
|
||||
persist(res.j.data || {}, shop);
|
||||
// ?next= 仅允许站内路径(防开放跳转)
|
||||
var next = new URLSearchParams(location.search).get('next') || '';
|
||||
location.href = (next.charAt(0) === '/' && next.indexOf('//') !== 0) ? next : '/app/';
|
||||
})
|
||||
.catch(function (e) {
|
||||
showErr(e && e.message ? e.message : '无法连接服务器,请稍后重试');
|
||||
btn.disabled = false; btn.textContent = '登 录';
|
||||
});
|
||||
}
|
||||
$('loginBtn').addEventListener('click', doLogin);
|
||||
['shop', 'user', 'pass'].forEach(function (id) {
|
||||
$(id).addEventListener('keydown', function (e) { if (e.key === 'Enter') doLogin(); });
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@@ -1,327 +1,110 @@
|
||||
---
|
||||
layout: base.njk
|
||||
title: 注册新门店
|
||||
description: 填写门店信息,创建岩美酒库管理账户,注册完成后获取门店编码用于登录客户端。
|
||||
pageStyle: |
|
||||
.reg-page { padding: var(--space-16) 0 var(--space-24); }
|
||||
.reg-wrap { max-width: 640px; margin: 0 auto; padding: 0 var(--space-4); }
|
||||
.reg-hero { text-align: center; margin-bottom: var(--space-8); }
|
||||
.reg-hero h1 { font-size: var(--text-3xl); font-weight: 700; margin-bottom: var(--space-2); }
|
||||
.reg-hero p { color: var(--neutral-500); font-size: var(--text-md); max-width: 480px; margin: 0 auto; }
|
||||
.reg-card { background: var(--neutral-0); border: 1px solid var(--neutral-200); border-radius: var(--radius-xl); padding: var(--space-8); }
|
||||
.reg-fieldset { border: none; padding: 0; margin: 0 0 var(--space-8); }
|
||||
.reg-legend { font-size: var(--text-sm); font-weight: 600; color: var(--neutral-500); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: var(--space-5); padding-bottom: var(--space-3); border-bottom: 1px solid var(--neutral-100); display: block; width: 100%; }
|
||||
.form-row { margin-bottom: var(--space-5); }
|
||||
.form-label { display: block; font-size: var(--text-sm); font-weight: 500; color: var(--neutral-700); margin-bottom: var(--space-1-5); }
|
||||
.form-label .req { color: var(--error-500); margin-left: 2px; }
|
||||
.form-input, .form-textarea { width: 100%; padding: var(--space-2-5) var(--space-3); border: 1.5px solid var(--neutral-300); border-radius: var(--radius-md); font-size: var(--text-md); font-family: inherit; background: var(--neutral-0); color: var(--neutral-900); transition: border-color .15s, box-shadow .15s; box-sizing: border-box; }
|
||||
.form-input:focus, .form-textarea:focus { outline: none; border-color: var(--brand-500); box-shadow: 0 0 0 3px var(--brand-100); }
|
||||
.form-input.error, .form-textarea.error { border-color: var(--error-500); box-shadow: 0 0 0 3px rgba(239,68,68,.12); }
|
||||
.form-textarea { resize: vertical; min-height: 80px; }
|
||||
.form-helper { font-size: var(--text-xs); color: var(--neutral-400); margin-top: var(--space-1); }
|
||||
.field-error { font-size: var(--text-xs); color: var(--error-600); margin-top: 4px; display: none; }
|
||||
.field-error.visible { display: block; }
|
||||
.reg-submit { width: 100%; padding: var(--space-3) var(--space-4); font-size: var(--text-md); font-weight: 600; margin-top: var(--space-2); }
|
||||
.reg-login-hint { text-align: center; margin-top: var(--space-4); font-size: var(--text-sm); color: var(--neutral-500); }
|
||||
.reg-login-hint a { color: var(--brand-600); }
|
||||
.reg-error { display: none; background: var(--error-50); border: 1px solid var(--error-200); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-5); font-size: var(--text-sm); color: var(--error-700); }
|
||||
.reg-error.visible { display: block; }
|
||||
.success-panel { display: none; text-align: center; }
|
||||
.success-panel.visible { display: block; }
|
||||
.success-icon { color: var(--success-500); margin-bottom: var(--space-4); }
|
||||
.success-panel h2 { font-size: var(--text-2xl); font-weight: 700; margin-bottom: var(--space-2); }
|
||||
.success-panel > p { color: var(--neutral-500); margin-bottom: var(--space-6); }
|
||||
.shop-code-box { background: var(--brand-50); border: 1px solid var(--brand-200); border-radius: var(--radius-lg); padding: var(--space-5) var(--space-6); margin-bottom: var(--space-6); display: flex; align-items: center; justify-content: center; gap: var(--space-3); }
|
||||
.shop-code-text { font-size: var(--text-3xl); font-weight: 700; font-family: 'JetBrains Mono', monospace; color: var(--brand-700); letter-spacing: 0.05em; }
|
||||
.copy-btn { display: inline-flex; align-items: center; gap: var(--space-1-5); padding: var(--space-2) var(--space-3); background: var(--brand-600); color: #fff; border: none; border-radius: var(--radius-md); font-size: var(--text-sm); font-weight: 500; cursor: pointer; transition: background .15s; }
|
||||
.copy-btn:hover { background: var(--brand-700); }
|
||||
.login-hint-card { background: var(--neutral-50); border: 1px solid var(--neutral-200); border-radius: var(--radius-md); padding: var(--space-4) var(--space-5); margin-bottom: var(--space-6); text-align: left; }
|
||||
.login-hint-card p { font-size: var(--text-sm); font-weight: 600; color: var(--neutral-600); margin-bottom: var(--space-3); }
|
||||
.login-hint-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
|
||||
.login-hint-table td { padding: var(--space-1-5) var(--space-2); }
|
||||
.login-hint-table td:first-child { color: var(--neutral-500); width: 80px; }
|
||||
.login-hint-table td:last-child { font-weight: 500; color: var(--neutral-800); font-family: 'JetBrains Mono', monospace; }
|
||||
.success-note { font-size: var(--text-xs); color: var(--neutral-400); margin-bottom: var(--space-6); }
|
||||
.btn-loading { opacity: .7; cursor: not-allowed; }
|
||||
description: 几分钟创建你的酒水进销存门店,注册完成后获取门店编号用于登录。
|
||||
permalink: /register/
|
||||
---
|
||||
|
||||
<section class="reg-page">
|
||||
<div class="reg-wrap">
|
||||
|
||||
<div class="reg-hero">
|
||||
<h1>注册新门店</h1>
|
||||
<p>填写以下信息,创建您的专属酒库管理账户。注册完成后系统自动分配门店编码,用于登录客户端。</p>
|
||||
</div>
|
||||
|
||||
<!-- 注册表单 -->
|
||||
<div class="reg-card" id="reg-form-card">
|
||||
<div class="reg-error" id="reg-error"></div>
|
||||
|
||||
<!-- 门店信息 -->
|
||||
<fieldset class="reg-fieldset">
|
||||
<legend class="reg-legend">门店信息</legend>
|
||||
|
||||
<div class="form-row">
|
||||
<label class="form-label" for="shop_name">店铺名称<span class="req">*</span></label>
|
||||
<input class="form-input" type="text" id="shop_name" placeholder="例:强朋友名酒行" autocomplete="organization" />
|
||||
<div class="field-error" id="err-shop_name"></div>
|
||||
<div class="form-helper">您的酒行正式名称,将显示在所有单据和商品标签上</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label class="form-label" for="address">门店地址<span class="req">*</span></label>
|
||||
<input class="form-input" type="text" id="address" placeholder="例:贵州省贵阳市云岩区中华北路 88 号" autocomplete="street-address" />
|
||||
<div class="field-error" id="err-address"></div>
|
||||
<div class="form-helper">实际经营地址,打印标签和单据时展示</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label class="form-label" for="manager_name">负责人姓名<span class="req">*</span></label>
|
||||
<input class="form-input" type="text" id="manager_name" placeholder="例:张三" autocomplete="name" />
|
||||
<div class="field-error" id="err-manager_name"></div>
|
||||
<div class="form-helper">主要负责人真实姓名,也是首个管理员账号的姓名</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label class="form-label" for="phone">联系电话<span class="req">*</span></label>
|
||||
<input class="form-input" type="tel" id="phone" placeholder="例:0851-12345678" autocomplete="tel" />
|
||||
<div class="field-error" id="err-phone"></div>
|
||||
<div class="form-helper">对外联系电话,打印商品标签时会展示</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label class="form-label" for="description">店铺简介</label>
|
||||
<textarea class="form-textarea" id="description" placeholder="简短介绍您的门店,例:专注高端白酒批发零售,主营茅台系列" maxlength="200"></textarea>
|
||||
<div class="form-helper">选填,最多 200 字;客户扫商品码时可见</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<!-- 管理员账号 -->
|
||||
<fieldset class="reg-fieldset" style="margin-bottom:0">
|
||||
<legend class="reg-legend">管理员账号</legend>
|
||||
|
||||
<div class="form-row">
|
||||
<label class="form-label" for="username">用户名<span class="req">*</span></label>
|
||||
<input class="form-input" type="text" id="username" placeholder="例:admin" autocomplete="username" />
|
||||
<div class="field-error" id="err-username"></div>
|
||||
<div class="form-helper">登录账号(3–30 位,字母/数字/下划线),创建后不可修改</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label class="form-label" for="password">密码<span class="req">*</span></label>
|
||||
<input class="form-input" type="password" id="password" placeholder="至少 6 位" autocomplete="new-password" />
|
||||
<div class="field-error" id="err-password"></div>
|
||||
<div class="form-helper">至少 6 位,建议字母数字组合</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label class="form-label" for="password_confirm">确认密码<span class="req">*</span></label>
|
||||
<input class="form-input" type="password" id="password_confirm" placeholder="再次输入密码" autocomplete="new-password" />
|
||||
<div class="field-error" id="err-password_confirm"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<button class="btn btn-primary reg-submit" id="reg-btn">
|
||||
<i data-lucide="store" class="icon"></i>
|
||||
立即注册
|
||||
</button>
|
||||
<p class="reg-login-hint">已有账号?<a href="/app/">直接登录</a></p>
|
||||
</div>
|
||||
|
||||
<!-- 注册成功面板 -->
|
||||
<div class="reg-card success-panel" id="success-panel">
|
||||
<div class="success-icon">
|
||||
<i data-lucide="check-circle" style="width:56px;height:56px;"></i>
|
||||
{# 官网内注册(不跳 App):POST /api/v1/public/register,成功显示门店编号并引导登录。
|
||||
版式与 App 注册页同款(App 真相源两栏卡片 + 三步时间线)。 #}
|
||||
<div class="auth-wrap">
|
||||
<div class="auth reg">
|
||||
<div class="auth-brand">
|
||||
<img class="mk" src="/assets/logo-mark.svg" alt="岩美酒库" style="width:60px;height:60px" />
|
||||
<div class="bname">开通门店</div>
|
||||
<div class="btag">几分钟创建你的酒水进销存门店,立即开始入库出库</div>
|
||||
<div class="steps">
|
||||
<div class="step done"><span class="si">1</span><div class="st"><b>填写门店信息</b><span>店名、地址与联系人</span></div></div>
|
||||
<div class="step"><span class="si">2</span><div class="st"><b>创建管理员账号</b><span>用于登录与管理成员</span></div></div>
|
||||
<div class="step"><span class="si">3</span><div class="st"><b>激活授权</b><span>先享 30 天试用,兑换券随时续期</span></div></div>
|
||||
</div>
|
||||
<h2>注册成功!</h2>
|
||||
<p>您的门店编码已生成,请妥善保存:</p>
|
||||
|
||||
<div class="shop-code-box">
|
||||
<span class="shop-code-text" id="result-shop-code">—</span>
|
||||
<button class="copy-btn" id="copy-code-btn">
|
||||
<i data-lucide="copy" class="icon"></i>复制
|
||||
</button>
|
||||
</div>
|
||||
<div class="auth-form">
|
||||
<div id="regForm">
|
||||
<h1>注册新门店</h1>
|
||||
<p class="alead">已有门店账号?<a href="/login/" style="font-weight:600">直接登录 →</a></p>
|
||||
<div class="auth-alert" id="regErr"></div>
|
||||
<div class="field"><label>门店名称<span class="req">*</span></label>
|
||||
<input class="input" id="shop_name" placeholder="例如 强朋友名酒行" autocomplete="organization" />
|
||||
<div class="hint">酒行正式名称,将显示在单据与商品标签上</div></div>
|
||||
<div class="grid2f">
|
||||
<div class="field"><label>联系电话<span class="req">*</span></label>
|
||||
<input class="input" id="phone" type="tel" placeholder="手机或座机" autocomplete="tel" /></div>
|
||||
<div class="field"><label>负责人姓名<span class="req">*</span></label>
|
||||
<input class="input" id="manager_name" placeholder="例如 王经理" autocomplete="name" /></div>
|
||||
</div>
|
||||
<div class="field"><label>门店地址<span class="req">*</span></label>
|
||||
<input class="input" id="address" placeholder="省 / 市 / 区 详细地址" autocomplete="street-address" /></div>
|
||||
<div class="field"><label>店铺简介</label>
|
||||
<textarea class="input" id="description" maxlength="200" placeholder="选填,最多 200 字;顾客扫商品码时可见"></textarea></div>
|
||||
<div style="height:1px;background:var(--border-subtle);margin:6px 0 16px"></div>
|
||||
<div class="field"><label>登录账号<span class="req">*</span></label>
|
||||
<input class="input" id="username" placeholder="3–30 位字母/数字/下划线" autocomplete="username" />
|
||||
<div class="hint">创建后不可修改</div></div>
|
||||
<div class="grid2f">
|
||||
<div class="field"><label>登录密码<span class="req">*</span></label>
|
||||
<input class="input" id="password" type="password" placeholder="至少 6 位" autocomplete="new-password" /></div>
|
||||
<div class="field"><label>确认密码<span class="req">*</span></label>
|
||||
<input class="input" id="password_confirm" type="password" placeholder="再次输入" autocomplete="new-password" /></div>
|
||||
</div>
|
||||
<button class="btn primary lg" id="reg-btn" style="margin-top:8px">创建门店并开始试用</button>
|
||||
<div class="auth-foot">创建即代表你将成为该门店的管理员,并同意<a href="/terms/">服务条款</a>与<a href="/privacy/">隐私政策</a></div>
|
||||
</div>
|
||||
|
||||
<div class="login-hint-card">
|
||||
<p>登录客户端时请输入:</p>
|
||||
<table class="login-hint-table">
|
||||
<tr>
|
||||
<td>门店编码</td>
|
||||
<td id="hint-code">—</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>用户名</td>
|
||||
<td id="hint-username">—</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>密码</td>
|
||||
<td>您设置的密码</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="regDone" style="display:none">
|
||||
<h1>门店创建成功 🎉</h1>
|
||||
<p class="alead">请记下你的门店编号,登录时需要用到。</p>
|
||||
<div class="auth-ok">
|
||||
门店编号:<code id="done-code">—</code><br/>
|
||||
<span style="color:var(--muted);font-size:var(--fs-sm)" id="done-detail"></span>
|
||||
</div>
|
||||
<a class="btn primary lg" href="/login/">前往登录</a>
|
||||
<div class="auth-foot">已自动开通 30 天全功能试用 · 到期可在 系统设置 → 授权兑换券 续期</div>
|
||||
</div>
|
||||
|
||||
<p class="success-note">如忘记门店编码,登录后可在「系统设置」中查看。</p>
|
||||
<a href="/app/" class="btn btn-primary" style="display:inline-flex;align-items:center;gap:8px;">
|
||||
<i data-lucide="log-in" class="icon"></i>前往登录
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
var API_URL = "{{ site.appBaseUrl }}/api/v1/public/register";
|
||||
|
||||
(function () {
|
||||
var API = '{{ site.appBaseUrl }}';
|
||||
function $(id) { return document.getElementById(id); }
|
||||
function showErr(msg) { var el = $('regErr'); el.textContent = msg; el.classList.add('show'); }
|
||||
function val(id) { return $(id).value.trim(); }
|
||||
|
||||
function getVal(id) { return $(id).value.trim(); }
|
||||
function submit() {
|
||||
$('regErr').classList.remove('show');
|
||||
if (!val('shop_name')) return showErr('请填写门店名称');
|
||||
if (!val('phone')) return showErr('请填写联系电话');
|
||||
if (!val('manager_name')) return showErr('请填写负责人姓名');
|
||||
if (!val('address')) return showErr('请填写门店地址');
|
||||
if (!/^[A-Za-z0-9_]{3,30}$/.test(val('username'))) return showErr('登录账号需 3–30 位字母/数字/下划线');
|
||||
if ($('password').value.length < 6) return showErr('密码至少 6 位');
|
||||
if ($('password').value !== $('password_confirm').value) return showErr('两次密码不一致');
|
||||
|
||||
function setFieldError(id, msg) {
|
||||
var input = $(id);
|
||||
var errEl = $('err-' + id);
|
||||
if (msg) {
|
||||
input.classList.add('error');
|
||||
if (errEl) { errEl.textContent = msg; errEl.classList.add('visible'); }
|
||||
} else {
|
||||
input.classList.remove('error');
|
||||
if (errEl) { errEl.textContent = ''; errEl.classList.remove('visible'); }
|
||||
}
|
||||
}
|
||||
|
||||
function clearAllErrors() {
|
||||
['shop_name','address','manager_name','phone','username','password','password_confirm'].forEach(function(id) {
|
||||
setFieldError(id, '');
|
||||
});
|
||||
}
|
||||
|
||||
// 用户修改字段后清除该字段的错误提示
|
||||
['shop_name','address','manager_name','phone','username','password','password_confirm'].forEach(function(id) {
|
||||
var el = $(id);
|
||||
if (el) el.addEventListener('input', function() { setFieldError(id, ''); });
|
||||
});
|
||||
|
||||
function validate() {
|
||||
clearAllErrors();
|
||||
var ok = true;
|
||||
var firstErr = null;
|
||||
|
||||
function require(id, msg) {
|
||||
if (!getVal(id)) { setFieldError(id, msg); if (!firstErr) firstErr = id; ok = false; }
|
||||
}
|
||||
|
||||
require('shop_name', '请填写店铺名称');
|
||||
require('address', '请填写门店地址');
|
||||
require('manager_name', '请填写负责人姓名');
|
||||
require('phone', '请填写联系电话');
|
||||
|
||||
var username = getVal('username');
|
||||
if (!username) {
|
||||
setFieldError('username', '请填写用户名'); if (!firstErr) firstErr = 'username'; ok = false;
|
||||
} else if (username.length < 3 || username.length > 30) {
|
||||
setFieldError('username', '用户名长度须在 3–30 位之间'); if (!firstErr) firstErr = 'username'; ok = false;
|
||||
} else if (!/^[a-zA-Z0-9_]+$/.test(username)) {
|
||||
setFieldError('username', '用户名只能包含字母、数字和下划线'); if (!firstErr) firstErr = 'username'; ok = false;
|
||||
}
|
||||
|
||||
var password = $('password').value;
|
||||
if (!password) {
|
||||
setFieldError('password', '请填写密码'); if (!firstErr) firstErr = 'password'; ok = false;
|
||||
} else if (password.length < 6) {
|
||||
setFieldError('password', '密码至少 6 位'); if (!firstErr) firstErr = 'password'; ok = false;
|
||||
}
|
||||
|
||||
var confirm = $('password_confirm').value;
|
||||
if (!confirm) {
|
||||
setFieldError('password_confirm', '请再次输入密码'); if (!firstErr) firstErr = 'password_confirm'; ok = false;
|
||||
} else if (password && password !== confirm) {
|
||||
setFieldError('password_confirm', '两次输入的密码不一致'); if (!firstErr) firstErr = 'password_confirm'; ok = false;
|
||||
}
|
||||
|
||||
if (firstErr) { $(firstErr).focus(); $(firstErr).scrollIntoView({ behavior: 'smooth', block: 'center' }); }
|
||||
return ok;
|
||||
}
|
||||
|
||||
function showTopError(msg) {
|
||||
var el = $('reg-error');
|
||||
el.textContent = msg;
|
||||
el.classList.add('visible');
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
|
||||
$('reg-btn').addEventListener('click', function() {
|
||||
$('reg-error').classList.remove('visible');
|
||||
if (!validate()) return;
|
||||
|
||||
var btn = $('reg-btn');
|
||||
btn.disabled = true;
|
||||
btn.classList.add('btn-loading');
|
||||
btn.textContent = '注册中…';
|
||||
|
||||
var payload = {
|
||||
shop_name: getVal('shop_name'),
|
||||
address: getVal('address'),
|
||||
manager_name: getVal('manager_name'),
|
||||
phone: getVal('phone'),
|
||||
description: getVal('description'),
|
||||
username: getVal('username'),
|
||||
password: $('password').value
|
||||
};
|
||||
|
||||
fetch(API_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
var btn = $('reg-btn'); btn.disabled = true; btn.textContent = '创建中…';
|
||||
fetch(API + '/api/v1/public/register', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
shop_name: val('shop_name'), phone: val('phone'), manager_name: val('manager_name'),
|
||||
address: val('address'), description: val('description'),
|
||||
username: val('username'), password: $('password').value,
|
||||
}),
|
||||
})
|
||||
.then(function(res) { return res.json().then(function(data) { return { ok: res.ok, data: data }; }); })
|
||||
.then(function(r) {
|
||||
if (!r.ok) {
|
||||
var msg = (r.data && r.data.error) ? r.data.error : '注册失败,请稍后重试';
|
||||
if (msg.indexOf('Duplicate') !== -1 || msg.indexOf('duplicate') !== -1) {
|
||||
msg = '该用户名在此门店已存在,请换一个用户名';
|
||||
}
|
||||
showTopError(msg);
|
||||
btn.disabled = false;
|
||||
btn.classList.remove('btn-loading');
|
||||
btn.innerHTML = '<i data-lucide="store" class="icon"></i>立即注册';
|
||||
if (window.lucide) lucide.createIcons();
|
||||
return;
|
||||
}
|
||||
var d = r.data.data;
|
||||
$('result-shop-code').textContent = d.shop_code;
|
||||
$('hint-code').textContent = d.shop_code;
|
||||
$('hint-username').textContent = d.username;
|
||||
$('reg-form-card').style.display = 'none';
|
||||
var panel = $('success-panel');
|
||||
panel.classList.add('visible');
|
||||
if (window.lucide) lucide.createIcons();
|
||||
panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
})
|
||||
.catch(function() {
|
||||
showTopError('网络异常,请检查网络连接后重试');
|
||||
btn.disabled = false;
|
||||
btn.classList.remove('btn-loading');
|
||||
btn.innerHTML = '<i data-lucide="store" class="icon"></i>立即注册';
|
||||
if (window.lucide) lucide.createIcons();
|
||||
});
|
||||
});
|
||||
|
||||
$('copy-code-btn').addEventListener('click', function() {
|
||||
var code = $('result-shop-code').textContent;
|
||||
navigator.clipboard.writeText(code).then(function() {
|
||||
var btn = $('copy-code-btn');
|
||||
btn.innerHTML = '<i data-lucide="check" class="icon"></i>已复制';
|
||||
if (window.lucide) lucide.createIcons();
|
||||
setTimeout(function() {
|
||||
btn.innerHTML = '<i data-lucide="copy" class="icon"></i>复制';
|
||||
if (window.lucide) lucide.createIcons();
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (window.lucide) lucide.createIcons();
|
||||
});
|
||||
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); })
|
||||
.then(function (res) {
|
||||
if (!res.ok) throw new Error((res.j && res.j.error) || '注册失败,请稍后重试');
|
||||
var d = res.j.data || {};
|
||||
$('done-code').textContent = d.shop_code || '—';
|
||||
$('done-detail').textContent = '门店「' + (d.shop_name || val('shop_name')) + '」已创建,管理员账号 ' + (d.username || val('username'));
|
||||
$('regForm').style.display = 'none';
|
||||
$('regDone').style.display = 'block';
|
||||
window.scrollTo(0, 0);
|
||||
})
|
||||
.catch(function (e) {
|
||||
showErr(e && e.message ? e.message : '无法连接服务器,请稍后重试');
|
||||
btn.disabled = false; btn.textContent = '创建门店并开始试用';
|
||||
});
|
||||
}
|
||||
$('reg-btn').addEventListener('click', submit);
|
||||
})();
|
||||
</script>
|
||||
|
||||