fix: 全部页面 confirm() 替换为 ConfirmDialog 组件 — 9个页面统一回调模式

This commit is contained in:
logan committed 2026-05-27 21:25:14 +08:00
1 parent 41dab3deab
commit 7f6a4bb6df
9 files changed
+153 -62

No files matched your search

+12 -7
View File
@@ -1,6 +1,7 @@
import { useState, useEffect, useCallback } from 'react';
import request from '@/api/request';
import { Megaphone, Plus, Edit2, Trash2, Eye, Clock, CheckCircle, X, Save } from 'lucide-react';
import { ConfirmDialog } from '@/components/ConfirmDialog';
/* ── types ── */
interface Announcement {
@@ -56,6 +57,7 @@ export default function AnnouncementPage() {
/* view preview */
const [viewAnn, setViewAnn] = useState<Announcement | null>(null);
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
const fetchList = useCallback(async () => {
try {
@@ -118,13 +120,8 @@ export default function AnnouncementPage() {
};
const handleDelete = async (id: number) => {
if (!confirm('确定删除此公告?')) return;
try {
await request.delete(`/announcements/${id}`);
fetchList();
} catch {
/* ignore */
}
setDeleteConfirm({msg: '确定删除此公告?', onConfirm: async () => { try { await request.delete(`/announcements/${id}`); fetchList(); } catch {} }});
return;
};
/* ── render ── */
@@ -344,6 +341,14 @@ export default function AnnouncementPage() {
</div>
</div>
)}
<ConfirmDialog
open={!!deleteConfirm}
title={deleteConfirm?.msg || '确认操作'}
variant="danger"
confirmText="确定"
onConfirm={() => { deleteConfirm?.onConfirm(); }}
onCancel={() => setDeleteConfirm(null)}
/>
</div>
);
}
+22 -6
View File
@@ -4,6 +4,7 @@ import { ArrowLeft, Database, Table2, Users, Cpu, Play, RefreshCw } from 'lucide
import { instanceDetailApi } from '@/api/instanceDetail';
import { instanceApi } from '@/api/instance';
import { queryApi } from '@/api/query';
import { ConfirmDialog } from '@/components/ConfirmDialog';
interface InstanceInfo {
id: number; name: string; db_type: string; host: string; port: number;
@@ -27,6 +28,7 @@ export default function InstanceDetailPage() {
var [sqlText, setSqlText] = useState('');
var [queryResult, setQueryResult] = useState<any>(null);
var [loading, setLoading] = useState(false);
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
var tabs: { key: TabKey; label: string; icon: React.ElementType }[] = [
{ key: 'overview', label: '概览', icon: Database },
@@ -81,12 +83,17 @@ export default function InstanceDetailPage() {
};
var handleKill = function (pid: number) {
if (!confirm('确定 Kill 进程 ' + pid + '?')) return;
instanceDetailApi.killProcess(instanceId, pid).then(function () {
instanceDetailApi.getProcesslist(instanceId).then(function (res: any) {
setProcesses(res.processes || res || []);
});
}).catch(function () {});
setDeleteConfirm({
msg: '确定 Kill 进程 ' + pid + '?',
onConfirm: () => {
instanceDetailApi.killProcess(instanceId, pid).then(() => {
instanceDetailApi.getProcesslist(instanceId).then((res: any) => {
setProcesses(res.processes || res || []);
});
});
}
});
return;
};
if (!instance) return <div className="p-10 text-center text-[var(--dg-text-muted)]">加载中...</div>;
@@ -255,6 +262,15 @@ export default function InstanceDetailPage() {
{processes.length === 0 && <div className="text-center py-8 text-[var(--dg-text-muted)]">暂无进程</div>}
</div>
)}
<ConfirmDialog
open={!!deleteConfirm}
title={deleteConfirm?.msg || '确认操作'}
variant="danger"
confirmText="确定"
onConfirm={() => { deleteConfirm?.onConfirm(); }}
onCancel={() => setDeleteConfirm(null)}
/>
</div>
);
}
+16 -4
View File
@@ -8,6 +8,7 @@ import { instanceGroupApi, type InstanceGroup } from '@/api/instanceGroup';
import { instanceApi } from '@/api/instance';
import { userApi } from '@/api/user';
import { useActionPermission } from '@/hooks/useAuth';
import { ConfirmDialog } from '@/components/ConfirmDialog';
/* ───────── Constants ───────── */
@@ -109,6 +110,7 @@ export default function InstanceGroupPage() {
const [showCreateModal, setShowCreateModal] = useState(false);
const [showEditModal, setShowEditModal] = useState(false);
const [showUserModal, setShowUserModal] = useState(false);
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
const canManage = useActionPermission('instance-group.manage');
// Form state — shared by create & edit
@@ -215,10 +217,11 @@ export default function InstanceGroupPage() {
/* ── Delete ── */
const handleDelete = async (id: number) => {
if (!confirm('确定删除该权限组?')) return;
await instanceGroupApi.delete(id);
if (selectedId === id) setSelectedId(null);
fetchGroups();
setDeleteConfirm({msg: '确定删除该权限组?', onConfirm: async () => {
await instanceGroupApi.delete(id);
if (selectedId === id) setSelectedId(null);
fetchGroups();
}});
};
/* ── Assign Users ── */
@@ -439,6 +442,15 @@ export default function InstanceGroupPage() {
<FormModal mode="create" />
<FormModal mode="edit" />
<ConfirmDialog
open={!!deleteConfirm}
title={deleteConfirm?.msg || '确认操作'}
variant="danger"
confirmText="确定"
onConfirm={() => { deleteConfirm?.onConfirm(); }}
onCancel={() => setDeleteConfirm(null)}
/>
{/* User Modal */}
{showUserModal && (
<div className="fixed inset-0 z-[100] flex items-start justify-center pt-[10vh] bg-black/60 backdrop-blur-sm">
+28 -19
View File
@@ -12,6 +12,7 @@ import PageHeader from '@/components/PageHeader';
import EmptyState from '@/components/EmptyState';
import { instanceApi } from '@/api/instance';
import EditInstanceDialog from '@/components/EditInstanceDialog';
import { ConfirmDialog } from '@/components/ConfirmDialog';
/* ------------------------------------------------------------------ */
/* Types */
@@ -189,29 +190,28 @@ export default function InstancePage() {
}, [filtered]);
const handleDelete = useCallback(async (id: number) => {
if (!confirm('确定删除该实例?')) return;
try {
await instanceApi.delete(id);
fetchInstances();
} catch {
/* ignore */
}
setDeleteConfirm({
msg: '确定删除该实例?',
onConfirm: async () => {
try { await instanceApi.delete(id); fetchInstances(); } catch {}
},
});
}, [fetchInstances]);
const handleBatchDelete = useCallback(async () => {
if (selectedIds.size === 0) return;
if (!confirm(`确定删除选中的 ${selectedIds.size} 个实例?此操作不可恢复。`)) return;
setBatchDeleting(true);
try {
const ids = Array.from(selectedIds);
await Promise.all(ids.map(id => instanceApi.delete(id)));
setSelectedIds(new Set());
fetchInstances();
} catch {
/* ignore */
} finally {
setBatchDeleting(false);
}
setDeleteConfirm({
msg: `确定删除选中的 ${selectedIds.size} 个实例?此操作不可恢复。`,
onConfirm: async () => {
setBatchDeleting(true);
try {
const ids = Array.from(selectedIds);
await Promise.all(ids.map(i => instanceApi.delete(i)));
setSelectedIds(new Set());
fetchInstances();
} finally { setBatchDeleting(false); }
},
});
}, [selectedIds, fetchInstances]);
const toggleSelect = useCallback((id: number) => {
@@ -994,6 +994,7 @@ function CreateInstanceForm({ defaultType, onCancel, onCreated }: {
const [error, setError] = useState('');
const [testing, setTesting] = useState(false);
const [testResult, setTestResult] = useState<{ success: boolean; message: string; version?: string } | null>(null);
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
const isRedis = dbType === 'redis';
const needUsername = !isRedis;
@@ -1447,6 +1448,14 @@ function CreateInstanceForm({ defaultType, onCancel, onCreated }: {
</div>
</div>
</div>
<ConfirmDialog
open={!!deleteConfirm}
title={deleteConfirm?.msg || '确认操作'}
variant="danger"
confirmText="确定"
onConfirm={() => { deleteConfirm?.onConfirm(); }}
onCancel={() => setDeleteConfirm(null)}
/>
</div>
);
}
+12 -7
View File
@@ -1,6 +1,7 @@
import { useState, useEffect, useCallback } from 'react';
import request from '@/api/request';
import { Plus, Trash2, Send, Bell, Mail, Settings, X } from 'lucide-react';
import { ConfirmDialog } from '@/components/ConfirmDialog';
/* ── types ── */
type ChannelType = 'dingtalk' | 'webhook_feishu' | 'email';
@@ -62,6 +63,7 @@ export default function NotificationPage() {
/* test */
const [testingId, setTestingId] = useState<number | null>(null);
const [testResult, setTestResult] = useState<Record<number, { success: boolean; message: string } | null>>({});
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
const fetchList = useCallback(async () => {
try {
@@ -128,13 +130,8 @@ export default function NotificationPage() {
};
const handleDelete = async (id: number) => {
if (!confirm('确定删除此通知渠道?')) return;
try {
await request.delete(`/notifications/${id}`);
fetchList();
} catch {
/* ignore */
}
setDeleteConfirm({msg: '确定删除此通知渠道?', onConfirm: async () => { try { await request.delete(`/notifications/${id}`); fetchList(); } catch {} }});
return;
};
const handleTest = async (id: number) => {
@@ -451,6 +448,14 @@ export default function NotificationPage() {
</div>
</div>
)}
<ConfirmDialog
open={!!deleteConfirm}
title={deleteConfirm?.msg || '确认操作'}
variant="danger"
confirmText="确定"
onConfirm={() => { deleteConfirm?.onConfirm(); }}
onCancel={() => setDeleteConfirm(null)}
/>
</div>
);
}
+12 -5
View File
@@ -2,6 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
import { Bell, Webhook, Check, Settings, TestTube, ToggleLeft, ToggleRight, Loader2, AlertCircle, Plus, Trash2 } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { notificationApi } from '@/api/notification';
import { ConfirmDialog } from '@/components/ConfirmDialog';
interface NotificationChannel {
id: number;
@@ -25,6 +26,7 @@ export default function NotificationsPage() {
const [error, setError] = useState<string | null>(null);
const [testingId, setTestingId] = useState<number | null>(null);
const [testResult, setTestResult] = useState<{ id: number; success: boolean; message: string } | null>(null);
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
const fetchChannels = useCallback(async () => {
try {
@@ -67,11 +69,8 @@ export default function NotificationsPage() {
}, []);
const handleDelete = useCallback(async (id: number) => {
if (!confirm('确认删除该通知渠道?')) return;
try {
await notificationApi.delete(id);
setChannels(prev => prev.filter(c => c.id !== id));
} catch {}
setDeleteConfirm({msg: '确认删除该通知渠道?', onConfirm: async () => { try { await notificationApi.delete(id); setChannels(prev => prev.filter(c => c.id !== id)); } catch {} }});
return;
}, []);
if (loading) {
@@ -175,6 +174,14 @@ export default function NotificationsPage() {
</div>
</>
)}
<ConfirmDialog
open={!!deleteConfirm}
title={deleteConfirm?.msg || '确认操作'}
variant="danger"
confirmText="确定"
onConfirm={() => { deleteConfirm?.onConfirm(); }}
onCancel={() => setDeleteConfirm(null)}
/>
</div>
);
}
+14 -2
View File
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { ArrowLeft, Key, Activity, Terminal, Gauge, Plus, RefreshCw, Search } from 'lucide-react';
import { redisApi } from '@/api/redis';
import { ConfirmDialog } from '@/components/ConfirmDialog';
type TabKey = 'keys' | 'monitor' | 'cli' | 'perf';
@@ -24,6 +25,7 @@ export default function RedisDetailPage() {
var [slowlog, setSlowlog] = useState<any[]>([]);
var [clients, setClients] = useState<any[]>([]);
var [loading, setLoading] = useState(false);
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
var tabs: { key: TabKey; label: string; icon: React.ElementType }[] = [
{ key: 'keys', label: '键管理', icon: Key },
@@ -54,8 +56,10 @@ export default function RedisDetailPage() {
};
var handleDeleteKey = function (keyName: string) {
if (!confirm('确定删除键 ' + keyName + '?')) return;
redisApi.deleteKey(instanceId, keyName, selectedDb).then(function () { fetchKeys(); }).catch(function () {});
setDeleteConfirm({msg: '确定删除该键?', onConfirm: async () => {
redisApi.deleteKey(instanceId, keyName, selectedDb).then(function () { fetchKeys(); }).catch(function () {});
}});
return;
};
var handleCommand = function () {
@@ -304,6 +308,14 @@ export default function RedisDetailPage() {
</div>
</div>
)}
<ConfirmDialog
open={!!deleteConfirm}
title={deleteConfirm?.msg || '确认操作'}
variant="danger"
confirmText="确定"
onConfirm={() => { deleteConfirm?.onConfirm(); }}
onCancel={() => setDeleteConfirm(null)}
/>
</div>
);
}
+20 -7
View File
@@ -10,6 +10,7 @@ import { userApi, ldapApi } from '@/api/user';
import { instanceGroupApi, type InstanceGroup } from '@/api/instanceGroup';
import { nameToUsername } from '@/utils/pinyin';
import { toast } from '@/hooks/useToast';
import { ConfirmDialog } from '@/components/ConfirmDialog';
/* ───────── Types ───────── */
@@ -134,6 +135,7 @@ export default function UsersPage() {
const [selectedIds, setSelectedIds] = useState<Set<number>>(new Set());
const [showBatchMenu, setShowBatchMenu] = useState(false);
const [showImport, setShowImport] = useState(false);
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
const fetchUsers = useCallback(async () => {
setLoading(true);
@@ -188,13 +190,15 @@ export default function UsersPage() {
};
const handleDelete = async (id: number) => {
if (!confirm('确定删除该用户?此操作不可恢复。')) return;
try {
await userApi.delete(id);
setSelectedIds(prev => { const n = new Set(prev); n.delete(id); return n; });
toast('success', '用户已删除');
fetchUsers();
} catch { toast('error', '删除失败'); }
setDeleteConfirm({msg: '确定删除该用户?此操作不可恢复。', onConfirm: async () => {
try {
await userApi.delete(id);
setSelectedIds(prev => { const n = new Set(prev); n.delete(id); return n; });
toast('success', '用户已删除');
fetchUsers();
} catch { toast('error', '删除失败'); }
}});
return;
};
const handleBatchAction = async (action: string) => {
@@ -521,6 +525,14 @@ export default function UsersPage() {
{showImport && (
<BatchImportModal onClose={() => setShowImport(false)} onImported={() => { setShowImport(false); fetchUsers(); }} />
)}
<ConfirmDialog
open={!!deleteConfirm}
title={deleteConfirm?.msg || '确认操作'}
variant="danger"
confirmText="确定"
onConfirm={() => { deleteConfirm?.onConfirm(); }}
onCancel={() => setDeleteConfirm(null)}
/>
</div>
);
}
@@ -888,6 +900,7 @@ function BatchImportModal({ onClose, onImported }: { onClose: () => void; onImpo
const [newOuName, setNewOuName] = useState('');
const [newOuDesc, setNewOuDesc] = useState('');
const [creatingOu, setCreatingOu] = useState(false);
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
// Check LDAP readiness
useEffect(() => {
+17 -5
View File
@@ -7,6 +7,7 @@ import {
import { Card, CardContent } from '@/components/ui/card';
import { workflowApi } from '@/api/workflow';
import { userApi } from '@/api/user';
import { ConfirmDialog } from '@/components/ConfirmDialog';
/* ------------------------------------------------------------------ */
/* Types */
@@ -470,6 +471,7 @@ export default function WorkflowPage() {
const [expandedId, setExpandedId] = useState<number | null>(null);
const [previewWorkflow, setPreviewWorkflow] = useState<WorkflowDetail | null>(null);
const [editorWorkflow, setEditorWorkflow] = useState<WorkflowDetail | null | undefined>(undefined);
const [deleteConfirm, setDeleteConfirm] = useState<{msg: string; onConfirm: () => void} | null>(null);
const fetchWorkflows = useCallback(async () => {
try {
@@ -506,11 +508,13 @@ export default function WorkflowPage() {
}, []);
const handleDelete = useCallback(async (id: number) => {
if (!confirm('确认删除该审批流程?')) return;
try {
await workflowApi.delete(id);
setItems((prev) => prev.filter((w) => w.id !== id));
} catch {}
setDeleteConfirm({msg: '确认删除该审批流程?', onConfirm: async () => {
try {
await workflowApi.delete(id);
setItems((prev) => prev.filter((w) => w.id !== id));
} catch {}
}});
return;
}, []);
const setDefault = useCallback(async (id: number) => {
@@ -807,6 +811,14 @@ export default function WorkflowPage() {
onSaved={() => { setEditorWorkflow(undefined); fetchWorkflows(); }}
/>
)}
<ConfirmDialog
open={!!deleteConfirm}
title={deleteConfirm?.msg || '确认操作'}
variant="danger"
confirmText="确定"
onConfirm={() => { deleteConfirm?.onConfirm(); }}
onCancel={() => setDeleteConfirm(null)}
/>
</div>
);
}