Merge pull request #560 from JiQingzhe2004/main

feat: 强制更新支持 minimumVersion,阻止低版本用户继续使用
This commit is contained in:
xuncha
2026-03-27 15:23:02 +08:00
committed by GitHub
6 changed files with 90 additions and 11 deletions

View File

@@ -49,6 +49,22 @@ jobs:
run: | run: |
npx electron-builder --mac dmg --arm64 --publish always npx electron-builder --mac dmg --arm64 --publish always
- name: Inject minimumVersion into latest yml
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
TAG=${GITHUB_REF_NAME}
REPO=${{ github.repository }}
MINIMUM_VERSION="4.1.7"
for YML_FILE in latest-mac.yml latest-arm64-mac.yml; do
gh release download "$TAG" --repo "$REPO" --pattern "$YML_FILE" --output "/tmp/$YML_FILE" 2>/dev/null || continue
if ! grep -q 'minimumVersion' "/tmp/$YML_FILE"; then
echo "minimumVersion: $MINIMUM_VERSION" >> "/tmp/$YML_FILE"
fi
gh release upload "$TAG" --repo "$REPO" "/tmp/$YML_FILE" --clobber
done
release-linux: release-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -85,6 +101,20 @@ jobs:
run: | run: |
npx electron-builder --linux --publish always npx electron-builder --linux --publish always
- name: Inject minimumVersion into latest yml
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
TAG=${GITHUB_REF_NAME}
REPO=${{ github.repository }}
MINIMUM_VERSION="4.1.7"
gh release download "$TAG" --repo "$REPO" --pattern "latest-linux.yml" --output "/tmp/latest-linux.yml" 2>/dev/null
if [ -f /tmp/latest-linux.yml ] && ! grep -q 'minimumVersion' /tmp/latest-linux.yml; then
echo "minimumVersion: $MINIMUM_VERSION" >> /tmp/latest-linux.yml
gh release upload "$TAG" --repo "$REPO" /tmp/latest-linux.yml --clobber
fi
release: release:
runs-on: windows-latest runs-on: windows-latest
@@ -121,6 +151,20 @@ jobs:
run: | run: |
npx electron-builder --win nsis --x64 --publish always '--config.artifactName=${productName}-${version}-x64-Setup.${ext}' npx electron-builder --win nsis --x64 --publish always '--config.artifactName=${productName}-${version}-x64-Setup.${ext}'
- name: Inject minimumVersion into latest yml
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
TAG=${GITHUB_REF_NAME}
REPO=${{ github.repository }}
MINIMUM_VERSION="4.1.7"
gh release download "$TAG" --repo "$REPO" --pattern "latest.yml" --output "/tmp/latest.yml" 2>/dev/null
if [ -f /tmp/latest.yml ] && ! grep -q 'minimumVersion' /tmp/latest.yml; then
echo "minimumVersion: $MINIMUM_VERSION" >> /tmp/latest.yml
gh release upload "$TAG" --repo "$REPO" /tmp/latest.yml --clobber
fi
release-windows-arm64: release-windows-arm64:
runs-on: windows-latest runs-on: windows-latest
@@ -157,6 +201,20 @@ jobs:
run: | run: |
npx electron-builder --win nsis --arm64 --publish always '--config.publish.channel=latest-arm64' '--config.artifactName=${productName}-${version}-arm64-Setup.${ext}' npx electron-builder --win nsis --arm64 --publish always '--config.publish.channel=latest-arm64' '--config.artifactName=${productName}-${version}-arm64-Setup.${ext}'
- name: Inject minimumVersion into latest yml
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
TAG=${GITHUB_REF_NAME}
REPO=${{ github.repository }}
MINIMUM_VERSION="4.1.7"
gh release download "$TAG" --repo "$REPO" --pattern "latest-arm64.yml" --output "/tmp/latest-arm64.yml" 2>/dev/null
if [ -f /tmp/latest-arm64.yml ] && ! grep -q 'minimumVersion' /tmp/latest-arm64.yml; then
echo "minimumVersion: $MINIMUM_VERSION" >> /tmp/latest-arm64.yml
gh release upload "$TAG" --repo "$REPO" /tmp/latest-arm64.yml --clobber
fi
update-release-notes: update-release-notes:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:

View File

