feat(V0.2): 版本方案落地 —— 前端/外壳解绑, build 标识统一, 外壳版本展示
Docker Build and Push / build-image (push) Successful in 1m5s

- check-version: 分组校验 (前端 package.json / 外壳 tauri.conf+Cargo),
  两组不再要求相等; 分支前缀校验只针对前端版本
- build-ota: build_id 改为 YYYYMMDDHHmmss (北京时间, 与前端 BUILD_ID
  同格式); sequence 保持毫秒仅用于判新
- 我的页: 当前版本恢复 v0.2.0 · build <原始BUILD_ID>; 新版本附 OTA
  build_id; 底部替换为外壳版本 (Tauri getVersion, Web 端 —)
- README: 合并遗留 readme 全部内容并按决议重写版本管理章节;
  新增 CHANGELOG.md (PATCH 仅明确提出时自增)
This commit is contained in:
jif2.zhang
2026-10-25 21:28:06 +08:00
parent 06aa48f6ad
commit 67be8d8f7b
18 changed files with 700 additions and 338 deletions
+15 -12
View File
@@ -2,10 +2,10 @@ import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { Avatar, Button, List, ProgressBar, Switch, Toast } from 'antd-mobile'
import { useAuth } from '../auth/AuthContext.jsx'
import { APP_VERSION, BUILD_ID } from '../version.js'
import {
applyOtaUpdate,
checkOtaUpdate,
fmtBuildId,
getCurrentVersionInfo,
getOtaDevMode,
getOtaVersionInfo,
@@ -14,14 +14,7 @@ import {
setOtaDevMode,
} from '../api/ota.js'
// seq/build 时间戳 → 'MM-dd HH:mm' (sequence 为毫秒时间戳, build_id 形如 seq-<ms>)
export function fmtSeqTime(v) {
const ms = typeof v === 'string' && v.startsWith('seq-') ? Number(v.slice(4)) : Number(v)
if (!Number.isFinite(ms) || ms <= 0) return ''
const p = (n) => String(n).padStart(2, '0')
const d = new Date(ms)
return `${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`
}
const inTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window
// "我" 页: 顶部 NavBar + 用户头像卡片 + 信息列表 + OTA 升级区
// OTA 区:
@@ -47,6 +40,16 @@ export default function MePage() {
const [otaInfo, setOtaInfo] = useState(null) // 检查结果中的 info
const [otaVersion, setOtaVersion] = useState(null) // hotswap 当前激活的覆盖包版本
const [progress, setProgress] = useState({ received: 0, total: 0 })
const [shellVersion, setShellVersion] = useState('') // 外壳 (APK/桌面包) 版本, 独立维护
// 外壳版本: 经 Tauri API 读取 (Web 端为空, 底部显示 —)
useEffect(() => {
if (!inTauri) return
import('@tauri-apps/api/app')
.then((m) => m.getVersion())
.then(setShellVersion)
.catch((e) => console.warn('[shell] getVersion failed:', e))
}, [])
const [error, setError] = useState('')
// 判新模式: false(默认)=版本号比较, true=build sequence 比较; 值持久化在设备端
const [devMode, setDevMode] = useState(() => getOtaDevMode())
@@ -146,7 +149,7 @@ export default function MePage() {
{/* OTA 升级区 */}
<List className="me-list" mode="card" header="前端升级 (OTA)">
<List.Item extra={'v' + cur.version + (fmtSeqTime(cur.build) ? ' · ' + fmtSeqTime(cur.build) : '')}>当前版本</List.Item>
<List.Item extra={'v' + cur.version + (cur.build ? ' · build ' + cur.build : '')}>当前版本</List.Item>
<List.Item extra={otaVersion?.active ? 'v' + (otaVersion.version || '?') : '内置'}>
运行资源
</List.Item>
@@ -206,7 +209,7 @@ export default function MePage() {
</div>
</List.Item>
{otaState === 'available' && otaInfo && (
<List.Item extra={'v' + otaInfo.version + (fmtSeqTime(otaInfo.sequence) ? ' · ' + fmtSeqTime(otaInfo.sequence) : '')}>
<List.Item extra={'v' + otaInfo.version + (otaInfo.build ? ' · build ' + otaInfo.build : '')}>
新版本
{otaInfo.bundle_size ? ` (${(otaInfo.bundle_size / 1024).toFixed(0)} KB)` : ''}
</List.Item>
@@ -253,7 +256,7 @@ export default function MePage() {
退出登录
</List.Item>
</List>
<div className="me-version">v{APP_VERSION} · build {BUILD_ID}</div>
<div className="me-version">外壳 v{shellVersion || '—'}</div>
</div>
)
}