Browse Source

引入Vue

黄中银 1 month ago
parent
commit
7bbc6ce462

+ 0 - 26
ApqInstaller/package-lock.json

@@ -2445,32 +2445,6 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
-    "node_modules/encoding": {
-      "version": "0.1.13",
-      "resolved": "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz",
-      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "dependencies": {
-        "iconv-lite": "^0.6.2"
-      }
-    },
-    "node_modules/encoding/node_modules/iconv-lite": {
-      "version": "0.6.3",
-      "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz",
-      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "dependencies": {
-        "safer-buffer": ">= 2.1.2 < 3.0.0"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/end-of-stream": {
     "node_modules/end-of-stream": {
       "version": "1.4.5",
       "version": "1.4.5",
       "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.5.tgz",
       "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.5.tgz",

+ 0 - 67
ApqInstaller/src/html/settings-panel.js

@@ -1,67 +0,0 @@
-// src/html/settings-panel.js - 设置面板组件
-class SettingsPanel extends HTMLElement {
-    constructor() {
-        super();
-    }
-
-    connectedCallback() {
-        this.innerHTML = `
-            <h2>代理设置</h2>
-            <div class="settings-content">
-                <!-- Node.js 代理设置 -->
-                <div class="setting-group">
-                    <h3>Node.js</h3>
-                    <div class="setting-item">
-                        <label class="checkbox-label">
-                            <input type="checkbox" id="nodejs-use-proxy">
-                            <span>使用国内代理</span>
-                        </label>
-                    </div>
-                    <div class="setting-item proxy-url-item" id="nodejs-proxy-item">
-                        <label class="setting-label">代理地址</label>
-                        <input type="text" id="nodejs-proxy-url" class="proxy-input" value="https://npmmirror.com/mirrors/node/">
-                    </div>
-                </div>
-
-                <!-- VS Code 代理设置 -->
-                <div class="setting-group">
-                    <h3>VS Code</h3>
-                    <div class="setting-item">
-                        <label class="checkbox-label">
-                            <input type="checkbox" id="vscode-use-proxy">
-                            <span>使用国内代理</span>
-                        </label>
-                    </div>
-                    <div class="setting-item proxy-url-item" id="vscode-proxy-item">
-                        <label class="setting-label">代理地址</label>
-                        <input type="text" id="vscode-proxy-url" class="proxy-input" value="https://registry.npmmirror.com/-/binary/vscode/">
-                    </div>
-                </div>
-
-                <!-- Git 代理设置 -->
-                <div class="setting-group">
-                    <h3>Git</h3>
-                    <div class="setting-item">
-                        <label class="checkbox-label">
-                            <input type="checkbox" id="git-use-proxy">
-                            <span>使用国内代理</span>
-                        </label>
-                    </div>
-                    <div class="setting-item proxy-url-item" id="git-proxy-item">
-                        <label class="setting-label">代理地址</label>
-                        <input type="text" id="git-proxy-url" class="proxy-input" value="https://registry.npmmirror.com/-/binary/git-for-windows/">
-                    </div>
-                </div>
-
-                <!-- 代理说明 -->
-                <div class="setting-group">
-                    <div class="proxy-info">
-                        <p>启用代理后将加速版本列表获取,适合网络访问较慢的情况</p>
-                    </div>
-                </div>
-            </div>
-        `;
-    }
-}
-
-customElements.define('settings-panel', SettingsPanel);

+ 0 - 70
ApqInstaller/src/html/tab-all.js

@@ -1,70 +0,0 @@
-// src/html/tab-all.js - 一键全装页组件
-class TabAll extends HTMLElement {
-    constructor() {
-        super();
-    }
-
-    connectedCallback() {
-        this.innerHTML = `
-            <div class="software-info">
-                <h2>一键安装全部</h2>
-                <p>自定义安装 Node.js、VS Code、Git</p>
-            </div>
-            <div class="all-options">
-                <!-- Node.js 选项 -->
-                <div class="option-group">
-                    <div class="checkbox-option">
-                        <label class="checkbox-label">
-                            <input type="checkbox" id="all-install-nodejs" checked>
-                            <span>Node.js</span>
-                        </label>
-                    </div>
-                    <div class="option-details">
-                        <select id="all-nodejs-version" class="version-dropdown-small" data-software="nodejs">
-                            <option value="">...</option>
-                        </select>
-                        <label class="checkbox-label-small">
-                            <input type="checkbox" id="all-install-pnpm" checked>
-                            <span>+ pnpm</span>
-                        </label>
-                    </div>
-                </div>
-                <!-- VS Code 选项 -->
-                <div class="option-group">
-                    <div class="checkbox-option">
-                        <label class="checkbox-label">
-                            <input type="checkbox" id="all-install-vscode" checked>
-                            <span>VS Code</span>
-                        </label>
-                    </div>
-                    <div class="option-details">
-                        <select id="all-vscode-version" class="version-dropdown-small" data-software="vscode">
-                            <option value="">...</option>
-                        </select>
-                    </div>
-                </div>
-                <!-- Git 选项 -->
-                <div class="option-group">
-                    <div class="checkbox-option">
-                        <label class="checkbox-label">
-                            <input type="checkbox" id="all-install-git" checked>
-                            <span>Git</span>
-                        </label>
-                    </div>
-                    <div class="option-details">
-                        <select id="all-git-version" class="version-dropdown-small" data-software="git">
-                            <option value="">...</option>
-                        </select>
-                    </div>
-                </div>
-            </div>
-            <button class="btn-primary install-btn" data-software="all">开始一键安装</button>
-            <div class="status-container">
-                <p class="status-text">就绪</p>
-                <progress class="progress-bar" value="0" max="100" hidden></progress>
-            </div>
-        `;
-    }
-}
-
-customElements.define('tab-all', TabAll);

+ 0 - 28
ApqInstaller/src/html/tab-git.js

@@ -1,28 +0,0 @@
-// src/html/tab-git.js - Git 页组件
-class TabGit extends HTMLElement {
-    constructor() {
-        super();
-    }
-
-    connectedCallback() {
-        this.innerHTML = `
-            <div class="software-info">
-                <h2>Git</h2>
-                <p>分布式版本控制系统</p>
-            </div>
-            <div class="version-select">
-                <label for="git-version">选择版本:</label>
-                <select id="git-version" class="version-dropdown" data-software="git">
-                    <option value="">加载中...</option>
-                </select>
-            </div>
-            <button class="btn-primary install-btn" data-software="git">安装 Git</button>
-            <div class="status-container">
-                <p class="status-text">就绪</p>
-                <progress class="progress-bar" value="0" max="100" hidden></progress>
-            </div>
-        `;
-    }
-}
-
-customElements.define('tab-git', TabGit);

+ 0 - 52
ApqInstaller/src/html/tab-intro.js

@@ -1,52 +0,0 @@
-// src/html/tab-intro.js - 功能介绍页组件
-class TabIntro extends HTMLElement {
-    constructor() {
-        super();
-    }
-
-    connectedCallback() {
-        this.innerHTML = `
-            <div class="intro-content">
-                <div class="intro-header">
-                    <h2>欢迎使用开发工具安装器</h2>
-                    <p class="intro-subtitle">一站式安装前端开发必备工具</p>
-                </div>
-                <div class="intro-features">
-                    <div class="feature-item">
-                        <div class="feature-icon">📦</div>
-                        <div class="feature-text">
-                            <h3>Node.js</h3>
-                            <p>JavaScript 运行时环境,支持多版本选择,可同时安装 pnpm 包管理器</p>
-                        </div>
-                    </div>
-                    <div class="feature-item">
-                        <div class="feature-icon">💻</div>
-                        <div class="feature-text">
-                            <h3>VS Code</h3>
-                            <p>轻量级但功能强大的代码编辑器,支持稳定版和预览版</p>
-                        </div>
-                    </div>
-                    <div class="feature-item">
-                        <div class="feature-icon">🔀</div>
-                        <div class="feature-text">
-                            <h3>Git</h3>
-                            <p>分布式版本控制系统,支持完整版、精简版和 LFS 扩展</p>
-                        </div>
-                    </div>
-                    <div class="feature-item">
-                        <div class="feature-icon">🚀</div>
-                        <div class="feature-text">
-                            <h3>一键安装</h3>
-                            <p>自定义选择需要的工具,一次性完成所有安装</p>
-                        </div>
-                    </div>
-                </div>
-                <div class="intro-tips">
-                    <p>💡 提示:如果网络访问较慢,可在右侧设置面板开启国内代理加速</p>
-                </div>
-            </div>
-        `;
-    }
-}
-
-customElements.define('tab-intro', TabIntro);

+ 0 - 34
ApqInstaller/src/html/tab-nodejs.js

@@ -1,34 +0,0 @@
-// src/html/tab-nodejs.js - Node.js 页组件
-class TabNodejs extends HTMLElement {
-    constructor() {
-        super();
-    }
-
-    connectedCallback() {
-        this.innerHTML = `
-            <div class="software-info">
-                <h2>Node.js</h2>
-                <p>JavaScript 运行时环境,用于服务端开发</p>
-            </div>
-            <div class="version-select">
-                <label for="nodejs-version">选择版本:</label>
-                <select id="nodejs-version" class="version-dropdown" data-software="nodejs">
-                    <option value="">加载中...</option>
-                </select>
-            </div>
-            <div class="checkbox-option">
-                <label class="checkbox-label">
-                    <input type="checkbox" id="nodejs-install-pnpm" checked>
-                    <span>同时安装 pnpm (快速包管理器)</span>
-                </label>
-            </div>
-            <button class="btn-primary install-btn" data-software="nodejs">安装 Node.js</button>
-            <div class="status-container">
-                <p class="status-text">就绪</p>
-                <progress class="progress-bar" value="0" max="100" hidden></progress>
-            </div>
-        `;
-    }
-}
-
-customElements.define('tab-nodejs', TabNodejs);

+ 0 - 28
ApqInstaller/src/html/tab-vscode.js

@@ -1,28 +0,0 @@
-// src/html/tab-vscode.js - VS Code 页组件
-class TabVscode extends HTMLElement {
-    constructor() {
-        super();
-    }
-
-    connectedCallback() {
-        this.innerHTML = `
-            <div class="software-info">
-                <h2>Visual Studio Code</h2>
-                <p>轻量级但功能强大的代码编辑器</p>
-            </div>
-            <div class="version-select">
-                <label for="vscode-version">选择版本:</label>
-                <select id="vscode-version" class="version-dropdown" data-software="vscode">
-                    <option value="">加载中...</option>
-                </select>
-            </div>
-            <button class="btn-primary install-btn" data-software="vscode">安装 VS Code</button>
-            <div class="status-container">
-                <p class="status-text">就绪</p>
-                <progress class="progress-bar" value="0" max="100" hidden></progress>
-            </div>
-        `;
-    }
-}
-
-customElements.define('tab-vscode', TabVscode);

+ 310 - 58
ApqInstaller/src/index.html

@@ -9,78 +9,330 @@
 </head>
 </head>
 
 
 <body>
 <body>
-    <!-- 浮动错误提示层容器 -->
-    <div id="toastContainer" class="toast-container"></div>
-
-    <div class="app-container">
-        <!-- 左侧主内容区 -->
-        <div class="main-panel">
-            <h1>开发工具安装器</h1>
-
-            <!-- 系统状态提示栏 -->
-            <div id="systemStatus" class="system-status hidden">
-                <span id="statusIcon"></span>
-                <span id="statusMessage"></span>
-                <button id="statusAction" class="btn-small hidden"></button>
+    <div id="app">
+        <!-- 浮动错误提示层容器 -->
+        <div class="toast-container">
+            <div v-for="toast in toasts" :key="toast.id" :class="['toast-item', toast.type, { closing: toast.closing }]">
+                <span class="toast-icon">{{ getToastIcon(toast.type) }}</span>
+                <div class="toast-content">
+                    <div class="toast-title">{{ toast.title }}</div>
+                    <div class="toast-message">{{ toast.message }}</div>
+                </div>
+                <button class="toast-close" @click="closeToast(toast.id)">&times;</button>
+                <div class="toast-progress" :style="{ width: toast.progress + '%' }"></div>
             </div>
             </div>
+        </div>
 
 
-            <!-- 标签页导航 -->
-            <div class="tabs">
-                <button class="tab-btn active" data-tab="intro">功能介绍</button>
-                <button class="tab-btn" data-tab="nodejs">Node.js</button>
-                <button class="tab-btn" data-tab="vscode">VS Code</button>
-                <button class="tab-btn" data-tab="git">Git</button>
-                <button class="tab-btn" data-tab="all">一键全装</button>
-            </div>
+        <div class="app-container">
+            <!-- 左侧主内容区 -->
+            <div class="main-panel">
+                <h1>开发工具安装器</h1>
 
 
-            <!-- 标签页内容 -->
-            <div class="tab-content">
-                <!-- 功能介绍页面 -->
-                <div class="tab-pane active" id="intro">
-                    <tab-intro></tab-intro>
+                <!-- 系统状态提示栏 -->
+                <div :class="['system-status', systemStatus.type, { hidden: !systemStatus.visible }]">
+                    <span>{{ getStatusIcon(systemStatus.type) }}</span>
+                    <span>{{ systemStatus.message }}</span>
+                    <button v-if="systemStatus.actionText" class="btn-small" @click="systemStatus.actionHandler">
+                        {{ systemStatus.actionText }}
+                    </button>
                 </div>
                 </div>
 
 
-                <!-- Node.js 页面 -->
-                <div class="tab-pane" id="nodejs">
-                    <tab-nodejs></tab-nodejs>
+                <!-- 标签页导航 -->
+                <div class="tabs">
+                    <button :class="['tab-btn', { active: activeTab === 'intro' }]" @click="switchTab('intro')">功能介绍</button>
+                    <button :class="['tab-btn', { active: activeTab === 'nodejs' }]" @click="switchTab('nodejs')">Node.js</button>
+                    <button :class="['tab-btn', { active: activeTab === 'vscode' }]" @click="switchTab('vscode')">VS Code</button>
+                    <button :class="['tab-btn', { active: activeTab === 'git' }]" @click="switchTab('git')">Git</button>
+                    <button :class="['tab-btn', { active: activeTab === 'all' }]" @click="switchTab('all')">一键全装</button>
                 </div>
                 </div>
 
 
-                <!-- VS Code 页面 -->
-                <div class="tab-pane" id="vscode">
-                    <tab-vscode></tab-vscode>
-                </div>
+                <!-- 标签页内容 -->
+                <div class="tab-content">
+                    <!-- 功能介绍页面 -->
+                    <div :class="['tab-pane', { active: activeTab === 'intro' }]">
+                        <div class="intro-content">
+                            <div class="intro-header">
+                                <h2>欢迎使用开发工具安装器</h2>
+                                <p class="intro-subtitle">一站式安装前端开发必备工具</p>
+                            </div>
+                            <div class="intro-features">
+                                <div class="feature-item">
+                                    <div class="feature-icon">📦</div>
+                                    <div class="feature-text">
+                                        <h3>Node.js</h3>
+                                        <p>JavaScript 运行时环境,支持多版本选择,可同时安装 pnpm 包管理器</p>
+                                    </div>
+                                </div>
+                                <div class="feature-item">
+                                    <div class="feature-icon">💻</div>
+                                    <div class="feature-text">
+                                        <h3>VS Code</h3>
+                                        <p>轻量级但功能强大的代码编辑器,支持稳定版和预览版</p>
+                                    </div>
+                                </div>
+                                <div class="feature-item">
+                                    <div class="feature-icon">🔀</div>
+                                    <div class="feature-text">
+                                        <h3>Git</h3>
+                                        <p>分布式版本控制系统,支持完整版、精简版和 LFS 扩展</p>
+                                    </div>
+                                </div>
+                                <div class="feature-item">
+                                    <div class="feature-icon">🚀</div>
+                                    <div class="feature-text">
+                                        <h3>一键安装</h3>
+                                        <p>自定义选择需要的工具,一次性完成所有安装</p>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="intro-tips">
+                                <p>💡 提示:如果网络访问较慢,可在右侧设置面板开启国内代理加速</p>
+                            </div>
+                        </div>
+                    </div>
 
 
-                <!-- Git 页面 -->
-                <div class="tab-pane" id="git">
-                    <tab-git></tab-git>
-                </div>
+                    <!-- Node.js 页面 -->
+                    <div :class="['tab-pane', { active: activeTab === 'nodejs' }]">
+                        <div class="software-info">
+                            <h2>Node.js</h2>
+                            <p>JavaScript 运行时环境,用于服务端开发</p>
+                        </div>
+                        <div class="version-select">
+                            <label>选择版本:</label>
+                            <select v-model="selectedVersions.nodejs" class="version-dropdown" :disabled="versions.nodejs.loading || versions.nodejs.error">
+                                <option v-if="versions.nodejs.loading" value="" disabled>加载中...</option>
+                                <option v-else-if="versions.nodejs.error" value="" disabled>加载失败</option>
+                                <template v-else>
+                                    <option v-for="v in versions.nodejs.list" :key="v.value" :value="v.value" :disabled="v.disabled || v.separator" :class="{ 'separator-option': v.disabled || v.separator }">
+                                        {{ v.label }}
+                                    </option>
+                                </template>
+                            </select>
+                        </div>
+                        <div class="checkbox-option">
+                            <label class="checkbox-label">
+                                <input type="checkbox" v-model="installOptions.nodejs.installPnpm">
+                                <span>同时安装 pnpm (快速包管理器)</span>
+                            </label>
+                        </div>
+                        <button class="btn-primary install-btn" :disabled="isInstallDisabled('nodejs')" @click="doInstall('nodejs')">
+                            {{ getInstallButtonText('nodejs') }}
+                        </button>
+                        <div class="status-container">
+                            <p :class="['status-text', { success: installStatus.nodejs.success, error: installStatus.nodejs.error }]">
+                                {{ getStatusText('nodejs') }}
+                            </p>
+                            <progress class="progress-bar" :value="installStatus.nodejs.progress" max="100" :hidden="!installStatus.nodejs.installing"></progress>
+                        </div>
+                    </div>
+
+                    <!-- VS Code 页面 -->
+                    <div :class="['tab-pane', { active: activeTab === 'vscode' }]">
+                        <div class="software-info">
+                            <h2>Visual Studio Code</h2>
+                            <p>轻量级但功能强大的代码编辑器</p>
+                        </div>
+                        <div class="version-select">
+                            <label>选择版本:</label>
+                            <select v-model="selectedVersions.vscode" class="version-dropdown" :disabled="versions.vscode.loading || versions.vscode.error">
+                                <option v-if="versions.vscode.loading" value="" disabled>加载中...</option>
+                                <option v-else-if="versions.vscode.error" value="" disabled>加载失败</option>
+                                <template v-else>
+                                    <option v-for="v in versions.vscode.list" :key="v.value" :value="v.value" :disabled="v.disabled || v.separator" :class="{ 'separator-option': v.disabled || v.separator }">
+                                        {{ v.label }}
+                                    </option>
+                                </template>
+                            </select>
+                        </div>
+                        <button class="btn-primary install-btn" :disabled="isInstallDisabled('vscode')" @click="doInstall('vscode')">
+                            {{ getInstallButtonText('vscode') }}
+                        </button>
+                        <div class="status-container">
+                            <p :class="['status-text', { success: installStatus.vscode.success, error: installStatus.vscode.error }]">
+                                {{ getStatusText('vscode') }}
+                            </p>
+                            <progress class="progress-bar" :value="installStatus.vscode.progress" max="100" :hidden="!installStatus.vscode.installing"></progress>
+                        </div>
+                    </div>
+
+                    <!-- Git 页面 -->
+                    <div :class="['tab-pane', { active: activeTab === 'git' }]">
+                        <div class="software-info">
+                            <h2>Git</h2>
+                            <p>分布式版本控制系统</p>
+                        </div>
+                        <div class="version-select">
+                            <label>选择版本:</label>
+                            <select v-model="selectedVersions.git" class="version-dropdown" :disabled="versions.git.loading || versions.git.error">
+                                <option v-if="versions.git.loading" value="" disabled>加载中...</option>
+                                <option v-else-if="versions.git.error" value="" disabled>加载失败</option>
+                                <template v-else>
+                                    <option v-for="v in versions.git.list" :key="v.value" :value="v.value" :disabled="v.disabled || v.separator" :class="{ 'separator-option': v.disabled || v.separator }">
+                                        {{ v.label }}
+                                    </option>
+                                </template>
+                            </select>
+                        </div>
+                        <button class="btn-primary install-btn" :disabled="isInstallDisabled('git')" @click="doInstall('git')">
+                            {{ getInstallButtonText('git') }}
+                        </button>
+                        <div class="status-container">
+                            <p :class="['status-text', { success: installStatus.git.success, error: installStatus.git.error }]">
+                                {{ getStatusText('git') }}
+                            </p>
+                            <progress class="progress-bar" :value="installStatus.git.progress" max="100" :hidden="!installStatus.git.installing"></progress>
+                        </div>
+                    </div>
 
 
-                <!-- 一键全装 页面 -->
-                <div class="tab-pane" id="all">
-                    <tab-all></tab-all>
+                    <!-- 一键全装 页面 -->
+                    <div :class="['tab-pane', { active: activeTab === 'all' }]">
+                        <div class="software-info">
+                            <h2>一键安装全部</h2>
+                            <p>自定义安装 Node.js、VS Code、Git</p>
+                        </div>
+                        <div class="all-options">
+                            <!-- Node.js 选项 -->
+                            <div class="option-group">
+                                <div class="checkbox-option">
+                                    <label class="checkbox-label">
+                                        <input type="checkbox" v-model="installOptions.all.installNodejs">
+                                        <span>Node.js</span>
+                                    </label>
+                                </div>
+                                <div class="option-details">
+                                    <select v-model="selectedVersions.nodejs" class="version-dropdown-small" :disabled="versions.nodejs.loading || versions.nodejs.error">
+                                        <option v-if="versions.nodejs.loading" value="" disabled>...</option>
+                                        <option v-else-if="versions.nodejs.error" value="" disabled>失败</option>
+                                        <template v-else>
+                                            <option v-for="v in versions.nodejs.list" :key="v.value" :value="v.value" :disabled="v.disabled || v.separator" :class="{ 'separator-option': v.disabled || v.separator }">
+                                                {{ formatVersionLabel(v.label, true) }}
+                                            </option>
+                                        </template>
+                                    </select>
+                                    <label class="checkbox-label-small">
+                                        <input type="checkbox" v-model="installOptions.all.installPnpm">
+                                        <span>+ pnpm</span>
+                                    </label>
+                                </div>
+                            </div>
+                            <!-- VS Code 选项 -->
+                            <div class="option-group">
+                                <div class="checkbox-option">
+                                    <label class="checkbox-label">
+                                        <input type="checkbox" v-model="installOptions.all.installVscode">
+                                        <span>VS Code</span>
+                                    </label>
+                                </div>
+                                <div class="option-details">
+                                    <select v-model="selectedVersions.vscode" class="version-dropdown-small" :disabled="versions.vscode.loading || versions.vscode.error">
+                                        <option v-if="versions.vscode.loading" value="" disabled>...</option>
+                                        <option v-else-if="versions.vscode.error" value="" disabled>失败</option>
+                                        <template v-else>
+                                            <option v-for="v in versions.vscode.list" :key="v.value" :value="v.value" :disabled="v.disabled || v.separator" :class="{ 'separator-option': v.disabled || v.separator }">
+                                                {{ formatVersionLabel(v.label, true) }}
+                                            </option>
+                                        </template>
+                                    </select>
+                                </div>
+                            </div>
+                            <!-- Git 选项 -->
+                            <div class="option-group">
+                                <div class="checkbox-option">
+                                    <label class="checkbox-label">
+                                        <input type="checkbox" v-model="installOptions.all.installGit">
+                                        <span>Git</span>
+                                    </label>
+                                </div>
+                                <div class="option-details">
+                                    <select v-model="selectedVersions.git" class="version-dropdown-small" :disabled="versions.git.loading || versions.git.error">
+                                        <option v-if="versions.git.loading" value="" disabled>...</option>
+                                        <option v-else-if="versions.git.error" value="" disabled>失败</option>
+                                        <template v-else>
+                                            <option v-for="v in versions.git.list" :key="v.value" :value="v.value" :disabled="v.disabled || v.separator" :class="{ 'separator-option': v.disabled || v.separator }">
+                                                {{ formatVersionLabel(v.label, true) }}
+                                            </option>
+                                        </template>
+                                    </select>
+                                </div>
+                            </div>
+                        </div>
+                        <button class="btn-primary install-btn" :disabled="isInstallDisabled('all')" @click="doInstall('all')">
+                            {{ getInstallButtonText('all') }}
+                        </button>
+                        <div class="status-container">
+                            <p :class="['status-text', { success: installStatus.all.success, error: installStatus.all.error }]">
+                                {{ getStatusText('all') }}
+                            </p>
+                            <progress class="progress-bar" :value="installStatus.all.progress" max="100" :hidden="!installStatus.all.installing"></progress>
+                        </div>
+                    </div>
                 </div>
                 </div>
             </div>
             </div>
-        </div>
 
 
-        <!-- 右侧设置面板 -->
-        <div class="settings-panel">
-            <settings-panel></settings-panel>
+            <!-- 右侧设置面板 -->
+            <div class="settings-panel">
+                <h2>代理设置</h2>
+                <div class="settings-content">
+                    <!-- Node.js 代理设置 -->
+                    <div class="setting-group">
+                        <h3>Node.js</h3>
+                        <div class="setting-item">
+                            <label class="checkbox-label">
+                                <input type="checkbox" v-model="proxySettings.nodejs.enabled" @change="onProxyToggle('nodejs')">
+                                <span>使用国内代理</span>
+                            </label>
+                        </div>
+                        <div :class="['setting-item', 'proxy-url-item', { active: proxySettings.nodejs.enabled }]">
+                            <label class="setting-label">代理地址</label>
+                            <input type="text" v-model="proxySettings.nodejs.url" class="proxy-input" :disabled="!proxySettings.nodejs.enabled" @blur="onProxyUrlBlur('nodejs')">
+                        </div>
+                    </div>
+
+                    <!-- VS Code 代理设置 -->
+                    <div class="setting-group">
+                        <h3>VS Code</h3>
+                        <div class="setting-item">
+                            <label class="checkbox-label">
+                                <input type="checkbox" v-model="proxySettings.vscode.enabled" @change="onProxyToggle('vscode')">
+                                <span>使用国内代理</span>
+                            </label>
+                        </div>
+                        <div :class="['setting-item', 'proxy-url-item', { active: proxySettings.vscode.enabled }]">
+                            <label class="setting-label">代理地址</label>
+                            <input type="text" v-model="proxySettings.vscode.url" class="proxy-input" :disabled="!proxySettings.vscode.enabled" @blur="onProxyUrlBlur('vscode')">
+                        </div>
+                    </div>
+
+                    <!-- Git 代理设置 -->
+                    <div class="setting-group">
+                        <h3>Git</h3>
+                        <div class="setting-item">
+                            <label class="checkbox-label">
+                                <input type="checkbox" v-model="proxySettings.git.enabled" @change="onProxyToggle('git')">
+                                <span>使用国内代理</span>
+                            </label>
+                        </div>
+                        <div :class="['setting-item', 'proxy-url-item', { active: proxySettings.git.enabled }]">
+                            <label class="setting-label">代理地址</label>
+                            <input type="text" v-model="proxySettings.git.url" class="proxy-input" :disabled="!proxySettings.git.enabled" @blur="onProxyUrlBlur('git')">
+                        </div>
+                    </div>
+
+                    <!-- 代理说明 -->
+                    <div class="setting-group">
+                        <div class="proxy-info">
+                            <p>启用代理后将加速版本列表获取,适合网络访问较慢的情况</p>
+                        </div>
+                    </div>
+                </div>
+            </div>
         </div>
         </div>
     </div>
     </div>
-    <!-- Web Components -->
-    <script src="html/tab-intro.js"></script>
-    <script src="html/tab-nodejs.js"></script>
-    <script src="html/tab-vscode.js"></script>
-    <script src="html/tab-git.js"></script>
-    <script src="html/tab-all.js"></script>
-    <script src="html/settings-panel.js"></script>
-    <!-- 模块化脚本 -->
-    <script src="js/toast.js"></script>
-    <script src="js/system.js"></script>
-    <script src="js/proxy.js"></script>
-    <script src="js/version.js"></script>
-    <script src="js/install.js"></script>
-    <script src="js/renderer.js"></script>
+
+    <!-- Vue 3 CDN -->
+    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
+    <!-- Vue 应用 -->
+    <script src="js/app.js"></script>
 </body>
 </body>
 
 
 </html>
 </html>

+ 510 - 0
ApqInstaller/src/js/app.js

@@ -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');

+ 0 - 128
ApqInstaller/src/js/install.js

@@ -1,128 +0,0 @@
-// src/js/install.js - 安装逻辑模块
-
-// 获取版本选择
-function getVersionForSoftware(software) {
-    switch (software) {
-        case 'nodejs':
-            return document.getElementById('nodejs-version')?.value || 'lts';
-        case 'vscode':
-            return document.getElementById('vscode-version')?.value || 'stable';
-        case 'git':
-            return document.getElementById('git-version')?.value || 'stable';
-        case 'all':
-            return document.getElementById('all-nodejs-version')?.value || 'lts';
-        default:
-            return null;
-    }
-}
-
-// 获取安装选项
-function getOptionsForSoftware(software) {
-    const options = {
-        version: getVersionForSoftware(software)
-    };
-
-    if (software === 'nodejs') {
-        options.installPnpm = document.getElementById('nodejs-install-pnpm')?.checked ?? true;
-    }
-
-    if (software === 'all') {
-        // 一键安装的所有选项
-        options.installNodejs = document.getElementById('all-install-nodejs')?.checked ?? true;
-        options.nodejsVersion = document.getElementById('all-nodejs-version')?.value || 'lts';
-        options.installPnpm = document.getElementById('all-install-pnpm')?.checked ?? true;
-        options.installVscode = document.getElementById('all-install-vscode')?.checked ?? true;
-        options.vscodeVersion = document.getElementById('all-vscode-version')?.value || 'stable';
-        options.installGit = document.getElementById('all-install-git')?.checked ?? true;
-        options.gitVersion = document.getElementById('all-git-version')?.value || 'stable';
-    }
-
-    return options;
-}
-
-// 绑定安装按钮事件
-function bindInstallEvents() {
-    const installBtns = document.querySelectorAll('.install-btn');
-
-    installBtns.forEach(btn => {
-        btn.addEventListener('click', async () => {
-            // 如果正在加载版本,不允许安装
-            if (isLoadingVersions) return;
-
-            const software = btn.dataset.software;
-            const pane = btn.closest('.tab-pane');
-            const statusText = pane.querySelector('.status-text');
-            const progressBar = pane.querySelector('.progress-bar');
-
-            // 获取安装选项
-            const options = getOptionsForSoftware(software);
-
-            // 重置状态
-            btn.disabled = true;
-            btn.textContent = '安装中...';
-            statusText.textContent = '正在准备安装...';
-            statusText.className = 'status-text';
-            progressBar.value = 0;
-            progressBar.hidden = false;
-
-            // 调用对应的安装方法,传入选项
-            await window.electronAPI.install(software, options);
-        });
-    });
-}
-
-// 绑定安装状态监听
-function bindInstallListeners() {
-    // 监听安装状态更新
-    window.electronAPI.onInstallStatus((data) => {
-        const { software, message, progress } = data;
-        const pane = document.getElementById(software === 'all' ? 'all' : software);
-        if (!pane) return;
-
-        const statusText = pane.querySelector('.status-text');
-        const progressBar = pane.querySelector('.progress-bar');
-
-        statusText.textContent = message;
-        if (progress !== undefined) {
-            progressBar.value = progress;
-        }
-    });
-
-    // 监听安装完成
-    window.electronAPI.onInstallComplete((data) => {
-        const { software, message } = data;
-        const pane = document.getElementById(software === 'all' ? 'all' : software);
-        if (!pane) return;
-
-        const btn = pane.querySelector('.install-btn');
-        const statusText = pane.querySelector('.status-text');
-        const progressBar = pane.querySelector('.progress-bar');
-
-        statusText.textContent = message;
-        statusText.className = 'status-text success';
-        progressBar.value = 100;
-        btn.disabled = false;
-        btn.textContent = '安装完成';
-    });
-
-    // 监听安装错误
-    window.electronAPI.onInstallError((data) => {
-        const { software, message } = data;
-        const pane = document.getElementById(software === 'all' ? 'all' : software);
-        if (!pane) return;
-
-        const btn = pane.querySelector('.install-btn');
-        const statusText = pane.querySelector('.status-text');
-        const progressBar = pane.querySelector('.progress-bar');
-
-        statusText.textContent = message;
-        statusText.className = 'status-text error';
-        progressBar.hidden = true;
-        btn.disabled = false;
-        btn.textContent = '重新安装';
-
-        // 显示错误提示
-        const softwareNames = { nodejs: 'Node.js', vscode: 'VS Code', git: 'Git', all: '一键安装' };
-        showError(message, `${softwareNames[software]} 安装失败`);
-    });
-}

+ 0 - 94
ApqInstaller/src/js/proxy.js

@@ -1,94 +0,0 @@
-// src/js/proxy.js - 代理设置模块
-
-// 分软件代理设置元素
-const proxyElements = {
-    nodejs: {
-        checkbox: document.getElementById('nodejs-use-proxy'),
-        urlInput: document.getElementById('nodejs-proxy-url'),
-        urlItem: document.getElementById('nodejs-proxy-item')
-    },
-    vscode: {
-        checkbox: document.getElementById('vscode-use-proxy'),
-        urlInput: document.getElementById('vscode-proxy-url'),
-        urlItem: document.getElementById('vscode-proxy-item')
-    },
-    git: {
-        checkbox: document.getElementById('git-use-proxy'),
-        urlInput: document.getElementById('git-proxy-url'),
-        urlItem: document.getElementById('git-proxy-item')
-    }
-};
-
-// 初始化代理设置
-async function initProxySettings() {
-    const settings = await window.electronAPI.getProxy();
-
-    // 初始化各软件的代理设置 UI
-    for (const software of ['nodejs', 'vscode', 'git']) {
-        const elements = proxyElements[software];
-        const config = settings[software];
-
-        // 设置复选框状态
-        elements.checkbox.checked = config.enabled;
-        // 设置代理地址
-        elements.urlInput.value = config.url;
-        // 更新 UI 状态
-        updateProxyItemUI(software, config.enabled);
-    }
-}
-
-// 更新单个软件的代理 UI 状态
-function updateProxyItemUI(software, enabled) {
-    const elements = proxyElements[software];
-    if (enabled) {
-        elements.urlItem.classList.add('active');
-        elements.urlInput.disabled = false;
-    } else {
-        elements.urlItem.classList.remove('active');
-        elements.urlInput.disabled = true;
-    }
-}
-
-// 获取当前代理设置
-function getCurrentProxySettings() {
-    const settings = {};
-    for (const software of ['nodejs', 'vscode', 'git']) {
-        const elements = proxyElements[software];
-        settings[software] = {
-            enabled: elements.checkbox.checked,
-            url: elements.urlInput.value
-        };
-    }
-    return settings;
-}
-
-// 绑定代理设置事件
-function bindProxyEvents() {
-    for (const software of ['nodejs', 'vscode', 'git']) {
-        const elements = proxyElements[software];
-
-        // 复选框变化事件
-        elements.checkbox.addEventListener('change', async () => {
-            const enabled = elements.checkbox.checked;
-            updateProxyItemUI(software, enabled);
-
-            // 保存设置到后端
-            const settings = getCurrentProxySettings();
-            await window.electronAPI.setProxy(settings);
-
-            // 重新加载该软件的版本列表
-            await loadVersionForSoftware(software);
-        });
-
-        // 代理地址变化事件(失去焦点时保存)
-        elements.urlInput.addEventListener('blur', async () => {
-            const settings = getCurrentProxySettings();
-            await window.electronAPI.setProxy(settings);
-
-            // 如果代理已启用,重新加载版本列表
-            if (elements.checkbox.checked) {
-                await loadVersionForSoftware(software);
-            }
-        });
-    }
-}

+ 0 - 42
ApqInstaller/src/js/renderer.js

@@ -1,42 +0,0 @@
-// src/renderer.js - 主入口文件
-// 模块依赖: toast.js, proxy.js, version.js, install.js, system.js
-
-// --------------- 标签页切换 ---------------
-const tabBtns = document.querySelectorAll('.tab-btn');
-const tabPanes = document.querySelectorAll('.tab-pane');
-
-tabBtns.forEach(btn => {
-    btn.addEventListener('click', () => {
-        const tabId = btn.dataset.tab;
-
-        // 移除所有 active 状态
-        tabBtns.forEach(b => b.classList.remove('active'));
-        tabPanes.forEach(p => p.classList.remove('active'));
-
-        // 添加当前 active 状态
-        btn.classList.add('active');
-        document.getElementById(tabId).classList.add('active');
-    });
-});
-
-// --------------- 页面初始化 ---------------
-// 页面卸载时移除监听
-window.addEventListener('unload', () => {
-    window.electronAPI.removeAllListeners();
-});
-
-// 页面加载完成后初始化
-window.addEventListener('DOMContentLoaded', async () => {
-    // 绑定代理设置事件
-    bindProxyEvents();
-    // 绑定安装按钮事件
-    bindInstallEvents();
-    // 绑定安装状态监听
-    bindInstallListeners();
-    // 初始化代理设置
-    await initProxySettings();
-    // 加载版本列表
-    await loadAllVersions();
-    // 检测系统状态
-    await checkSystemStatus();
-});

+ 0 - 70
ApqInstaller/src/js/system.js

@@ -1,70 +0,0 @@
-// src/js/system.js - 系统检测模块
-
-// DOM 元素
-const systemStatus = document.getElementById('systemStatus');
-const statusIcon = document.getElementById('statusIcon');
-const statusMessage = document.getElementById('statusMessage');
-const statusAction = document.getElementById('statusAction');
-
-// 页面加载时检测系统状态
-async function checkSystemStatus() {
-    // 检测管理员权限
-    const isAdmin = await window.electronAPI.checkAdmin();
-    if (!isAdmin) {
-        showSystemStatus('warning', '未检测到管理员权限,安装时可能需要授权', null);
-    }
-
-    // 检测包管理器
-    const pmResult = await window.electronAPI.checkPackageManager();
-    if (!pmResult.exists) {
-        const managerName = pmResult.manager === 'winget' ? 'Windows Package Manager (winget)' : 'Homebrew';
-        showSystemStatus(
-            'error',
-            `未检测到 ${managerName},需要先安装`,
-            {
-                text: `安装 ${pmResult.manager}`,
-                action: () => installPackageManager(pmResult.manager)
-            }
-        );
-    }
-}
-
-// 显示系统状态
-function showSystemStatus(type, message, action) {
-    systemStatus.classList.remove('hidden', 'warning', 'error', 'success');
-    systemStatus.classList.add(type);
-
-    statusIcon.textContent = type === 'warning' ? '⚠️' : type === 'error' ? '❌' : '✅';
-    statusMessage.textContent = message;
-
-    if (action) {
-        statusAction.textContent = action.text;
-        statusAction.classList.remove('hidden');
-        statusAction.onclick = action.action;
-    } else {
-        statusAction.classList.add('hidden');
-    }
-}
-
-// 隐藏系统状态
-function hideSystemStatus() {
-    systemStatus.classList.add('hidden');
-}
-
-// 安装包管理器
-async function installPackageManager(manager) {
-    statusAction.disabled = true;
-    statusAction.textContent = '安装中...';
-
-    const result = await window.electronAPI.installPackageManager(manager);
-
-    if (result.success) {
-        showSystemStatus('success', `${manager} 安装成功!`, null);
-        setTimeout(hideSystemStatus, 3000);
-    } else {
-        showSystemStatus('error', `${manager} 安装失败:${result.error}`, {
-            text: '重试',
-            action: () => installPackageManager(manager)
-        });
-    }
-}

+ 0 - 151
ApqInstaller/src/js/toast.js

@@ -1,151 +0,0 @@
-// src/js/toast.js - 浮动提示层模块
-
-const toastContainer = document.getElementById('toastContainer');
-const toasts = []; // 存储所有 toast 实例
-
-// 显示 toast 提示
-function showToast(message, options = {}) {
-    const {
-        type = 'error',      // 类型: error, warning, success, info
-        title = type === 'error' ? '错误' : type === 'warning' ? '警告' : type === 'success' ? '成功' : '提示',
-        closable = true      // 是否可手动关闭
-    } = options;
-
-    // 创建 toast 元素
-    const toast = document.createElement('div');
-    toast.className = `toast-item ${type}`;
-
-    // 图标
-    const icons = {
-        error: '❌',
-        warning: '⚠️',
-        success: '✅',
-        info: 'ℹ️'
-    };
-
-    toast.innerHTML = `
-        <span class="toast-icon">${icons[type]}</span>
-        <div class="toast-content">
-            <div class="toast-title">${title}</div>
-            <div class="toast-message">${message}</div>
-        </div>
-        ${closable ? '<button class="toast-close">×</button>' : ''}
-        <div class="toast-progress" style="width: 100%"></div>
-    `;
-
-    // 添加到容器
-    toastContainer.appendChild(toast);
-
-    // 存储 toast 信息
-    const toastInfo = {
-        element: toast,
-        timer: null,
-        progressTimer: null
-    };
-    toasts.push(toastInfo);
-
-    // 关闭函数
-    const closeToast = () => {
-        // 清除定时器
-        if (toastInfo.timer) clearTimeout(toastInfo.timer);
-        if (toastInfo.progressTimer) clearInterval(toastInfo.progressTimer);
-
-        // 添加关闭动画
-        toast.classList.add('closing');
-
-        // 动画结束后移除元素
-        setTimeout(() => {
-            if (toast.parentNode) {
-                toast.parentNode.removeChild(toast);
-            }
-            // 从数组中移除
-            const index = toasts.indexOf(toastInfo);
-            if (index > -1) {
-                toasts.splice(index, 1);
-            }
-            // 更新其他 toast 的自动关闭状态
-            updateToastsAutoClose();
-        }, 300);
-    };
-
-    // 绑定关闭按钮事件
-    if (closable) {
-        const closeBtn = toast.querySelector('.toast-close');
-        closeBtn.addEventListener('click', closeToast);
-    }
-
-    // 更新所有 toast 的自动关闭状态
-    updateToastsAutoClose();
-
-    return { close: closeToast };
-}
-
-// 更新 toast 的自动关闭状态
-// 规则:除了最后一个,其他都在 10 秒后自动关闭
-function updateToastsAutoClose() {
-    const duration = 10000; // 10 秒
-
-    toasts.forEach((toastInfo, index) => {
-        const isLast = index === toasts.length - 1;
-        const progressBar = toastInfo.element.querySelector('.toast-progress');
-
-        // 清除之前的定时器
-        if (toastInfo.timer) {
-            clearTimeout(toastInfo.timer);
-            toastInfo.timer = null;
-        }
-        if (toastInfo.progressTimer) {
-            clearInterval(toastInfo.progressTimer);
-            toastInfo.progressTimer = null;
-        }
-
-        if (isLast) {
-            // 最后一个不自动关闭,隐藏进度条
-            if (progressBar) progressBar.style.width = '0%';
-        } else {
-            // 非最后一个,启动自动关闭
-            const startTime = Date.now();
-
-            // 更新进度条
-            if (progressBar) {
-                progressBar.style.width = '100%';
-                toastInfo.progressTimer = setInterval(() => {
-                    const elapsed = Date.now() - startTime;
-                    const remaining = Math.max(0, 100 - (elapsed / duration) * 100);
-                    progressBar.style.width = `${remaining}%`;
-                }, 100);
-            }
-
-            // 设置自动关闭
-            toastInfo.timer = setTimeout(() => {
-                // 添加关闭动画
-                toastInfo.element.classList.add('closing');
-                setTimeout(() => {
-                    if (toastInfo.element.parentNode) {
-                        toastInfo.element.parentNode.removeChild(toastInfo.element);
-                    }
-                    const idx = toasts.indexOf(toastInfo);
-                    if (idx > -1) {
-                        toasts.splice(idx, 1);
-                    }
-                    updateToastsAutoClose();
-                }, 300);
-            }, duration);
-        }
-    });
-}
-
-// 显示错误提示的便捷函数
-function showError(message, title = '错误') {
-    return showToast(message, { type: 'error', title });
-}
-
-// 显示警告提示的便捷函数
-function showWarning(message, title = '警告') {
-    return showToast(message, { type: 'warning', title });
-}
-
-// 显示成功提示的便捷函数
-function showSuccess(message, title = '成功') {
-    return showToast(message, { type: 'success', title });
-}

+ 0 - 261
ApqInstaller/src/js/version.js

@@ -1,261 +0,0 @@
-// src/js/version.js - 版本加载模块
-
-// 版本加载状态
-let isLoadingVersions = false;
-
-// 设置下拉框为加载中状态
-function setDropdownLoading(selectElement, isSmall = false) {
-    selectElement.innerHTML = '';
-    const option = document.createElement('option');
-    option.value = '';
-    option.textContent = isSmall ? '...' : '加载中...';
-    option.disabled = true;
-    option.selected = true;
-    selectElement.appendChild(option);
-    selectElement.disabled = true;
-}
-
-// 设置下拉框为可用状态
-function setDropdownEnabled(selectElement) {
-    selectElement.disabled = false;
-}
-
-// 设置所有下拉框为加载中状态
-function setAllDropdownsLoading() {
-    const softwareList = ['nodejs', 'vscode', 'git'];
-    softwareList.forEach(software => {
-        const mainSelect = document.getElementById(`${software}-version`);
-        if (mainSelect) {
-            setDropdownLoading(mainSelect, false);
-        }
-        const allSelect = document.getElementById(`all-${software}-version`);
-        if (allSelect) {
-            setDropdownLoading(allSelect, true);
-        }
-    });
-}
-
-// 设置所有安装按钮的禁用状态
-function setInstallButtonsDisabled(disabled) {
-    const installBtns = document.querySelectorAll('.install-btn');
-    installBtns.forEach(btn => {
-        // 只在非安装过程中控制按钮状态
-        if (!btn.textContent.includes('安装中')) {
-            btn.disabled = disabled;
-        }
-    });
-}
-
-// 填充版本下拉框
-function populateVersionDropdown(selectElement, versions, isSmall = false) {
-    selectElement.innerHTML = '';
-    let firstSelectable = true;
-
-    versions.forEach((v) => {
-        const option = document.createElement('option');
-        option.value = v.value;
-
-        // 处理分隔符
-        if (v.disabled || v.separator) {
-            option.disabled = true;
-            option.textContent = v.label;
-            option.className = 'separator-option';
-        } else {
-            // 小型下拉框使用简短标签
-            if (isSmall) {
-                // 提取版本号部分
-                const versionMatch = v.label.match(/(\d+\.\d+\.\d+)/);
-                option.textContent = versionMatch ? versionMatch[1] : v.label.replace(/Node\.js |Git |\(.*?\)/g, '').trim();
-            } else {
-                option.textContent = v.label;
-            }
-            // 选中第一个可选项
-            if (firstSelectable) {
-                option.selected = true;
-                firstSelectable = false;
-            }
-        }
-
-        selectElement.appendChild(option);
-    });
-
-    // 启用下拉框
-    setDropdownEnabled(selectElement);
-}
-
-// 设置单个软件的加载状态(包括下拉框、安装按钮、状态文本)
-// isFailed: 是否加载失败
-function setSoftwareLoadingState(software, isLoading, isFailed = false) {
-    const pane = document.getElementById(software);
-    if (!pane) return;
-
-    const installBtn = pane.querySelector('.install-btn');
-    const statusText = pane.querySelector('.status-text');
-
-    if (isLoading) {
-        // 禁用安装按钮,显示加载中状态
-        if (installBtn && !installBtn.textContent.includes('安装中')) {
-            installBtn.disabled = true;
-        }
-        if (statusText && statusText.textContent === '就绪') {
-            statusText.textContent = '加载中...';
-        }
-    } else if (isFailed) {
-        // 加载失败:保持安装按钮禁用,显示加载失败状态
-        if (installBtn && !installBtn.textContent.includes('安装中')) {
-            installBtn.disabled = true;
-        }
-        if (statusText) {
-            statusText.textContent = '加载失败';
-        }
-    } else {
-        // 加载成功:恢复安装按钮,显示就绪状态
-        if (installBtn && !installBtn.textContent.includes('安装中')) {
-            installBtn.disabled = false;
-        }
-        if (statusText && statusText.textContent === '加载中...') {
-            statusText.textContent = '就绪';
-        }
-    }
-
-    // 一键安装页面也需要更新
-    updateAllPaneStatus();
-}
-
-// 更新一键安装页面的状态
-function updateAllPaneStatus() {
-    const allPane = document.getElementById('all');
-    if (!allPane) return;
-
-    const allInstallBtn = allPane.querySelector('.install-btn');
-    const allStatusText = allPane.querySelector('.status-text');
-
-    // 检查所有软件的下拉框状态
-    const softwareList = ['nodejs', 'vscode', 'git'];
-    let allLoaded = true;
-    let hasFailure = false;
-    let hasLoading = false;
-
-    softwareList.forEach(software => {
-        const select = document.getElementById(`all-${software}-version`);
-        if (select) {
-            const firstOption = select.options[0];
-            if (firstOption) {
-                const text = firstOption.textContent;
-                if (text === '...' || text === '加载中...') {
-                    hasLoading = true;
-                    allLoaded = false;
-                } else if (text === '失败' || text === '加载失败') {
-                    hasFailure = true;
-                    allLoaded = false;
-                }
-            }
-        }
-    });
-
-    if (hasLoading) {
-        // 还有正在加载的
-        if (allInstallBtn && !allInstallBtn.textContent.includes('安装中')) {
-            allInstallBtn.disabled = true;
-        }
-        if (allStatusText && allStatusText.textContent !== '加载中...') {
-            allStatusText.textContent = '加载中...';
-        }
-    } else if (hasFailure) {
-        // 有加载失败的
-        if (allInstallBtn && !allInstallBtn.textContent.includes('安装中')) {
-            allInstallBtn.disabled = true;
-        }
-        if (allStatusText) {
-            allStatusText.textContent = '部分加载失败';
-        }
-    } else if (allLoaded) {
-        // 全部加载成功
-        if (allInstallBtn && !allInstallBtn.textContent.includes('安装中')) {
-            allInstallBtn.disabled = false;
-        }
-        if (allStatusText && (allStatusText.textContent === '加载中...' || allStatusText.textContent === '部分加载失败')) {
-            allStatusText.textContent = '就绪';
-        }
-    }
-}
-
-// 加载单个软件的版本
-async function loadVersionForSoftware(software) {
-    const mainSelect = document.getElementById(`${software}-version`);
-    const allSelect = document.getElementById(`all-${software}-version`);
-    const softwareNames = { nodejs: 'Node.js', vscode: 'VS Code', git: 'Git' };
-
-    // 设置加载中状态
-    if (mainSelect) setDropdownLoading(mainSelect, false);
-    if (allSelect) setDropdownLoading(allSelect, true);
-    setSoftwareLoadingState(software, true);
-
-    try {
-        const result = await window.electronAPI.getVersions(software);
-        // 兼容新旧返回格式
-        const versions = result.versions || result;
-        const warning = result.warning;
-
-        // 如果有警告信息,显示警告提示
-        if (warning) {
-            showWarning(warning, `${softwareNames[software]} 版本获取`);
-        }
-
-        if (mainSelect) populateVersionDropdown(mainSelect, versions, false);
-        if (allSelect) populateVersionDropdown(allSelect, versions, true);
-        setSoftwareLoadingState(software, false);
-        return true; // 加载成功
-    } catch (error) {
-        console.error(`加载 ${software} 版本失败:`, error);
-        showError(`${softwareNames[software]} 版本列表加载失败,请检查网络连接或代理设置`, '版本加载失败');
-        if (mainSelect) {
-            mainSelect.innerHTML = '<option value="">加载失败</option>';
-            mainSelect.disabled = true;
-        }
-        if (allSelect) {
-            allSelect.innerHTML = '<option value="">失败</option>';
-            allSelect.disabled = true;
-        }
-        // 加载失败时,保持安装按钮禁用,更新状态文本
-        setSoftwareLoadingState(software, false, true); // 第三个参数表示失败
-        return false; // 加载失败
-    }
-}
-
-// 设置所有软件的状态文本
-function setAllStatusText(text) {
-    const softwareList = ['nodejs', 'vscode', 'git', 'all'];
-    softwareList.forEach(software => {
-        const pane = document.getElementById(software);
-        if (pane) {
-            const statusText = pane.querySelector('.status-text');
-            if (statusText && (statusText.textContent === '就绪' || statusText.textContent === '加载中...')) {
-                statusText.textContent = text;
-            }
-        }
-    });
-}
-
-// 加载所有软件版本
-async function loadAllVersions() {
-    if (isLoadingVersions) return;
-    isLoadingVersions = true;
-
-    const softwareList = ['nodejs', 'vscode', 'git'];
-
-    // 先设置所有下拉框为加载中状态,并禁用安装按钮,更新状态文本
-    setAllDropdownsLoading();
-    setInstallButtonsDisabled(true);
-    setAllStatusText('加载中...');
-
-    // 并行加载所有版本
-    const loadPromises = softwareList.map(software => loadVersionForSoftware(software));
-
-    // 等待所有加载完成
-    await Promise.all(loadPromises);
-
-    // 一键安装页面的状态由 updateAllPaneStatus 在每次加载完成时自动更新
-
-    isLoadingVersions = false;
-}