diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 1f7544d..c67f3f3 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -3,6 +3,7 @@ import { Provider } from '../shared/types' import ProviderList from './components/ProviderList' import AddProviderModal from './components/AddProviderModal' import EditProviderModal from './components/EditProviderModal' +import { ConfirmDialog } from './components/ConfirmDialog' import './App.css' function App() { @@ -13,6 +14,7 @@ function App() { const [editingProviderId, setEditingProviderId] = useState(null) const [notification, setNotification] = useState<{ 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(null) // 设置通知的辅助函数 @@ -82,10 +84,18 @@ function App() { } const handleDeleteProvider = async (id: string) => { - if (confirm('确定要删除这个供应商吗?')) { - await window.electronAPI.deleteProvider(id) - await loadProviders() - } + const provider = providers[id] + setConfirmDialog({ + isOpen: true, + title: '删除供应商', + message: `确定要删除供应商 "${provider?.name}" 吗?此操作无法撤销。`, + onConfirm: async () => { + await window.electronAPI.deleteProvider(id) + await loadProviders() + setConfirmDialog(null) + showNotification('供应商删除成功', 'success') + } + }) } const handleSwitchProvider = async (id: string) => { @@ -180,6 +190,16 @@ function App() { onClose={() => setEditingProviderId(null)} /> )} + + {confirmDialog && ( + setConfirmDialog(null)} + /> + )} ) } diff --git a/src/renderer/components/AddProviderModal.css b/src/renderer/components/AddProviderModal.css index 4c10017..0ecea99 100644 --- a/src/renderer/components/AddProviderModal.css +++ b/src/renderer/components/AddProviderModal.css @@ -29,6 +29,16 @@ color: #2c3e50; } +.error-message { + background: #fee; + color: #c33; + padding: 0.75rem; + border-radius: 4px; + margin-bottom: 1rem; + border: 1px solid #fcc; + font-size: 0.9rem; +} + .presets { margin-bottom: 1.5rem; padding-bottom: 1.5rem; diff --git a/src/renderer/components/AddProviderModal.tsx b/src/renderer/components/AddProviderModal.tsx index f466bcc..4eff714 100644 --- a/src/renderer/components/AddProviderModal.tsx +++ b/src/renderer/components/AddProviderModal.tsx @@ -16,12 +16,14 @@ const AddProviderModal: React.FC = ({ onAdd, onClose }) = websiteUrl: '' }) const [showPassword, setShowPassword] = useState(false) + const [error, setError] = useState('') const handleSubmit = (e: React.FormEvent) => { e.preventDefault() + setError('') if (!formData.name || !formData.apiUrl || !formData.apiKey) { - alert('请填写所有必填字段') + setError('请填写所有必填字段') return } @@ -89,6 +91,12 @@ const AddProviderModal: React.FC = ({ onAdd, onClose }) =
e.stopPropagation()}>

添加新供应商

+ {error && ( +
+ {error} +
+ )} +
diff --git a/src/renderer/components/ConfirmDialog.css b/src/renderer/components/ConfirmDialog.css new file mode 100644 index 0000000..814dc27 --- /dev/null +++ b/src/renderer/components/ConfirmDialog.css @@ -0,0 +1,105 @@ +.confirm-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + backdrop-filter: blur(2px); +} + +.confirm-dialog { + background: white; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); + min-width: 300px; + max-width: 400px; + animation: confirmSlideIn 0.2s ease-out; +} + +@keyframes confirmSlideIn { + from { + opacity: 0; + transform: scale(0.9) translateY(-20px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } +} + +.confirm-header { + padding: 1.5rem 1.5rem 1rem; + border-bottom: 1px solid #eee; +} + +.confirm-header h3 { + margin: 0; + font-size: 1.1rem; + color: #333; + font-weight: 600; +} + +.confirm-content { + padding: 1rem 1.5rem; +} + +.confirm-content p { + margin: 0; + color: #666; + line-height: 1.5; +} + +.confirm-actions { + display: flex; + gap: 0.75rem; + padding: 1rem 1.5rem 1.5rem; + justify-content: flex-end; +} + +.confirm-btn { + padding: 0.5rem 1rem; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 0.9rem; + font-weight: 500; + transition: background-color 0.2s, transform 0.1s; + min-width: 70px; +} + +.confirm-btn:hover { + transform: translateY(-1px); +} + +.confirm-btn:active { + transform: translateY(0); +} + +.cancel-btn { + background: #f8f9fa; + color: #6c757d; + border: 1px solid #dee2e6; +} + +.cancel-btn:hover { + background: #e9ecef; +} + +.confirm-btn-primary { + background: #dc3545; + color: white; +} + +.confirm-btn-primary:hover { + background: #c82333; +} + +.confirm-btn:focus { + outline: 2px solid #007bff; + outline-offset: 2px; +} \ No newline at end of file diff --git a/src/renderer/components/ConfirmDialog.tsx b/src/renderer/components/ConfirmDialog.tsx new file mode 100644 index 0000000..765c0b8 --- /dev/null +++ b/src/renderer/components/ConfirmDialog.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import './ConfirmDialog.css'; + +interface ConfirmDialogProps { + isOpen: boolean; + title: string; + message: string; + confirmText?: string; + cancelText?: string; + onConfirm: () => void; + onCancel: () => void; +} + +export const ConfirmDialog: React.FC = ({ + isOpen, + title, + message, + confirmText = '确定', + cancelText = '取消', + onConfirm, + onCancel +}) => { + if (!isOpen) return null; + + return ( +
+
+
+

{title}

+
+
+

{message}

+
+
+ + +
+
+
+ ); +}; \ No newline at end of file diff --git a/src/renderer/components/EditProviderModal.tsx b/src/renderer/components/EditProviderModal.tsx index bd56aae..5a52024 100644 --- a/src/renderer/components/EditProviderModal.tsx +++ b/src/renderer/components/EditProviderModal.tsx @@ -17,6 +17,7 @@ const EditProviderModal: React.FC = ({ provider, onSave, websiteUrl: provider.websiteUrl || '' }) const [showPassword, setShowPassword] = useState(false) + const [error, setError] = useState('') useEffect(() => { setFormData({ @@ -29,9 +30,10 @@ const EditProviderModal: React.FC = ({ provider, onSave, const handleSubmit = (e: React.FormEvent) => { e.preventDefault() + setError('') if (!formData.name || !formData.apiUrl || !formData.apiKey) { - alert('请填写所有必填字段') + setError('请填写所有必填字段') return } @@ -79,6 +81,12 @@ const EditProviderModal: React.FC = ({ provider, onSave,
e.stopPropagation()}>

编辑供应商

+ {error && ( +
+ {error} +
+ )} +