167 lines
4.0 KiB
TypeScript
167 lines
4.0 KiB
TypeScript
import React, { useState } from 'react';
|
||
import {
|
||
Dialog,
|
||
DialogTitle,
|
||
DialogContent,
|
||
DialogActions,
|
||
Button,
|
||
Typography,
|
||
Box,
|
||
IconButton,
|
||
} from '@mui/material';
|
||
import {
|
||
Close as CloseIcon,
|
||
Info as InfoIcon,
|
||
CheckCircle as SuccessIcon,
|
||
Warning as WarningIcon,
|
||
Error as ErrorIcon,
|
||
Help as ConfirmIcon,
|
||
} from '@mui/icons-material';
|
||
import { useTranslation } from 'react-i18next';
|
||
import { type IDialogInstance } from '../../interfaces/common';
|
||
|
||
interface DialogComponentProps {
|
||
dialog: IDialogInstance;
|
||
onClose: (result: boolean) => void;
|
||
}
|
||
|
||
const DialogComponent: React.FC<DialogComponentProps> = ({ dialog, onClose }) => {
|
||
const [loading, setLoading] = useState(false);
|
||
const { t } = useTranslation();
|
||
const { config } = dialog;
|
||
|
||
// 获取对话框图标
|
||
const getDialogIcon = () => {
|
||
const iconProps = { sx: { fontSize: 24, mr: 1 } };
|
||
|
||
switch (config.type) {
|
||
case 'info':
|
||
return <InfoIcon {...iconProps} color="info" />;
|
||
case 'success':
|
||
return <SuccessIcon {...iconProps} color="success" />;
|
||
case 'warning':
|
||
return <WarningIcon {...iconProps} color="warning" />;
|
||
case 'error':
|
||
return <ErrorIcon {...iconProps} color="error" />;
|
||
case 'confirm':
|
||
return <ConfirmIcon {...iconProps} color="warning" />;
|
||
default:
|
||
return null;
|
||
}
|
||
};
|
||
|
||
// 获取确认按钮颜色
|
||
const getConfirmButtonColor = () => {
|
||
switch (config.type) {
|
||
case 'error':
|
||
case 'warning':
|
||
return 'error';
|
||
case 'success':
|
||
return 'success';
|
||
case 'info':
|
||
return 'info';
|
||
default:
|
||
return 'primary';
|
||
}
|
||
};
|
||
|
||
// 处理确认操作
|
||
const handleConfirm = async () => {
|
||
try {
|
||
setLoading(true);
|
||
|
||
if (config.onConfirm) {
|
||
await config.onConfirm();
|
||
}
|
||
|
||
onClose(true);
|
||
} catch (error) {
|
||
console.error('Dialog confirm error:', error);
|
||
// 即使出错也关闭对话框,但返回false
|
||
onClose(false);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
// 处理取消操作
|
||
const handleCancel = () => {
|
||
if (config.onCancel) {
|
||
config.onCancel();
|
||
}
|
||
onClose(false);
|
||
};
|
||
|
||
// 处理遮罩点击
|
||
const handleBackdropClick = () => {
|
||
if (config.maskClosable !== false) {
|
||
handleCancel();
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Dialog
|
||
open={true}
|
||
onClose={handleBackdropClick}
|
||
maxWidth="sm"
|
||
fullWidth
|
||
slotProps={{
|
||
paper: {
|
||
sx: {
|
||
width: config.width || 'auto',
|
||
minWidth: config.width || '300px',
|
||
maxWidth: config.width || '500px',
|
||
}
|
||
}
|
||
}}
|
||
>
|
||
{/* 标题栏 */}
|
||
<DialogTitle sx={{ display: 'flex', alignItems: 'center', pr: 1 }}>
|
||
<Box sx={{ display: 'flex', alignItems: 'center', flex: 1 }}>
|
||
{getDialogIcon()}
|
||
<Typography variant="h6" component="span">
|
||
{config.title || t('dialog.confirm')}
|
||
</Typography>
|
||
</Box>
|
||
<IconButton
|
||
onClick={handleCancel}
|
||
size="small"
|
||
sx={{ ml: 1 }}
|
||
>
|
||
<CloseIcon />
|
||
</IconButton>
|
||
</DialogTitle>
|
||
|
||
{/* 内容区域 */}
|
||
<DialogContent>
|
||
<Typography variant="body1" sx={{ py: 1 }}>
|
||
{config.content}
|
||
</Typography>
|
||
</DialogContent>
|
||
|
||
{/* 操作按钮 */}
|
||
<DialogActions sx={{ px: 3, pb: 2 }}>
|
||
{config.showCancel !== false && (
|
||
<Button
|
||
onClick={handleCancel}
|
||
variant="outlined"
|
||
disabled={loading}
|
||
>
|
||
{config.cancelText || t('common.cancel')}
|
||
</Button>
|
||
)}
|
||
<Button
|
||
onClick={handleConfirm}
|
||
variant="contained"
|
||
color={getConfirmButtonColor() as any}
|
||
disabled={loading}
|
||
sx={{ ml: 1 }}
|
||
>
|
||
{loading ? t('dialog.processing') : (config.confirmText || t('common.confirm'))}
|
||
</Button>
|
||
</DialogActions>
|
||
</Dialog>
|
||
);
|
||
};
|
||
|
||
export default DialogComponent; |