@@ -1200,7 +1200,8 @@ function registerIpcHandlers() {
return { return {
hasUpdate: true, hasUpdate: true,
version: latestVersion, version: latestVersion,
releaseNotes: normalizeReleaseNotes(result.updateInfo.releaseNotes) releaseNotes: normalizeReleaseNotes(result.updateInfo.releaseNotes),
minimumVersion: (result.updateInfo as any).minimumVersion
} }
} }
} }
@@ -2661,7 +2662,8 @@ function checkForUpdatesOnStartup() {
// 通知渲染进程有新版本 // 通知渲染进程有新版本
mainWindow.webContents.send('app:updateAvailable', { mainWindow.webContents.send('app:updateAvailable', {
version: latestVersion, version: latestVersion,
releaseNotes: normalizeReleaseNotes(result.updateInfo.releaseNotes) releaseNotes: normalizeReleaseNotes(result.updateInfo.releaseNotes),
minimumVersion: (result.updateInfo as any).minimumVersion
}) })
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "weflow", "name": "weflow",
"version": "2.1.0", "version": "4.3.0",
"description": "WeFlow", "description": "WeFlow",
"main": "dist-electron/main.js", "main": "dist-electron/main.js",
"author": { "author": {

View File

@@ -312,10 +312,14 @@ function App() {
const removeUpdateListener = window.electronAPI?.app?.onUpdateAvailable?.((info: any) => { const removeUpdateListener = window.electronAPI?.app?.onUpdateAvailable?.((info: any) => {
// 发现新版本时保存更新信息,锁定状态下不弹窗,解锁后再显示 // 发现新版本时保存更新信息,锁定状态下不弹窗,解锁后再显示
if (info) { if (info) {
setUpdateInfo({ ...info, hasUpdate: true }) window.electronAPI.app.getVersion().then((currentVersion: string) => {
if (!useAppStore.getState().isLocked) { const isMandatory = !!(info.minimumVersion && currentVersion &&
setShowUpdateDialog(true) currentVersion.localeCompare(info.minimumVersion, undefined, { numeric: true, sensitivity: 'base' }) <= 0)
} setUpdateInfo({ ...info, hasUpdate: true, isMandatory })
if (!useAppStore.getState().isLocked) {
setShowUpdateDialog(true)
}
})
} }
}) })
const removeProgressListener = window.electronAPI?.app?.onDownloadProgress?.((progress: any) => { const removeProgressListener = window.electronAPI?.app?.onDownloadProgress?.((progress: any) => {
@@ -685,10 +689,11 @@ function App() {
<UpdateDialog <UpdateDialog
open={showUpdateDialog} open={showUpdateDialog}
updateInfo={updateInfo} updateInfo={updateInfo}
onClose={() => setShowUpdateDialog(false)} onClose={() => { if (!(updateInfo as any)?.isMandatory) setShowUpdateDialog(false) }}
onUpdate={handleUpdateNow} onUpdate={handleUpdateNow}
onIgnore={handleIgnoreUpdate} onIgnore={handleIgnoreUpdate}
isDownloading={isDownloading} isDownloading={isDownloading}
isMandatory={!!(updateInfo as any)?.isMandatory}
progress={downloadProgress} progress={downloadProgress}
/> />

View File

@@ -282,4 +282,13 @@
transform: translateY(0); transform: translateY(0);
opacity: 1; opacity: 1;
} }
} }
.mandatory-tip {
color: #e53e3e;
font-size: 13px;
text-align: center;
margin: 0 0 8px;
padding: 6px 12px;
background: rgba(229, 62, 62, 0.08);
border-radius: 6px;
}

View File

@@ -14,6 +14,7 @@ interface UpdateDialogProps {
onUpdate: () => void onUpdate: () => void
onIgnore?: () => void onIgnore?: () => void
isDownloading: boolean isDownloading: boolean
isMandatory?: boolean
progress: number | { progress: number | {
percent: number percent: number
bytesPerSecond?: number bytesPerSecond?: number
@@ -30,6 +31,7 @@ const UpdateDialog: React.FC<UpdateDialogProps> = ({
onUpdate, onUpdate,
onIgnore, onIgnore,
isDownloading, isDownloading,
isMandatory,
progress progress
}) => { }) => {
if (!open || !updateInfo) return null if (!open || !updateInfo) return null
@@ -69,7 +71,7 @@ const UpdateDialog: React.FC<UpdateDialogProps> = ({
return ( return (
<div className="update-dialog-overlay"> <div className="update-dialog-overlay">
<div className="update-dialog"> <div className="update-dialog">
{!isDownloading && ( {!isDownloading && !isMandatory && (
<button className="close-btn" onClick={onClose}> <button className="close-btn" onClick={onClose}>
<X size={20} /> <X size={20} />
</button> </button>
@@ -119,11 +121,14 @@ const UpdateDialog: React.FC<UpdateDialogProps> = ({
</div> </div>
) : ( ) : (
<div className="actions"> <div className="actions">
{onIgnore && ( {onIgnore && !isMandatory && (
<button className="btn-ignore" onClick={onIgnore}> <button className="btn-ignore" onClick={onIgnore}>
</button> </button>
)} )}
{isMandatory && (
<p className="mandatory-tip">使</p>
)}
<button className="btn-update" onClick={onUpdate}> <button className="btn-update" onClick={onUpdate}>
</button> </button>