feat(web): 重构对话列表和资产页面,添加加载骨架屏和确认对话框

- 重构 MiddlePanel 对话列表,按时间分组并优化交互
- 为 AccountList 和 AssetGallery 添加加载骨架屏
- 用确认对话框替换原生 confirm,统一交互体验
- 优化聊天消息组件的视觉样式和细节
- 添加 Escape 键快速返回账户列表导航
- 更新构建资源文件
This commit is contained in:
2026-05-08 00:53:34 +08:00
parent 0fb33b9f57
commit 10f11189f8
10 changed files with 600 additions and 411 deletions

View File

@@ -2,6 +2,8 @@ import { useState, useCallback } from 'react';
import { cn } from '@/lib/utils';
import { renderMarkdown } from '@/lib/markdown';
import { Bot, User, Copy, Trash2, ChevronDown, ChevronRight, RefreshCw, ArrowRight, Quote, Brain } from 'lucide-react';
import { ConfirmDialog } from '@/components/ui/confirm';
import { useConfirm } from '@/hooks/useConfirm';
import { useToast } from '@/hooks/useToast';
import type { Message } from '@/types';
@@ -29,6 +31,7 @@ export function ChatMessage({ message, isLast, isThinking, onRegenerate, onConti
const isTool = message.role === 'tool';
const [reasoningOpen, setReasoningOpen] = useState(false);
const { toast } = useToast();
const { confirmState, confirm, handleConfirm, handleCancel } = useConfirm();
const state = getState(message, !!isLast, !!isThinking);
const handleCopy = useCallback(() => {
@@ -37,10 +40,15 @@ export function ChatMessage({ message, isLast, isThinking, onRegenerate, onConti
});
}, [message.content, toast]);
const handleDelete = useCallback(() => {
if (!confirm('确定删除这条消息?')) return;
onDelete?.(message.id);
}, [message.id, onDelete]);
const handleDeleteClick = useCallback(async () => {
const ok = await confirm({
title: '删除消息',
description: '确定要删除这条消息吗?',
confirmText: '删除',
variant: 'danger',
});
if (ok) onDelete?.(message.id);
}, [message.id, onDelete, confirm]);
// Tool messages
if (isTool) {
@@ -138,7 +146,7 @@ export function ChatMessage({ message, isLast, isThinking, onRegenerate, onConti
className="flex items-center gap-1 px-1.5 py-0.5 rounded-md text-[10px] text-zinc-400 hover:text-zinc-600 hover:bg-zinc-100 transition-colors">
<Quote size={10} />
</button>
<button onClick={handleDelete}
<button onClick={handleDeleteClick}
className="flex items-center gap-1 px-1.5 py-0.5 rounded-md text-[10px] text-zinc-400 hover:text-red-500 hover:bg-red-50 transition-colors">
<Trash2 size={10} />
</button>
@@ -153,6 +161,17 @@ export function ChatMessage({ message, isLast, isThinking, onRegenerate, onConti
</div>
)}
</div>
<ConfirmDialog
open={confirmState.open}
title={confirmState.title}
description={confirmState.description}
confirmText={confirmState.confirmText}
cancelText={confirmState.cancelText}
variant={confirmState.variant}
onConfirm={handleConfirm}
onCancel={handleCancel}
/>
</div>
);
}