From 51863dcbd3f6180ddd0a455f4aa798a1373bf024 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Tue, 26 May 2026 18:29:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(deploy):=20=E6=96=B0=E5=A2=9E=20Windows=20?= =?UTF-8?q?=E6=A1=8C=E9=9D=A2=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E4=B8=8E=E5=8F=91=E5=B8=83=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI 拆成三个 job(mac 构建 Linux/Web、windows 构建 Windows 桌面、mac 发布部署);新增 compile-windows.sh 用 Flutter 构建并打包为 jiu-windows-x64.zip;release.sh 自动写入 Windows 下载 URL 到 version.yaml 并上传 zip。下载页 Windows 卡片从"敬请期待"改为真实下载按钮,URL 由 API 动态填充。 Co-Authored-By: Claude Sonnet 4.6 --- .gitea/workflows/deploy.yml | 53 ++++++++++++++++++++++++++++-- scripts/ci/compile-windows.sh | 44 +++++++++++++++++++++++++ scripts/ci/release.sh | 16 ++++++--- web/content/system-requirements.md | 2 +- web/download.njk | 31 ++++++++++------- 5 files changed, 128 insertions(+), 18 deletions(-) create mode 100755 scripts/ci/compile-windows.sh diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index a3fcd9c..75cb6f9 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -6,7 +6,7 @@ on: - 'v[0-9]*.[0-9]*.[0-9]*' jobs: - deploy: + build-linux-web: runs-on: mac env: GOPROXY: https://goproxy.cn,direct @@ -16,9 +16,58 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Compile + - name: Compile (Linux backend + Flutter Web) run: sh scripts/ci/compile.sh "${{ gitea.ref_name }}" + - name: Upload linux-web artifacts + uses: actions/upload-artifact@v3 + with: + name: linux-web + path: dist/ + + build-windows: + runs-on: windows + env: + GOPROXY: https://goproxy.cn,direct + PUB_HOSTED_URL: https://pub.flutter-io.cn + FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn + + steps: + - uses: actions/checkout@v4 + + - name: Compile (Flutter Windows) + shell: bash + run: sh scripts/ci/compile-windows.sh "${{ gitea.ref_name }}" + + - name: Upload windows artifacts + uses: actions/upload-artifact@v3 + with: + name: windows + path: dist/ + + release-deploy: + needs: [build-linux-web, build-windows] + runs-on: mac + env: + GOPROXY: https://goproxy.cn,direct + PUB_HOSTED_URL: https://pub.flutter-io.cn + FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn + + steps: + - uses: actions/checkout@v4 + + - name: Download linux-web artifacts + uses: actions/download-artifact@v3 + with: + name: linux-web + path: dist/ + + - name: Download windows artifacts + uses: actions/download-artifact@v3 + with: + name: windows + path: dist/ + - name: Test run: sh scripts/ci/test.sh diff --git a/scripts/ci/compile-windows.sh b/scripts/ci/compile-windows.sh new file mode 100755 index 0000000..790082b --- /dev/null +++ b/scripts/ci/compile-windows.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# compile-windows.sh — build Flutter Windows desktop, package into dist/ +set -euo pipefail + +export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}" +export PUB_HOSTED_URL="${PUB_HOSTED_URL:-https://pub.flutter-io.cn}" +export FLUTTER_STORAGE_BASE_URL="${FLUTTER_STORAGE_BASE_URL:-https://storage.flutter-io.cn}" + +TAG="$1" +VER="${TAG#v}" + +echo "==> compile-windows: version=${VER}" + +# Sync Flutter pubspec version +sed -i "s/^version:.*/version: ${VER}+1/" client/pubspec.yaml + +# Build Flutter Windows +cd client +flutter build windows --release \ + "--dart-define=BASE_URL=https://jiu.51yanmei.com" \ + "--dart-define=PUBLIC_URL=https://jiu.51yanmei.com" \ + "--dart-define=APP_VERSION=${TAG}" +cd .. + +# Package release folder into zip using Python (available on all platforms) +mkdir -p dist +python3 - <<'PYEOF' +import zipfile, os + +src = os.path.join('client', 'build', 'windows', 'x64', 'runner', 'Release') +dst = os.path.join('dist', 'jiu-windows-x64.zip') + +with zipfile.ZipFile(dst, 'w', zipfile.ZIP_DEFLATED) as zf: + for root, dirs, files in os.walk(src): + for fname in files: + fp = os.path.join(root, fname) + zf.write(fp, os.path.relpath(fp, src)) + +size = os.path.getsize(dst) +print(f'Packaged {dst} ({size // 1024 // 1024} MB)') +PYEOF + +echo "==> compile-windows: done — dist/ contents:" +ls -lh dist/ diff --git a/scripts/ci/release.sh b/scripts/ci/release.sh index b87ff75..0bf8e68 100755 --- a/scripts/ci/release.sh +++ b/scripts/ci/release.sh @@ -36,11 +36,16 @@ PYEOF echo "==> release: release_notes=${RELEASE_NOTES}" -# Update backend/config/version.yaml -python3 - "${VER}" "${RELEASE_NOTES}" <<'PYEOF' +# Update backend/config/version.yaml (version, build_number, release_notes, windows URL) +python3 - "${VER}" "${RELEASE_NOTES}" "${TAG}" "${FORGEJO_URL}" "${GITEA_REPOSITORY}" <<'PYEOF' import sys -ver = sys.argv[1] +ver = sys.argv[1] notes = sys.argv[2] +tag = sys.argv[3] +furl = sys.argv[4].rstrip('/') +repo = sys.argv[5] +win_url = f"{furl}/{repo}/releases/download/{tag}/jiu-windows-x64.zip" + lines = [] with open('backend/config/version.yaml') as f: for line in f: @@ -54,11 +59,13 @@ with open('backend/config/version.yaml') as f: lines.append('build_number: ' + str(build) + '\n') elif line.startswith('release_notes:'): lines.append('release_notes: "' + notes.replace('\\', '\\\\').replace('"', '\\"') + '"\n') + elif line.startswith(' windows:'): + lines.append(' windows: "' + win_url + '"\n') else: lines.append(line) with open('backend/config/version.yaml', 'w') as f: f.writelines(lines) -print('version.yaml updated to', ver) +print('version.yaml updated to', ver, '| windows:', win_url) PYEOF # Package configs.tar.gz (includes updated version.yaml) @@ -115,5 +122,6 @@ upload_asset() { upload_asset dist/jiu-server upload_asset dist/web.tar.gz upload_asset dist/configs.tar.gz +upload_asset dist/jiu-windows-x64.zip echo "==> release: done — Release ${TAG} created" diff --git a/web/content/system-requirements.md b/web/content/system-requirements.md index bf375df..9d0bc92 100644 --- a/web/content/system-requirements.md +++ b/web/content/system-requirements.md @@ -5,7 +5,7 @@ | 浏览器 | Chrome 90 / Firefox 90 / Safari 15 / Edge 90 | 最新稳定版 | | 网络 | 任意宽带 | 10 Mbps+ | -## Windows(敬请期待) +## Windows(已支持) | 要求 | 版本 | |---|---| diff --git a/web/download.njk b/web/download.njk index 782e1d9..e699203 100644 --- a/web/download.njk +++ b/web/download.njk @@ -258,7 +258,7 @@ pageStyle: |

