|
@@ -0,0 +1,510 @@
|
|
|
|
|
+// src/js/app.js - Vue 应用主文件
|
|
|
|
|
+
|
|
|
|
|
+const { createApp, ref, reactive, computed, watch, onMounted } = Vue;
|
|
|
|
|
+
|
|
|
|
|
+// 创建 Vue 应用
|
|
|
|
|
+const app = createApp({
|
|
|
|
|
+ setup() {
|
|
|
|
|
+ // ==================== 统一数据存储 ====================
|
|
|
|
|
+
|
|
|
|
|
+ // 当前激活的标签页
|
|
|
|
|
+ const activeTab = ref('intro');
|
|
|
|
|
+
|
|
|
|
|
+ // 软件列表配置
|
|
|
|
|
+ const softwareList = ['nodejs', 'vscode', 'git'];
|
|
|
|
|
+ const softwareNames = {
|
|
|
|
|
+ nodejs: 'Node.js',
|
|
|
|
|
+ vscode: 'VS Code',
|
|
|
|
|
+ git: 'Git',
|
|
|
|
|
+ all: '一键安装'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 版本数据(唯一数据源)
|
|
|
|
|
+ const versions = reactive({
|
|
|
|
|
+ nodejs: { list: [], loading: true, error: false },
|
|
|
|
|
+ vscode: { list: [], loading: true, error: false },
|
|
|
|
|
+ git: { list: [], loading: true, error: false }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 选中的版本
|
|
|
|
|
+ const selectedVersions = reactive({
|
|
|
|
|
+ nodejs: '',
|
|
|
|
|
+ vscode: '',
|
|
|
|
|
+ git: ''
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 代理设置(唯一数据源)
|
|
|
|
|
+ const proxySettings = reactive({
|
|
|
|
|
+ nodejs: { enabled: false, url: 'https://npmmirror.com/mirrors/node/' },
|
|
|
|
|
+ vscode: { enabled: false, url: 'https://registry.npmmirror.com/-/binary/vscode/' },
|
|
|
|
|
+ git: { enabled: false, url: 'https://registry.npmmirror.com/-/binary/git-for-windows/' }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 安装选项
|
|
|
|
|
+ const installOptions = reactive({
|
|
|
|
|
+ nodejs: { installPnpm: true },
|
|
|
|
|
+ all: {
|
|
|
|
|
+ installNodejs: true,
|
|
|
|
|
+ installVscode: true,
|
|
|
|
|
+ installGit: true,
|
|
|
|
|
+ installPnpm: true
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 安装状态(每个软件独立)
|
|
|
|
|
+ const installStatus = reactive({
|
|
|
|
|
+ nodejs: { installing: false, message: '就绪', progress: 0, success: false, error: false },
|
|
|
|
|
+ vscode: { installing: false, message: '就绪', progress: 0, success: false, error: false },
|
|
|
|
|
+ git: { installing: false, message: '就绪', progress: 0, success: false, error: false },
|
|
|
|
|
+ all: { installing: false, message: '就绪', progress: 0, success: false, error: false }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 系统状态
|
|
|
|
|
+ const systemStatus = reactive({
|
|
|
|
|
+ visible: false,
|
|
|
|
|
+ type: 'warning', // warning, error, success
|
|
|
|
|
+ message: '',
|
|
|
|
|
+ actionText: '',
|
|
|
|
|
+ actionHandler: null
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // Toast 提示列表
|
|
|
|
|
+ const toasts = ref([]);
|
|
|
|
|
+ let toastId = 0;
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 计算属性 ====================
|
|
|
|
|
+
|
|
|
|
|
+ // 版本是否正在加载
|
|
|
|
|
+ const isLoadingVersions = computed(() => {
|
|
|
|
|
+ return softwareList.some(s => versions[s].loading);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 是否有版本加载失败
|
|
|
|
|
+ const hasVersionError = computed(() => {
|
|
|
|
|
+ return softwareList.some(s => versions[s].error);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 所有版本是否加载完成
|
|
|
|
|
+ const allVersionsLoaded = computed(() => {
|
|
|
|
|
+ return softwareList.every(s => !versions[s].loading && !versions[s].error);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 一键安装页面的状态文本
|
|
|
|
|
+ const allPaneStatusText = computed(() => {
|
|
|
|
|
+ if (isLoadingVersions.value) return '加载中...';
|
|
|
|
|
+ if (hasVersionError.value) return '部分加载失败';
|
|
|
|
|
+ return '就绪';
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 获取软件的状态文本
|
|
|
|
|
+ const getStatusText = (software) => {
|
|
|
|
|
+ const status = installStatus[software];
|
|
|
|
|
+ if (status.installing) return status.message;
|
|
|
|
|
+ if (status.success) return status.message;
|
|
|
|
|
+ if (status.error) return status.message;
|
|
|
|
|
+
|
|
|
|
|
+ // 非安装状态时,显示版本加载状态
|
|
|
|
|
+ if (software === 'all') {
|
|
|
|
|
+ return allPaneStatusText.value;
|
|
|
|
|
+ }
|
|
|
|
|
+ const ver = versions[software];
|
|
|
|
|
+ if (ver.loading) return '加载中...';
|
|
|
|
|
+ if (ver.error) return '加载失败';
|
|
|
|
|
+ return '就绪';
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 获取安装按钮是否禁用
|
|
|
|
|
+ const isInstallDisabled = (software) => {
|
|
|
|
|
+ const status = installStatus[software];
|
|
|
|
|
+ if (status.installing) return true;
|
|
|
|
|
+
|
|
|
|
|
+ if (software === 'all') {
|
|
|
|
|
+ return isLoadingVersions.value || hasVersionError.value;
|
|
|
|
|
+ }
|
|
|
|
|
+ const ver = versions[software];
|
|
|
|
|
+ return ver.loading || ver.error;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 获取安装按钮文本
|
|
|
|
|
+ const getInstallButtonText = (software) => {
|
|
|
|
|
+ const status = installStatus[software];
|
|
|
|
|
+ if (status.installing) return '安装中...';
|
|
|
|
|
+ if (status.success) return '安装完成';
|
|
|
|
|
+ if (status.error) return '重新安装';
|
|
|
|
|
+ if (software === 'all') return '开始一键安装';
|
|
|
|
|
+ return `安装 ${softwareNames[software]}`;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 格式化版本标签(用于小型下拉框)
|
|
|
|
|
+ const formatVersionLabel = (label, isSmall) => {
|
|
|
|
|
+ if (!isSmall) return label;
|
|
|
|
|
+ const versionMatch = label.match(/(\d+\.\d+\.\d+)/);
|
|
|
|
|
+ return versionMatch ? versionMatch[1] : label.replace(/Node\.js |Git |\(.*?\)/g, '').trim();
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 方法 ====================
|
|
|
|
|
+
|
|
|
|
|
+ // 切换标签页
|
|
|
|
|
+ const switchTab = (tabId) => {
|
|
|
|
|
+ activeTab.value = tabId;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 显示 Toast 提示
|
|
|
|
|
+ const showToast = (message, options = {}) => {
|
|
|
|
|
+ const {
|
|
|
|
|
+ type = 'error',
|
|
|
|
|
+ title = type === 'error' ? '错误' : type === 'warning' ? '警告' : type === 'success' ? '成功' : '提示'
|
|
|
|
|
+ } = options;
|
|
|
|
|
+
|
|
|
|
|
+ const id = ++toastId;
|
|
|
|
|
+ const toast = reactive({
|
|
|
|
|
+ id,
|
|
|
|
|
+ type,
|
|
|
|
|
+ title,
|
|
|
|
|
+ message,
|
|
|
|
|
+ closing: false,
|
|
|
|
|
+ progress: 100,
|
|
|
|
|
+ timer: null,
|
|
|
|
|
+ progressTimer: null
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ toasts.value.push(toast);
|
|
|
|
|
+ updateToastsAutoClose();
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ close: () => closeToast(id)
|
|
|
|
|
+ };
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 关闭 Toast
|
|
|
|
|
+ const closeToast = (id) => {
|
|
|
|
|
+ const index = toasts.value.findIndex(t => t.id === id);
|
|
|
|
|
+ if (index === -1) return;
|
|
|
|
|
+
|
|
|
|
|
+ const toast = toasts.value[index];
|
|
|
|
|
+ if (toast.timer) clearTimeout(toast.timer);
|
|
|
|
|
+ if (toast.progressTimer) clearInterval(toast.progressTimer);
|
|
|
|
|
+
|
|
|
|
|
+ toast.closing = true;
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ const idx = toasts.value.findIndex(t => t.id === id);
|
|
|
|
|
+ if (idx > -1) {
|
|
|
|
|
+ toasts.value.splice(idx, 1);
|
|
|
|
|
+ updateToastsAutoClose();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 300);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 更新 Toast 自动关闭状态
|
|
|
|
|
+ const updateToastsAutoClose = () => {
|
|
|
|
|
+ const duration = 10000;
|
|
|
|
|
+
|
|
|
|
|
+ toasts.value.forEach((toast, index) => {
|
|
|
|
|
+ const isLast = index === toasts.value.length - 1;
|
|
|
|
|
+
|
|
|
|
|
+ if (toast.timer) {
|
|
|
|
|
+ clearTimeout(toast.timer);
|
|
|
|
|
+ toast.timer = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (toast.progressTimer) {
|
|
|
|
|
+ clearInterval(toast.progressTimer);
|
|
|
|
|
+ toast.progressTimer = null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (isLast) {
|
|
|
|
|
+ toast.progress = 0;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const startTime = Date.now();
|
|
|
|
|
+ toast.progress = 100;
|
|
|
|
|
+
|
|
|
|
|
+ toast.progressTimer = setInterval(() => {
|
|
|
|
|
+ const elapsed = Date.now() - startTime;
|
|
|
|
|
+ toast.progress = Math.max(0, 100 - (elapsed / duration) * 100);
|
|
|
|
|
+ }, 100);
|
|
|
|
|
+
|
|
|
|
|
+ toast.timer = setTimeout(() => {
|
|
|
|
|
+ closeToast(toast.id);
|
|
|
|
|
+ }, duration);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 便捷提示函数
|
|
|
|
|
+ const showError = (message, title = '错误') => showToast(message, { type: 'error', title });
|
|
|
|
|
+ const showWarning = (message, title = '警告') => showToast(message, { type: 'warning', title });
|
|
|
|
|
+ const showSuccess = (message, title = '成功') => showToast(message, { type: 'success', title });
|
|
|
|
|
+
|
|
|
|
|
+ // 加载单个软件的版本
|
|
|
|
|
+ const loadVersionForSoftware = async (software) => {
|
|
|
|
|
+ versions[software].loading = true;
|
|
|
|
|
+ versions[software].error = false;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const result = await window.electronAPI.getVersions(software);
|
|
|
|
|
+ const versionList = result.versions || result;
|
|
|
|
|
+ const warning = result.warning;
|
|
|
|
|
+
|
|
|
|
|
+ if (warning) {
|
|
|
|
|
+ showWarning(warning, `${softwareNames[software]} 版本获取`);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ versions[software].list = versionList;
|
|
|
|
|
+ versions[software].loading = false;
|
|
|
|
|
+
|
|
|
|
|
+ // 自动选中第一个可选版本
|
|
|
|
|
+ const firstSelectable = versionList.find(v => !v.disabled && !v.separator);
|
|
|
|
|
+ if (firstSelectable) {
|
|
|
|
|
+ selectedVersions[software] = firstSelectable.value;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(`加载 ${software} 版本失败:`, error);
|
|
|
|
|
+ showError(`${softwareNames[software]} 版本列表加载失败,请检查网络连接或代理设置`, '版本加载失败');
|
|
|
|
|
+ versions[software].loading = false;
|
|
|
|
|
+ versions[software].error = true;
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 加载所有版本
|
|
|
|
|
+ const loadAllVersions = async () => {
|
|
|
|
|
+ const loadPromises = softwareList.map(software => loadVersionForSoftware(software));
|
|
|
|
|
+ await Promise.all(loadPromises);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化代理设置
|
|
|
|
|
+ const initProxySettings = async () => {
|
|
|
|
|
+ const settings = await window.electronAPI.getProxy();
|
|
|
|
|
+ for (const software of softwareList) {
|
|
|
|
|
+ if (settings[software]) {
|
|
|
|
|
+ proxySettings[software].enabled = settings[software].enabled;
|
|
|
|
|
+ proxySettings[software].url = settings[software].url;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 保存代理设置
|
|
|
|
|
+ const saveProxySettings = async () => {
|
|
|
|
|
+ const settings = {};
|
|
|
|
|
+ for (const software of softwareList) {
|
|
|
|
|
+ settings[software] = {
|
|
|
|
|
+ enabled: proxySettings[software].enabled,
|
|
|
|
|
+ url: proxySettings[software].url
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ await window.electronAPI.setProxy(settings);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 代理开关变化处理
|
|
|
|
|
+ const onProxyToggle = async (software) => {
|
|
|
|
|
+ await saveProxySettings();
|
|
|
|
|
+ await loadVersionForSoftware(software);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 代理地址变化处理
|
|
|
|
|
+ const onProxyUrlBlur = async (software) => {
|
|
|
|
|
+ await saveProxySettings();
|
|
|
|
|
+ if (proxySettings[software].enabled) {
|
|
|
|
|
+ await loadVersionForSoftware(software);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 执行安装
|
|
|
|
|
+ const doInstall = async (software) => {
|
|
|
|
|
+ if (isLoadingVersions.value) return;
|
|
|
|
|
+
|
|
|
|
|
+ const status = installStatus[software];
|
|
|
|
|
+ status.installing = true;
|
|
|
|
|
+ status.message = '正在准备安装...';
|
|
|
|
|
+ status.progress = 0;
|
|
|
|
|
+ status.success = false;
|
|
|
|
|
+ status.error = false;
|
|
|
|
|
+
|
|
|
|
|
+ const options = {
|
|
|
|
|
+ version: selectedVersions[software === 'all' ? 'nodejs' : software]
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (software === 'nodejs') {
|
|
|
|
|
+ options.installPnpm = installOptions.nodejs.installPnpm;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (software === 'all') {
|
|
|
|
|
+ options.installNodejs = installOptions.all.installNodejs;
|
|
|
|
|
+ options.nodejsVersion = selectedVersions.nodejs;
|
|
|
|
|
+ options.installPnpm = installOptions.all.installPnpm;
|
|
|
|
|
+ options.installVscode = installOptions.all.installVscode;
|
|
|
|
|
+ options.vscodeVersion = selectedVersions.vscode;
|
|
|
|
|
+ options.installGit = installOptions.all.installGit;
|
|
|
|
|
+ options.gitVersion = selectedVersions.git;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ await window.electronAPI.install(software, options);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 绑定安装状态监听
|
|
|
|
|
+ const bindInstallListeners = () => {
|
|
|
|
|
+ window.electronAPI.onInstallStatus((data) => {
|
|
|
|
|
+ const { software, message, progress } = data;
|
|
|
|
|
+ const key = software === 'all' ? 'all' : software;
|
|
|
|
|
+ if (installStatus[key]) {
|
|
|
|
|
+ installStatus[key].message = message;
|
|
|
|
|
+ if (progress !== undefined) {
|
|
|
|
|
+ installStatus[key].progress = progress;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ window.electronAPI.onInstallComplete((data) => {
|
|
|
|
|
+ const { software, message } = data;
|
|
|
|
|
+ const key = software === 'all' ? 'all' : software;
|
|
|
|
|
+ if (installStatus[key]) {
|
|
|
|
|
+ installStatus[key].installing = false;
|
|
|
|
|
+ installStatus[key].message = message;
|
|
|
|
|
+ installStatus[key].progress = 100;
|
|
|
|
|
+ installStatus[key].success = true;
|
|
|
|
|
+ installStatus[key].error = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ window.electronAPI.onInstallError((data) => {
|
|
|
|
|
+ const { software, message } = data;
|
|
|
|
|
+ const key = software === 'all' ? 'all' : software;
|
|
|
|
|
+ if (installStatus[key]) {
|
|
|
|
|
+ installStatus[key].installing = false;
|
|
|
|
|
+ installStatus[key].message = message;
|
|
|
|
|
+ installStatus[key].success = false;
|
|
|
|
|
+ installStatus[key].error = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ showError(message, `${softwareNames[key]} 安装失败`);
|
|
|
|
|
+ });
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 检测系统状态
|
|
|
|
|
+ const checkSystemStatus = async () => {
|
|
|
|
|
+ const isAdmin = await window.electronAPI.checkAdmin();
|
|
|
|
|
+ if (!isAdmin) {
|
|
|
|
|
+ showSystemStatusMsg('warning', '未检测到管理员权限,安装时可能需要授权', null);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const pmResult = await window.electronAPI.checkPackageManager();
|
|
|
|
|
+ if (!pmResult.exists) {
|
|
|
|
|
+ const managerName = pmResult.manager === 'winget' ? 'Windows Package Manager (winget)' : 'Homebrew';
|
|
|
|
|
+ showSystemStatusMsg(
|
|
|
|
|
+ 'error',
|
|
|
|
|
+ `未检测到 ${managerName},需要先安装`,
|
|
|
|
|
+ {
|
|
|
|
|
+ text: `安装 ${pmResult.manager}`,
|
|
|
|
|
+ action: () => installPackageManager(pmResult.manager)
|
|
|
|
|
+ }
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 显示系统状态
|
|
|
|
|
+ const showSystemStatusMsg = (type, message, action) => {
|
|
|
|
|
+ systemStatus.visible = true;
|
|
|
|
|
+ systemStatus.type = type;
|
|
|
|
|
+ systemStatus.message = message;
|
|
|
|
|
+ if (action) {
|
|
|
|
|
+ systemStatus.actionText = action.text;
|
|
|
|
|
+ systemStatus.actionHandler = action.action;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ systemStatus.actionText = '';
|
|
|
|
|
+ systemStatus.actionHandler = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 隐藏系统状态
|
|
|
|
|
+ const hideSystemStatus = () => {
|
|
|
|
|
+ systemStatus.visible = false;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 安装包管理器
|
|
|
|
|
+ const installPackageManager = async (manager) => {
|
|
|
|
|
+ systemStatus.actionText = '安装中...';
|
|
|
|
|
+
|
|
|
|
|
+ const result = await window.electronAPI.installPackageManager(manager);
|
|
|
|
|
+
|
|
|
|
|
+ if (result.success) {
|
|
|
|
|
+ showSystemStatusMsg('success', `${manager} 安装成功!`, null);
|
|
|
|
|
+ setTimeout(hideSystemStatus, 3000);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ showSystemStatusMsg('error', `${manager} 安装失败:${result.error}`, {
|
|
|
|
|
+ text: '重试',
|
|
|
|
|
+ action: () => installPackageManager(manager)
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 获取状态图标
|
|
|
|
|
+ const getStatusIcon = (type) => {
|
|
|
|
|
+ return type === 'warning' ? '⚠️' : type === 'error' ? '❌' : '✅';
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 获取 Toast 图标
|
|
|
|
|
+ const getToastIcon = (type) => {
|
|
|
|
|
+ const icons = { error: '❌', warning: '⚠️', success: '✅', info: 'ℹ️' };
|
|
|
|
|
+ return icons[type] || 'ℹ️';
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 生命周期 ====================
|
|
|
|
|
+
|
|
|
|
|
+ onMounted(async () => {
|
|
|
|
|
+ bindInstallListeners();
|
|
|
|
|
+ await initProxySettings();
|
|
|
|
|
+ await loadAllVersions();
|
|
|
|
|
+ await checkSystemStatus();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 页面卸载时移除监听
|
|
|
|
|
+ window.addEventListener('unload', () => {
|
|
|
|
|
+ window.electronAPI.removeAllListeners();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 返回模板使用的数据和方法 ====================
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ // 数据
|
|
|
|
|
+ activeTab,
|
|
|
|
|
+ softwareList,
|
|
|
|
|
+ softwareNames,
|
|
|
|
|
+ versions,
|
|
|
|
|
+ selectedVersions,
|
|
|
|
|
+ proxySettings,
|
|
|
|
|
+ installOptions,
|
|
|
|
|
+ installStatus,
|
|
|
|
|
+ systemStatus,
|
|
|
|
|
+ toasts,
|
|
|
|
|
+
|
|
|
|
|
+ // 计算属性
|
|
|
|
|
+ isLoadingVersions,
|
|
|
|
|
+ hasVersionError,
|
|
|
|
|
+ allVersionsLoaded,
|
|
|
|
|
+ allPaneStatusText,
|
|
|
|
|
+
|
|
|
|
|
+ // 方法
|
|
|
|
|
+ switchTab,
|
|
|
|
|
+ getStatusText,
|
|
|
|
|
+ isInstallDisabled,
|
|
|
|
|
+ getInstallButtonText,
|
|
|
|
|
+ formatVersionLabel,
|
|
|
|
|
+ showToast,
|
|
|
|
|
+ closeToast,
|
|
|
|
|
+ showError,
|
|
|
|
|
+ showWarning,
|
|
|
|
|
+ showSuccess,
|
|
|
|
|
+ loadVersionForSoftware,
|
|
|
|
|
+ loadAllVersions,
|
|
|
|
|
+ onProxyToggle,
|
|
|
|
|
+ onProxyUrlBlur,
|
|
|
|
|
+ doInstall,
|
|
|
|
|
+ getStatusIcon,
|
|
|
|
|
+ getToastIcon,
|
|
|
|
|
+ hideSystemStatus
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 挂载应用
|
|
|
|
|
+app.mount('#app');
|