Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Build and Release

on:
push:
tags:
- 'v*'
workflow_dispatch:

jobs:
build-windows:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build Windows
run: npx electron-builder --win
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
name: windows-build
path: dist/*.exe

build-macos:
runs-on: macos-latest
strategy:
matrix:
arch: [x64, arm64]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build macOS (${{ matrix.arch }})
run: npx electron-builder --mac --${{ matrix.arch }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload macOS artifact
uses: actions/upload-artifact@v4
with:
name: macos-build-${{ matrix.arch }}
path: dist/*-${{ matrix.arch }}.dmg

build-linux:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build Linux
run: npx electron-builder --linux deb
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload Linux artifact
uses: actions/upload-artifact@v4
with:
name: linux-build
path: dist/*.deb

release:
needs: [build-windows, build-macos, build-linux]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts

- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: |
artifacts/windows-build/*.exe
artifacts/macos-build-x64/*.dmg
artifacts/macos-build-arm64/*.dmg
artifacts/linux-build/*.deb
generate_release_notes: true
fail_on_unmatched_files: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Binary file modified build/chatecnu.ico
Binary file not shown.
25 changes: 21 additions & 4 deletions build/chatecnu.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified build/favicon.ico
Binary file not shown.
Binary file added build/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/256x256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/48x48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build/icons/64x64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 26 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@
border: 1px solid #1a1a2e;
display: none;
}
.refresh-wrapper {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
Expand Down Expand Up @@ -262,12 +268,15 @@
<path d="M16 21v-3a2 2 0 0 1 2-2h3"></path>
</svg>
</button>
<button id="btn-refresh" class="btn-icon" title="刷新页面">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"></path>
<path d="M21 3v5h-5"></path>
</svg>
</button>
<div class="refresh-wrapper">
<button id="btn-refresh" class="btn-icon" title="刷新页面">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"></path>
<path d="M21 3v5h-5"></path>
</svg>
</button>
<div id="refresh-badge" class="badge-dot"></div>
</div>
<!-- UAT 环境切换 -->
<div id="env-switch" class="env-switch" style="display:none;">
<span class="env-label">UAT</span>
Expand Down Expand Up @@ -300,11 +309,22 @@
let isUpdateAvailable = false;
let isUpdateDownloaded = false;

const refreshBadge = document.getElementById('refresh-badge');

// 刷新按钮
btnRefresh.onclick = () => {
// 点击刷新后隐藏红点
refreshBadge.style.display = 'none';
ipcRenderer.send('reload-page');
};

// Web 版本有更新
ipcRenderer.on('web-update-available', (event, info) => {
console.log(`[web-update] 有新版本: ${info.current} -> ${info.latest}`);
refreshBadge.style.display = 'block';
btnRefresh.title = `刷新页面 (新版本 ${info.latest} 可用)`;
});

// 精灵模式按钮
const btnSprite = document.getElementById('btn-sprite');
btnSprite.onclick = () => {
Expand Down
78 changes: 76 additions & 2 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const APP_TITLE = `ChatECNU Desktop v${version}`;
// 判断是否为打包后的应用
const isPackaged = app.isPackaged;

// 命令行参数:--uat 强制启用 UAT 模式
const forceUat = process.argv.includes('--uat');

// ========== 窗口尺寸常量 ==========
const MAIN_WINDOW_WIDTH = 1280;
const MAIN_WINDOW_HEIGHT = 768;
Expand Down Expand Up @@ -67,9 +70,9 @@ let settingsWindow = null; // 设置窗口
function createWindow() {
// 图标路径
const iconPath = getIconPath('chatecnu.ico');
const isUatModeEnabled = store.get('uatMode'); // UAT 功能是否启用
const isUatModeEnabled = store.get('uatMode') || forceUat; // UAT 功能是否启用
const isUatActive = store.get('uatActive'); // UAT 环境是否激活
const shouldUseUat = isUatModeEnabled && isUatActive; // 启动时是否使用 UAT
const shouldUseUat = forceUat || (isUatModeEnabled && isUatActive); // 启动时是否使用 UAT

// 创建主窗口(App Shell)
mainWindow = new BrowserWindow({
Expand Down Expand Up @@ -214,6 +217,77 @@ function createWindow() {
});
}

// ========== JSBridge ==========
// 当前 web 版本(由前端上报)
let currentWebVersion = null;

// 比较版本号,返回 1 (a > b), -1 (a < b), 0 (a == b)
function compareVersions(a, b) {
const partsA = a.replace(/^v/, '').split('.').map(Number);
const partsB = b.replace(/^v/, '').split('.').map(Number);
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
const numA = partsA[i] || 0;
const numB = partsB[i] || 0;
if (numA > numB) return 1;
if (numA < numB) return -1;
}
return 0;
}

// 检查 web 版本更新
async function checkWebVersionUpdate(reportedVersion) {
try {
// 根据当前环境确定 API 地址(与 createWindow 逻辑保持一致)
const shouldUseUat = forceUat || (store.get('uatMode') && store.get('uatActive'));
const baseUrl = shouldUseUat ? URL_UAT : URL_PRODUCTION;
const url = `${baseUrl}/api/version/latest?_t=${Date.now()}`;

const response = await fetch(url);
const result = await response.json();

if (result.code === 0 && result.data && result.data.version) {
const serverVersion = result.data.version;
// 比较:服务器版本 > 当前加载版本
if (compareVersions(serverVersion, reportedVersion) > 0) {
console.log(`[web-update] new version available: ${reportedVersion} -> ${serverVersion}`);
// 通知主窗口显示提示
if (mainWindow) {
mainWindow.webContents.send('web-update-available', {
current: reportedVersion,
latest: serverVersion
});
}
} else {
console.log(`[web-update] up to date: ${reportedVersion}`);
}
}
} catch (err) {
console.error('[web-update] check failed:', err.message);
}
}

// 网页通过 _tx.status(key, value) 告知客户端状态
ipcMain.on('tx:status', (event, key, value) => {
console.log(`[tx:status] ${key}:`, value);

// 处理 version 上报
if (key === 'version' && value && value.frontend) {
const reportedVersion = value.frontend.replace(/^v/, '');
// 避免重复检查同一版本
if (currentWebVersion !== reportedVersion) {
currentWebVersion = reportedVersion;
checkWebVersionUpdate(reportedVersion);
}
}
});

// 向网页发送事件(供主进程其他模块调用)
function emitToWeb(eventName, data) {
if (view && view.webContents) {
view.webContents.send('tx:event', eventName, data);
}
}

// IPC: 检查更新
ipcMain.on('check-for-updates', () => checkForUpdates(true));

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 20 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"name": "chatecnu-desktop-app",
"version": "0.1.31",
"version": "0.1.41",
"description": "Desktop Application for chat.ecnu.edu.cn",
"main": "main.js",
"scripts": {
"start": "electron .",
"dev": "electron .",
"dev:uat": "electron . --uat",
"build": "dotenv -- electron-builder",
"build:win": "dotenv -- electron-builder --win && node post-build.js win",
"build:mac": "dotenv -- electron-builder --mac && node post-build.js mac",
Expand All @@ -19,7 +20,10 @@
"desktop",
"chat"
],
"author": "ChatECNU Team @ ECNU",
"author": {
"name": "ChatECNU Team",
"email": "20180208@ecnu.edu.cn"
},
"license": "ECNU",
"repository": {
"type": "git",
Expand Down Expand Up @@ -72,7 +76,7 @@
}
],
"artifactName": "${productName}-${version}-${arch}.${ext}",
"icon": "build/chatecnu.ico",
"icon": "build/icon.png",
"category": "public.app-category.productivity"
},
"dmg": {
Expand All @@ -89,6 +93,19 @@
}
]
},
"linux": {
"target": [
{
"target": "deb",
"arch": [
"x64"
]
}
],
"artifactName": "${productName}-${version}-${arch}.${ext}",
"icon": "build/icons",
"category": "Utility"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
Expand Down
Loading