refactor: mock清理+安全配置+通用组件+菜单优化
P0安全: SECRET_KEY/ADMIN_PASSWORD/CORS环境变量化, seed仅admin P1Mock: mock.ts 301->88行, 删8数据mock+5generateMock, net-1300行 P2组件: useToast/useFetchList+ConfirmDialog/FormDialog P3菜单: menuSections/menuItems->constants/menu.ts P4API: NotificationsPage/WorkflowPage重写+RolesPage演示 测试: 1050passed, tsc clean
This commit is contained in:
1 parent
ec3a03cf38
commit
8b921c6c83
33 files changed
+1734
-2006
No files matched your search
@@ -0,0 +1,59 @@
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
title?: string;
|
||||
description?: string;
|
||||
confirmText?: string;
|
||||
cancelText?: string;
|
||||
variant?: 'danger' | 'default';
|
||||
}
|
||||
|
||||
export function ConfirmDialog({
|
||||
open,
|
||||
onConfirm,
|
||||
onCancel,
|
||||
title = '确认操作',
|
||||
description,
|
||||
confirmText = '确认',
|
||||
cancelText = '取消',
|
||||
variant = 'default',
|
||||
}: Props) {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(v) => { if (!v) onCancel(); }}>
|
||||
<DialogContent
|
||||
showCloseButton={false}
|
||||
className="border-0 sm:max-w-[400px]"
|
||||
onPointerDownOutside={(e) => e.preventDefault()}
|
||||
onInteractOutside={(e) => e.preventDefault()}
|
||||
>
|
||||
<DialogTitle className="text-base">{title}</DialogTitle>
|
||||
{description && (
|
||||
<DialogDescription className="text-sm text-[var(--dg-text-secondary)]">
|
||||
{description}
|
||||
</DialogDescription>
|
||||
)}
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button variant="ghost" size="sm" onClick={onCancel}>
|
||||
{cancelText}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant={variant === 'danger' ? 'destructive' : 'default'}
|
||||
onClick={onConfirm}
|
||||
>
|
||||
{confirmText}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { XIcon } from 'lucide-react';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
title: string;
|
||||
children: ReactNode;
|
||||
width?: string;
|
||||
footer?: ReactNode;
|
||||
}
|
||||
|
||||
export function FormDialog({
|
||||
open,
|
||||
onClose,
|
||||
title,
|
||||
children,
|
||||
width = 'max-w-lg',
|
||||
footer,
|
||||
}: Props) {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(v) => { if (!v) onClose(); }}>
|
||||
<DialogContent
|
||||
showCloseButton={false}
|
||||
className={`border-0 ${width} flex max-h-[85vh] flex-col`}
|
||||
onPointerDownOutside={(e) => e.preventDefault()}
|
||||
onInteractOutside={(e) => e.preventDefault()}
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<DialogTitle className="text-base font-semibold">{title}</DialogTitle>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="rounded-xs p-1 text-[var(--dg-text-muted)] transition-opacity hover:opacity-70"
|
||||
>
|
||||
<XIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Scrollable content */}
|
||||
<div className="flex-1 overflow-y-auto pr-1">{children}</div>
|
||||
|
||||
{/* Optional footer */}
|
||||
{footer && <div className="flex justify-end gap-2 pt-2">{footer}</div>}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
ClipboardList, Search, UserCog, Users, Lock, Shield, GitBranch, Bell,
|
||||
LogOut, Settings, Clock, Megaphone, Sun, Moon, BookOpen
|
||||
} from 'lucide-react';
|
||||
import { menuSections } from '@/lib/mock';
|
||||
import { menuSections } from '@/constants/menu';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useTheme } from '@/hooks/useTheme';
|
||||
|
||||
|
||||
Reference in new issue
Block a user