代码优化:清理冗余功能并修复关键问题

- 删除未使用的 axios 依赖
- 移除 Provider 接口中未使用的 model 字段
- 删除未使用的供应商连通性检查功能
- 修复 preload.ts 中缺失的 IPC 方法暴露
- 简化 UI:移除重复的单选按钮,仅保留启用按钮
- 修复 TypeScript 接口定义不完整的问题
This commit is contained in:
farion1231
2025-08-06 20:48:03 +08:00
parent dbafab57cf
commit 588883ffc4
6 changed files with 116 additions and 126 deletions

View File

@@ -30,7 +30,6 @@
"vite": "^5.0.0" "vite": "^5.0.0"
}, },
"dependencies": { "dependencies": {
"axios": "^1.6.0",
"electron-store": "^8.1.0", "electron-store": "^8.1.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0" "react-dom": "^18.2.0"

View File

@@ -128,25 +128,6 @@ ipcMain.handle('selectConfigFile', async () => {
return result.filePaths[0] return result.filePaths[0]
}) })
ipcMain.handle('checkStatus', async (_, provider: Provider) => {
// 简单的连通性检查 - 向API地址发送HEAD请求
try {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 5000)
const response = await fetch(provider.apiUrl, {
method: 'HEAD',
signal: controller.signal
})
clearTimeout(timeoutId)
return response.ok
} catch (error) {
console.error('检查供应商状态失败:', error)
return false
}
})
ipcMain.handle('openExternal', async (_, url: string) => { ipcMain.handle('openExternal', async (_, url: string) => {
try { try {
await shell.openExternal(url) await shell.openExternal(url)

View File

@@ -7,7 +7,6 @@ contextBridge.exposeInMainWorld('electronAPI', {
addProvider: (provider: Provider) => ipcRenderer.invoke('addProvider', provider), addProvider: (provider: Provider) => ipcRenderer.invoke('addProvider', provider),
deleteProvider: (id: string) => ipcRenderer.invoke('deleteProvider', id), deleteProvider: (id: string) => ipcRenderer.invoke('deleteProvider', id),
updateProvider: (provider: Provider) => ipcRenderer.invoke('updateProvider', provider), updateProvider: (provider: Provider) => ipcRenderer.invoke('updateProvider', provider),
checkStatus: (provider: Provider) => ipcRenderer.invoke('checkStatus', provider),
switchProvider: (providerId: string) => ipcRenderer.invoke('switchProvider', providerId), switchProvider: (providerId: string) => ipcRenderer.invoke('switchProvider', providerId),
getClaudeCodeConfigPath: () => ipcRenderer.invoke('getClaudeCodeConfigPath'), getClaudeCodeConfigPath: () => ipcRenderer.invoke('getClaudeCodeConfigPath'),
selectConfigFile: () => ipcRenderer.invoke('selectConfigFile'), selectConfigFile: () => ipcRenderer.invoke('selectConfigFile'),

View File

@@ -1,144 +1,157 @@
import { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef } from "react";
import { Provider } from '../shared/types' import { Provider } from "../shared/types";
import ProviderList from './components/ProviderList' import ProviderList from "./components/ProviderList";
import AddProviderModal from './components/AddProviderModal' import AddProviderModal from "./components/AddProviderModal";
import EditProviderModal from './components/EditProviderModal' import EditProviderModal from "./components/EditProviderModal";
import { ConfirmDialog } from './components/ConfirmDialog' import { ConfirmDialog } from "./components/ConfirmDialog";
import './App.css' import "./App.css";
function App() { function App() {
const [providers, setProviders] = useState<Record<string, Provider>>({}) const [providers, setProviders] = useState<Record<string, Provider>>({});
const [currentProviderId, setCurrentProviderId] = useState<string>('') const [currentProviderId, setCurrentProviderId] = useState<string>("");
const [isAddModalOpen, setIsAddModalOpen] = useState(false) const [isAddModalOpen, setIsAddModalOpen] = useState(false);
const [configPath, setConfigPath] = useState<string>('') const [configPath, setConfigPath] = useState<string>("");
const [editingProviderId, setEditingProviderId] = useState<string | null>(null) const [editingProviderId, setEditingProviderId] = useState<string | null>(
const [notification, setNotification] = useState<{ message: string; type: 'success' | 'error' } | null>(null) null
const [isNotificationVisible, setIsNotificationVisible] = useState(false) );
const [confirmDialog, setConfirmDialog] = useState<{ isOpen: boolean; title: string; message: string; onConfirm: () => void } | null>(null) const [notification, setNotification] = useState<{
const timeoutRef = useRef<NodeJS.Timeout | null>(null) message: string;
type: "success" | "error";
} | null>(null);
const [isNotificationVisible, setIsNotificationVisible] = useState(false);
const [confirmDialog, setConfirmDialog] = useState<{
isOpen: boolean;
title: string;
message: string;
onConfirm: () => void;
} | null>(null);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
// 设置通知的辅助函数 // 设置通知的辅助函数
const showNotification = (message: string, type: 'success' | 'error', duration = 3000) => { const showNotification = (
message: string,
type: "success" | "error",
duration = 3000
) => {
// 清除之前的定时器 // 清除之前的定时器
if (timeoutRef.current) { if (timeoutRef.current) {
clearTimeout(timeoutRef.current) clearTimeout(timeoutRef.current);
} }
// 立即显示通知 // 立即显示通知
setNotification({ message, type }) setNotification({ message, type });
setIsNotificationVisible(true) setIsNotificationVisible(true);
// 设置淡出定时器 // 设置淡出定时器
timeoutRef.current = setTimeout(() => { timeoutRef.current = setTimeout(() => {
setIsNotificationVisible(false) setIsNotificationVisible(false);
// 等待淡出动画完成后清除通知 // 等待淡出动画完成后清除通知
setTimeout(() => { setTimeout(() => {
setNotification(null) setNotification(null);
timeoutRef.current = null timeoutRef.current = null;
}, 300) // 与CSS动画时间匹配 }, 300); // 与CSS动画时间匹配
}, duration) }, duration);
} };
// 加载供应商列表 // 加载供应商列表
useEffect(() => { useEffect(() => {
loadProviders() loadProviders();
loadConfigPath() loadConfigPath();
}, []) }, []);
// 清理定时器 // 清理定时器
useEffect(() => { useEffect(() => {
return () => { return () => {
if (timeoutRef.current) { if (timeoutRef.current) {
clearTimeout(timeoutRef.current) clearTimeout(timeoutRef.current);
} }
} };
}, []) }, []);
const loadProviders = async () => { const loadProviders = async () => {
const loadedProviders = await window.electronAPI.getProviders() const loadedProviders = await window.electronAPI.getProviders();
const currentId = await window.electronAPI.getCurrentProvider() const currentId = await window.electronAPI.getCurrentProvider();
setProviders(loadedProviders) setProviders(loadedProviders);
setCurrentProviderId(currentId) setCurrentProviderId(currentId);
} };
const loadConfigPath = async () => { const loadConfigPath = async () => {
const path = await window.electronAPI.getClaudeCodeConfigPath() const path = await window.electronAPI.getClaudeCodeConfigPath();
setConfigPath(path) setConfigPath(path);
} };
// 生成唯一ID // 生成唯一ID
const generateId = () => { const generateId = () => {
return Date.now().toString(36) + Math.random().toString(36).substr(2, 9) return Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
} };
const handleAddProvider = async (provider: Omit<Provider, 'id'>) => { const handleAddProvider = async (provider: Omit<Provider, "id">) => {
const newProvider: Provider = { const newProvider: Provider = {
...provider, ...provider,
id: generateId() id: generateId(),
} };
await window.electronAPI.addProvider(newProvider) await window.electronAPI.addProvider(newProvider);
await loadProviders() await loadProviders();
setIsAddModalOpen(false) setIsAddModalOpen(false);
} };
const handleDeleteProvider = async (id: string) => { const handleDeleteProvider = async (id: string) => {
const provider = providers[id] const provider = providers[id];
setConfirmDialog({ setConfirmDialog({
isOpen: true, isOpen: true,
title: '删除供应商', title: "删除供应商",
message: `确定要删除供应商 "${provider?.name}" 吗?此操作无法撤销。`, message: `确定要删除供应商 "${provider?.name}" 吗?此操作无法撤销。`,
onConfirm: async () => { onConfirm: async () => {
await window.electronAPI.deleteProvider(id) await window.electronAPI.deleteProvider(id);
await loadProviders() await loadProviders();
setConfirmDialog(null) setConfirmDialog(null);
showNotification('供应商删除成功', 'success') showNotification("供应商删除成功", "success");
} },
}) });
} };
const handleSwitchProvider = async (id: string) => { const handleSwitchProvider = async (id: string) => {
const success = await window.electronAPI.switchProvider(id) const success = await window.electronAPI.switchProvider(id);
if (success) { if (success) {
setCurrentProviderId(id) setCurrentProviderId(id);
// 显示重启提示,时间更长 // 显示重启提示
showNotification('切换成功!请重启 Claude Code 终端以生效', 'success', 4000) showNotification(
"切换成功!请重启 Claude Code 终端以生效",
"success",
2000
);
} else { } else {
showNotification('切换失败,请检查配置', 'error') showNotification("切换失败,请检查配置", "error");
}
} }
};
const handleEditProvider = async (provider: Provider) => { const handleEditProvider = async (provider: Provider) => {
try { try {
await window.electronAPI.updateProvider(provider) await window.electronAPI.updateProvider(provider);
await loadProviders() await loadProviders();
setEditingProviderId(null) setEditingProviderId(null);
// 显示编辑成功提示,时间较短 // 显示编辑成功提示
showNotification('供应商配置已保存', 'success', 2000) showNotification("供应商配置已保存", "success", 2000);
} catch (error) { } catch (error) {
console.error('更新供应商失败:', error) console.error("更新供应商失败:", error);
setEditingProviderId(null) setEditingProviderId(null);
showNotification('保存失败,请重试', 'error') showNotification("保存失败,请重试", "error");
}
} }
};
const handleSelectConfigFile = async () => { const handleSelectConfigFile = async () => {
const selectedPath = await window.electronAPI.selectConfigFile() const selectedPath = await window.electronAPI.selectConfigFile();
if (selectedPath) { if (selectedPath) {
setConfigPath(selectedPath) setConfigPath(selectedPath);
}
} }
};
return ( return (
<div className="app"> <div className="app">
<header className="app-header"> <header className="app-header">
<h1>Claude Code </h1> <h1>Claude Code </h1>
<div className="header-actions"> <div className="header-actions">
<button <button className="add-btn" onClick={() => setIsAddModalOpen(true)}>
className="add-btn"
onClick={() => setIsAddModalOpen(true)}
>
</button> </button>
</div> </div>
@@ -148,7 +161,13 @@ function App() {
<div className="provider-section"> <div className="provider-section">
{/* 浮动通知组件 */} {/* 浮动通知组件 */}
{notification && ( {notification && (
<div className={`notification-floating ${notification.type === 'error' ? 'notification-error' : 'notification-success'} ${isNotificationVisible ? 'fade-in' : 'fade-out'}`}> <div
className={`notification-floating ${
notification.type === "error"
? "notification-error"
: "notification-success"
} ${isNotificationVisible ? "fade-in" : "fade-out"}`}
>
{notification.message} {notification.message}
</div> </div>
)} )}
@@ -201,7 +220,7 @@ function App() {
/> />
)} )}
</div> </div>
) );
} }
export default App export default App;

View File

@@ -44,12 +44,6 @@ const ProviderList: React.FC<ProviderListProps> = ({
> >
<div className="provider-info"> <div className="provider-info">
<div className="provider-name"> <div className="provider-name">
<input
type="radio"
name="provider"
checked={isCurrent}
onChange={() => onSwitch(provider.id)}
/>
<span>{provider.name}</span> <span>{provider.name}</span>
{isCurrent && <span className="current-badge">使</span>} {isCurrent && <span className="current-badge">使</span>}
</div> </div>

View File

@@ -3,7 +3,6 @@ export interface Provider {
name: string name: string
apiUrl: string apiUrl: string
apiKey: string apiKey: string
model?: string
websiteUrl?: string websiteUrl?: string
} }
@@ -23,7 +22,6 @@ declare global {
switchProvider: (providerId: string) => Promise<boolean> switchProvider: (providerId: string) => Promise<boolean>
getClaudeCodeConfigPath: () => Promise<string> getClaudeCodeConfigPath: () => Promise<string>
selectConfigFile: () => Promise<string | null> selectConfigFile: () => Promise<string | null>
checkStatus: (provider: Provider) => Promise<boolean>
openExternal: (url: string) => Promise<boolean> openExternal: (url: string) => Promise<boolean>
} }
} }