随时随地,
轻松管理酒库。

- Web 版已正式上线,浏览器直接访问,无需安装。Windows、macOS、iOS、Android 客户端即将推出。 + Web 版与 Windows 桌面版已正式上线,macOS、iOS、Android 客户端即将推出。

@@ -271,7 +271,7 @@ pageStyle: |
可用平台
-
Web 浏览器
+
Web / Windows
@@ -308,7 +308,7 @@ pageStyle: |

支持的平台

-

Web 版现已可用,其余平台正在开发中。

+

Web 版与 Windows 桌面版现已可用,其余平台正在开发中。

@@ -323,14 +323,14 @@ pageStyle: |
-
+

Windows

-

原生桌面客户端,支持离线模式与本地打印。

- 敬请期待 - - 即将推出 - +

原生桌面客户端,支持 Win 10/11(64 位),离线模式与本地打印。

+ ✓ 已支持 + + 下载 Windows 版 +
@@ -431,7 +431,7 @@ pageStyle: | web: { name: 'Web 版', desc: '浏览器直接访问,功能完整,无需下载安装。', icon: 'globe', btnText: '立即使用 Web 版', btnHref: 'https://jiu.51yanmei.com/app/', available: true }, ios: { name: 'iOS', desc: 'iOS 客户端正在开发中,敬请期待。', icon: 'smartphone', btnText: '敬请期待', available: false }, android: { name: 'Android', desc: 'Android 客户端正在开发中,敬请期待。', icon: 'tablet-smartphone', btnText: '敬请期待', available: false }, - windows: { name: 'Windows 桌面', desc: 'Windows 客户端正在开发中,敬请期待。', icon: 'monitor', btnText: '敬请期待', available: false }, + windows: { name: 'Windows 桌面', desc: '原生桌面客户端,支持 Win 10/11(64 位),离线模式与本地打印。', icon: 'monitor', btnText: '下载 Windows 版', btnHref: '#', available: true }, macos: { name: 'macOS 桌面', desc: 'macOS 客户端正在开发中,敬请期待。', icon: 'laptop', btnText: '敬请期待', available: false } }; @@ -499,7 +499,16 @@ pageStyle: | fetch('https://jiu.51yanmei.com/api/v1/public/release') .then(function(r) { return r.json(); }) - .then(function(data) { if (data && data.version) updateVersionBadges(data.version); }) + .then(function(data) { + if (data && data.version) updateVersionBadges(data.version); + 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; + // 若用户在 Windows 上,同步更新自动识别卡片 + if (detected === 'windows') updateDetectCard(detected); + } + }) .catch(function() {}); }); })();