const MessageType = Object.freeze({ SUCCESS: 'success', ERROR: 'error', WARNING: 'warning', INFO: 'info' }); new Vue({ el: '#app', data: { config: {}, message: '', textContent: '启动', bgColor: '#3B82F6', serverRunning: false, showMessage: false, messageType: MessageType.SUCCESS, messageTimer: null, selectedProtocol: 'http' }, mounted() { this.fetchConfig(); }, methods: { msg(message, type = MessageType.SUCCESS) { this.message = message; this.messageType = type; // 如果已经有一个定时器在运行,先清除它 if (this.messageTimer) { clearTimeout(this.messageTimer); } // 显示消息 this.showMessage = true; // 设置淡出定时器 this.messageTimer = setTimeout(() => { this.showMessage = false; }, 2500); // 2.5秒后开始淡出 }, fetchConfig() { axios.get('/api/config') .then(response => { this.config = this.processConfig(response.data); }) .catch(error => { this.msg('获取配置失败: ' + error, MessageType.ERROR); }); }, processConfig(config) { const processed = {}; for (const [key, value] of Object.entries(config)) { if (typeof value === 'object' && value !== null) { processed[key] = JSON.stringify(value, null, 2); } else { processed[key] = value; } } return processed; }, updateConfig() { const updatedConfig = this.prepareConfigForUpdate(this.config); axios.post('/api/config', updatedConfig) .then(() => { this.msg('配置更新成功,服务器正在重启 '); this.restartApp(); }) .catch(error => { this.msg('获取配置失败: ' + error, MessageType.ERROR); }); }, prepareConfigForUpdate(config) { const prepared = {}; for (const [key, value] of Object.entries(config)) { if (typeof value === 'string' && value.trim().startsWith('{')) { try { prepared[key] = JSON.parse(value); } catch (e) { console.error(`解析 JSON 失败,键: ${key}:`, e); prepared[key] = value; // 保持原始字符串 } } else { prepared[key] = value; } } return prepared; }, restartApp() { axios.post('/api/restart') .then(() => { this.msg('应用正在重启'); }) .catch(error => { this.msg('获取配置失败: ' + error, MessageType.ERROR); }); }, toggleServer() { this.serverRunning = !this.serverRunning; let message = ''; let textContent = ''; let bgColor = ''; let url = ''; let errorMsg = ''; if (this.serverRunning) { message = '应用正在停止'; textContent = '停止'; bgColor = '#EF4444'; url = '/api/stop'; errorMsg = '停止应用失败: '; } else { message = '应用正在启动'; textContent = '启动'; bgColor = '#3B82F6'; url = '/api/start'; errorMsg = '启动应用失败: '; } axios.post(url) .then(() => { this.textContent = textContent; this.bgColor = bgColor; this.msg(message); }) .catch(error => { this.msg(errorMsg + error, MessageType.ERROR); }); }, toggleServerStyle() { return { backgroundColor: this.bgColor } }, copyVscodeConfig() { let config = { "github.copilot.advanced": { "debug.overrideCAPIUrl": `http://${this.config.bind}/v1`, "debug.overrideProxyUrl": `http://${this.config.bind}`, "debug.chatOverrideProxyUrl": `http://${this.config.bind}/v1/chat/completions`, "authProvider": "github-enterprise" }, "github-enterprise.uri": "https://cocopilot.org", }; let configStr = JSON.stringify(config, null, 2); configStr = configStr.slice(1, -1); navigator.clipboard.writeText(`${configStr.trimEnd()},\n`) .then(r => { this.msg('vscode 配置已复制到剪贴板'); }); }, testConnection() { const params = new URLSearchParams({ bind: this.config.bind, protocol: this.selectedProtocol }); axios.get(`/_ping?${params.toString()}`, { timeout: 5000 }) .then(response => { this.textContent = '停止'; this.bgColor = '#EF4444'; this.msg(response.data.msg); }) .catch(error => { this.textContent = '启动'; this.bgColor = '#3B82F6'; const errorMsg = error.response ? error.response.data.msg : error.message; this.msg('连接测试失败: ' + errorMsg, MessageType.ERROR); }); } } });