Files
jiu/web/download.njk
T
wangjia 0e91768da4 feat(site): 下载页平台专属图标 + 检测卡放大重排
- 图标 sprite 新增 i-apple / i-android(simple-icons 品牌图标,填充式)与
  i-tablet-smartphone(lucide),先登记原型 icons.js 再同步官网 icons.njk
- 下载页 macOS/Android/iOS 卡片及当前平台检测卡换用专属图标(原为 copy/phone-call/funnel 错配)
- 检测卡高度加倍:icbox 44→84、标题 16→22、内边距加大,新增引导行与版本徽章,
  描述文字由 muted 灰改为正文色;窄屏按钮转全宽

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
2026-07-04 00:08:01 +08:00

291 lines
15 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
layout: base.njk
title: 下载
description: 下载岩美酒库管理系统客户端:Windows、macOS、Android、iOS 与免安装 Web 版。
pageStyle: |
.dl-hero{background:var(--mk-hero-grad); color:var(--on-accent); padding:64px 0 88px; 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:720px; margin:-56px auto 0; position:relative; z-index:2;}
.detect .card{display:flex; align-items:center; gap:26px; box-shadow:var(--sh-2); padding:34px 36px;}
.detect .icbox{width:84px; height:84px; border-radius:var(--r-lg); flex:none; display:flex; align-items:center; justify-content:center;}
.detect .icbox .ic{width:42px; height:42px;}
.detect .detect-info{flex:1; min-width:0;}
.detect .detect-eyebrow{color:var(--primary); font-size:var(--fs-xs); font-weight:800; letter-spacing:1px; margin-bottom:5px;}
.detect .detect-title{display:flex; align-items:center; gap:10px; margin-bottom:7px; flex-wrap:wrap;}
.detect b{color:var(--heading); font-size:22px; font-weight:800; line-height:1.3;}
.detect .detect-ver{font-family:var(--font-mono); font-size:var(--fs-xs); font-weight:700; color:var(--primary); background:var(--info-soft); padding:3px 10px; border-radius:var(--r-pill);}
.detect .detect-desc{display:block; color:var(--text); font-size:15px; line-height:1.7;}
.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; padding:26px 22px; gap:18px;} .detect .btn{margin-left:0; width:100%;} .changelog-entry{grid-template-columns:1fr;} }
---
<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 class="detect-info">
<div class="detect-eyebrow">已识别你的设备 · 为你推荐</div>
<div class="detect-title">
<b id="detect-name">Web 版</b>
<span class="detect-ver version-badge">v{{ changelog[0].version }}</span>
</div>
<span class="detect-desc" id="detect-desc">浏览器直接访问,功能完整,无需下载安装。</span>
</div>
<a class="btn primary lg" id="detect-btn" href="{{ site.appBaseUrl }}/app/"><span>立即使用</span></a>
</div>
</div>
<section class="section">
<div class="container">
<div class="dl-grid" id="platform-grid">
<div class="dl-card" data-platform="windows">
<div class="icbox ic-info"><svg class="ic"><use href="#i-ic63"/></svg></div>
<h3>Windows</h3>
<div class="req">Win 10 / 1164 位)</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>
<div class="dl-card" data-platform="macos">
<div class="icbox ic-info"><svg class="ic"><use href="#i-apple"/></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>
<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>
<div class="dl-card" data-platform="android">
<div class="icbox ic-warn"><svg class="ic"><use href="#i-android"/></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-tablet-smartphone"/></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>
<section class="section alt" id="changelog">
<div class="container">
<div class="sec-head">
<div class="eyebrow">更新日志</div>
<h2>最近更新</h2>
<p id="changelog-count">最近 {{ changelog | length }} 个版本。</p>
</div>
<div class="changelog" id="changelog-list">
{% for entry in changelog %}
<div class="changelog-entry{% if loop.first %} current{% endif %}">
<div class="changelog-meta">
<div class="changelog-version">v{{ entry.version }}</div>
<div class="changelog-date">{{ entry.date }}</div>
{% if loop.first %}<span class="changelog-tag">当前版本</span>{% endif %}
</div>
<div class="changelog-body">
{% if entry.intro %}<p class="changelog-intro">{{ entry.intro }}</p>{% endif %}
{% for section in entry.sections %}
<div class="changelog-cat">
<div class="changelog-cat-label">
<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>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</div>
</section>
<script>
(function() {
var APP_BASE = '{{ site.appBaseUrl }}';
var SPRITE = { web:'#i-ic01', ios:'#i-tablet-smartphone', android:'#i-android', windows:'#i-ic63', macos:'#i-apple' };
var platforms = {
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() {
var ua = navigator.userAgent;
if (/iPhone|iPad|iPod/.test(ua)) return 'ios';
if (/Android/.test(ua)) return 'android';
var platform = navigator.platform || '';
if (/Win/.test(platform) || /Win/.test(ua)) return 'windows';
if (/Mac/.test(platform) || /Mac/.test(ua)) return 'macos';
return 'web';
}
function updateDetectCard(p) {
var info = platforms[p];
var nameEl = document.getElementById('detect-name');
var descEl = document.getElementById('detect-desc');
var btnEl = document.getElementById('detect-btn');
var iconEl = document.getElementById('detect-icon');
if (nameEl) nameEl.textContent = info.name;
if (descEl) descEl.textContent = info.desc;
if (btnEl) {
if (info.available && info.btnHref && info.btnHref !== '#') {
btnEl.href = info.btnHref;
btnEl.classList.remove('disabled');
btnEl.innerHTML = '<span>' + info.btnText + '</span>';
} else if (!info.available) {
btnEl.href = '#';
btnEl.classList.add('disabled');
btnEl.innerHTML = '<span>' + info.btnText + '</span>';
}
}
if (iconEl) {
iconEl.innerHTML = '<svg class="ic"><use href="' + (SPRITE[p] || '#i-ic01') + '"/></svg>';
}
}
function highlightPlatformCard(p) {
document.querySelectorAll('#platform-grid .dl-card').forEach(function(el) {
el.classList.remove('detected');
});
var card = document.querySelector('#platform-grid [data-platform="' + p + '"]');
if (card) card.classList.add('detected');
}
function updateVersionBadges(version) {
document.querySelectorAll('.version-badge').forEach(function(el) {
el.textContent = 'v' + version;
});
}
// 用 /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' };
function esc(s) {
return String(s == null ? '' : s).replace(/[&<>"]/g, function(c) {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c];
});
}
var html = '';
entries.forEach(function(entry, i) {
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 (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';
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>';
});
var list = document.getElementById('changelog-list');
if (list) list.innerHTML = html;
var count = document.getElementById('changelog-count');
if (count) count.textContent = '最近 ' + entries.length + ' 个版本。';
}
document.addEventListener('DOMContentLoaded', function() {
var detected = detectPlatform();
updateDetectCard(detected);
highlightPlatformCard(detected);
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);
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 = urls.ios;
platforms.ios.btnText = '通过 TestFlight 安装';
var iosStatus = document.getElementById('ios-status');
var iosBtn = document.getElementById('ios-dl-btn');
if (iosStatus) { iosStatus.className = 'dl-status'; iosStatus.textContent = '✓ 已上线'; }
if (iosBtn) {
iosBtn.className = 'btn primary';
iosBtn.href = urls.ios;
iosBtn.target = '_blank';
iosBtn.rel = 'noopener';
iosBtn.textContent = 'TestFlight 安装';
}
if (detected === 'ios') updateDetectCard(detected);
}
})
.catch(function() {
['windows-dl-btn', 'macos-dl-btn', 'android-dl-btn'].forEach(function(id) {
var btn = document.getElementById(id);
if (btn && btn.getAttribute('href') === '#') {
btn.className = 'btn ghost disabled';
btn.textContent = '暂时无法获取下载地址';
}
});
var detectBtn = document.getElementById('detect-btn');
if (detectBtn && detectBtn.getAttribute('href') === '#') {
detectBtn.classList.add('disabled');
detectBtn.innerHTML = '<span>暂时无法连接服务器</span>';
}
});
});
})();
</script>