feat: 构建系统重构 + VCHSM 架构迁移 + 右键菜单修复 + 尺寸参数统一

## 构建、打包与分发系统重构 (build/)

- 构建系统收敛至 build/ 目录:build.mjs + electron-builder.js + 6 个脚本

- electron-builder 配置从 package.json 提取为 build/electron-builder.js

- 新增 --edition (personal/enterprise) 和 --channel (stable/beta/alpha) 参数

- OSS 路径按渠道隔离

- 新增 pre-build-check.mjs:Git/CHANGELOG/版本/环境变量校验

- 新增 bump-version.mjs:版本号管理 + CHANGELOG 自动生成

- updater.ts 发送 channel/edition/deviceFingerprint

- 新增 src/shared/utils/rollout.ts 灰度测试工具

- 新增 10 条 NPM 脚本

## VCHSM 五层架构迁移

- 7 个业务模块 + ~500 处导入路径同步

## 修复

- MediaCardContextMenu 改用共享 ContextMenu 组件

- ComboBox 尺寸参数显示统一 (size-format.ts)

## 文档

- UpdateA.md / build/README.md / README.md / .env.example 更新

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-29 18:41:07 +08:00
parent e0d91335c7
commit 337d6c1205
187 changed files with 5252 additions and 1702 deletions

View File

@@ -0,0 +1,135 @@
// ============================================================
// pre-build-check.mjs — 构建前校验
//
// 用法:
// node build/scripts/pre-build-check.mjs <platform> <version> <channel>
//
// 检查项:
// 1. Git 工作区是否干净(有未提交变更时警告,非阻断)
// 2. CHANGELOG.md 是否包含当前版本条目
// 3. package.json 版本号与传入版本号一致
// 4. 渠道版本号格式校验beta/alpha 必须含预发布后缀)
// ============================================================
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { execSync } from 'node:child_process';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..', '..');
const platform = process.argv[2];
const version = process.argv[3];
const channel = process.argv[4] || 'stable';
if (!platform || !version) {
console.error('用法: node build/scripts/pre-build-check.mjs <platform> <version> [channel]');
process.exit(1);
}
let hasError = false;
// ---------- 1. Git 工作区检查 ----------
console.log('▸ 检查 Git 工作区状态...');
try {
const status = execSync('git status --porcelain', { cwd: ROOT, encoding: 'utf-8' }).trim();
if (status) {
console.warn('⚠️ 警告: Git 工作区有未提交的变更:');
const lines = status.split('\n').slice(0, 10);
lines.forEach((l) => console.warn(` ${l}`));
if (status.split('\n').length > 10) {
console.warn(` ... 还有 ${status.split('\n').length - 10} 个文件`);
}
console.warn(' (不阻断构建,但建议先提交)\n');
} else {
console.log(' ✅ Git 工作区干净\n');
}
} catch {
console.warn(' ⚠️ 非 Git 环境,跳过工作区检查\n');
}
// ---------- 2. CHANGELOG 版本条目检查 ----------
console.log('▸ 检查 CHANGELOG.md 版本条目...');
const changelogPath = join(ROOT, 'CHANGELOG.md');
try {
const changelogContent = readFileSync(changelogPath, 'utf-8');
const versionPattern = new RegExp(
`^##\\s+${version.replace(/\./g, '\\.')}\\b`,
'm',
);
if (versionPattern.test(changelogContent)) {
console.log(` ✅ CHANGELOG.md 已包含 v${version} 条目\n`);
} else {
console.error(` ❌ CHANGELOG.md 中未找到 v${version} 的更新日志条目`);
console.error(` 请在 CHANGELOG.md 顶部添加: ## ${version}(日期)\n`);
hasError = true;
}
} catch {
console.warn(' ⚠️ CHANGELOG.md 不存在,跳过版本条目检查\n');
}
// ---------- 3. package.json 版本号一致性 ----------
console.log('▸ 检查 package.json 版本一致性...');
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
if (pkg.version === version) {
console.log(` ✅ package.json 版本号一致: ${version}\n`);
} else {
console.error(` ❌ 版本号不一致: 传入 ${version}package.json 为 ${pkg.version}`);
console.error(' 请先执行: node build/scripts/bump-version.mjs <major|minor|patch>\n');
hasError = true;
}
// ---------- 4. 渠道版本号格式校验 ----------
console.log('▸ 检查渠道版本号格式...');
if (channel === 'stable') {
// stable 版本号必须是纯 semver如 0.0.28
if (/^\d+\.\d+\.\d+$/.test(version)) {
console.log(' ✅ Stable 渠道版本号格式正确\n');
} else {
console.error(` ❌ Stable 渠道版本号必须为纯 semver 格式 (x.y.z),当前: ${version}\n`);
hasError = true;
}
} else {
// beta/alpha 版本号必须含预发布后缀(如 0.0.29-beta.1
if (/-/.test(version)) {
console.log(`${channel} 渠道版本号含预发布后缀\n`);
} else {
console.warn(` ⚠️ ${channel} 渠道建议使用预发布版本号(如 ${version}-${channel}.1`);
console.warn(' 当前版本号不含预发布后缀,可能覆盖 stable 版本的 OSS 文件\n');
}
}
// ---------- 5. 环境变量检查(仅 upload/publish 时有效,此处仅提示) ----------
console.log('▸ 环境变量就绪检查...');
const uploadVars = ['OSS_ENDPOINT', 'OSS_BUCKET', 'OSS_ACCESS_KEY_ID', 'OSS_ACCESS_KEY_SECRET'];
const missingUpload = uploadVars.filter((v) => !process.env[v]);
if (missingUpload.length > 0) {
console.warn(` ⚠️ OSS 相关环境变量未设置: ${missingUpload.join(', ')}`);
console.warn(' 如需上传 OSS请配置这些环境变量或在 .env.local 中设置)');
} else {
console.log(' ✅ OSS 环境变量已配置');
}
if (!process.env.UPDATE_API_KEY) {
console.warn(' ⚠️ UPDATE_API_KEY 未设置,发布到 API 可能失败');
} else {
console.log(' ✅ UPDATE_API_KEY 已配置');
}
console.log('');
// ---------- 结果 ----------
if (hasError) {
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.error('❌ 构建前校验未通过,请修复以上问题后重试');
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
process.exit(1);
}
console.log('✅ 构建前校验全部通过');