feat(ui): 添加删除操作延迟确认功能
增强用户体验,防止误删除操作: 1. MessageModal 组件增强 - 添加 confirmDelay 属性(秒) - 确认按钮倒计时功能 - 倒计时期间禁用确认按钮 - 按钮显示剩余秒数 (例如: "删除 (4s)") 2. 删除操作应用延迟确认(4秒) - ✅ 文档类型删除 (document-types._index.tsx) - ✅ 文档删除和批量删除 (documents.list.tsx) - ✅ 入口模块删除 (entry-modules._index.tsx) - ✅ 提示词删除 (prompts._index.tsx) - ✅ 规则组删除 (rule-groups._index.tsx) 技术实现: - 使用 useEffect + setInterval 实现倒计时 - 倒计时结束自动清理定时器 - 按钮禁用状态控制(disabled + opacity + cursor) 用户体验提升: - 防止误操作:4秒思考时间 - 视觉反馈:倒计时提示 - 操作可逆:倒计时期间可取消 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,8 @@ interface MessageModalProps {
|
||||
customIcon?: React.ReactNode;
|
||||
// 自定义内容
|
||||
children?: React.ReactNode;
|
||||
// 确认按钮延迟时间(秒)- 用于危险操作(如删除)
|
||||
confirmDelay?: number;
|
||||
}
|
||||
|
||||
// 默认自动关闭延迟
|
||||
@@ -63,10 +65,12 @@ export function MessageModal({
|
||||
cancelText = '取消',
|
||||
showCloseButton = true,
|
||||
customIcon,
|
||||
children
|
||||
children,
|
||||
confirmDelay = 0
|
||||
}: MessageModalProps) {
|
||||
const [isClosing, setIsClosing] = useState(false);
|
||||
const [portalElement, setPortalElement] = useState<HTMLElement | null>(null);
|
||||
const [remainingSeconds, setRemainingSeconds] = useState(confirmDelay);
|
||||
|
||||
// 在客户端渲染时获取 portal 容器
|
||||
useEffect(() => {
|
||||
@@ -108,6 +112,23 @@ export function MessageModal({
|
||||
}
|
||||
}, [isOpen, autoClose, autoCloseDelay, handleClose]);
|
||||
|
||||
// 确认延迟倒计时
|
||||
useEffect(() => {
|
||||
if (isOpen && confirmDelay > 0) {
|
||||
setRemainingSeconds(confirmDelay);
|
||||
const timer = setInterval(() => {
|
||||
setRemainingSeconds((prev) => {
|
||||
if (prev <= 1) {
|
||||
clearInterval(timer);
|
||||
return 0;
|
||||
}
|
||||
return prev - 1;
|
||||
});
|
||||
}, 1000);
|
||||
return () => clearInterval(timer);
|
||||
}
|
||||
}, [isOpen, confirmDelay]);
|
||||
|
||||
// 关闭按钮键盘交互
|
||||
const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
@@ -194,15 +215,20 @@ export function MessageModal({
|
||||
<div className="message-modal-actions">
|
||||
{onConfirm && (
|
||||
<>
|
||||
<button
|
||||
className="message-modal-button primary"
|
||||
<button
|
||||
className="message-modal-button primary"
|
||||
onClick={handleConfirm}
|
||||
disabled={remainingSeconds > 0}
|
||||
style={{
|
||||
opacity: remainingSeconds > 0 ? 0.5 : 1,
|
||||
cursor: remainingSeconds > 0 ? 'not-allowed' : 'pointer'
|
||||
}}
|
||||
>
|
||||
{confirmText}
|
||||
{remainingSeconds > 0 ? `${confirmText} (${remainingSeconds}s)` : confirmText}
|
||||
</button>
|
||||
{cancelText && (
|
||||
<button
|
||||
className="message-modal-button"
|
||||
<button
|
||||
className="message-modal-button"
|
||||
onClick={handleClose}
|
||||
>
|
||||
{cancelText}
|
||||
@@ -210,10 +236,10 @@ export function MessageModal({
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
{!onConfirm && (
|
||||
<button
|
||||
className="message-modal-button primary"
|
||||
<button
|
||||
className="message-modal-button primary"
|
||||
onClick={handleClose}
|
||||
>
|
||||
{confirmText}
|
||||
|
||||
@@ -25,7 +25,7 @@ export { UploadArea } from './UploadArea';
|
||||
|
||||
// 反馈组件
|
||||
export { Alert } from './Alert';
|
||||
export { MessageModal } from './MessageModal';
|
||||
export { MessageModal, messageService } from './MessageModal';
|
||||
export { LoadingBar } from './LoadingBar';
|
||||
export { RouteChangeLoader } from './RouteChangeLoader';
|
||||
export { FileProgress } from './FileProgress';
|
||||
|
||||
Reference in New Issue
Block a user