ux: 对话历史页手机端优化(布局/按钮/卡片/气泡宽度)
CI / 后端测试 (push) Has been cancelled
CI / 前端构建 (push) Has been cancelled

This commit is contained in:
selfrelease
2026-08-31 19:51:22 +08:00
parent 9e79e17a35
commit 86f15bc79c
2 changed files with 22 additions and 23 deletions
+3 -3
View File
@@ -11,9 +11,9 @@ interface PageLayoutProps {
export function PageLayout({ title, description, actions, children, className }: PageLayoutProps) {
return (
<div className={cn('space-y-6', className)}>
<div className="flex items-start justify-between gap-4">
<div>
<div className={cn('space-y-4 md:space-y-6', className)}>
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between sm:gap-4">
<div className="min-w-0">
<h2 className="text-xl font-bold text-foreground md:text-2xl">{title}</h2>
{description && <p className="mt-1 text-sm text-muted-foreground">{description}</p>}
</div>
+19 -20
View File
@@ -183,8 +183,8 @@ export function ChatHistory() {
actions={
<div className="flex items-center gap-2">
<Button variant="outline" size="sm" onClick={handleBack}>
<ArrowLeft className="mr-1 h-4 w-4" />
返回列表
<ArrowLeft className="h-4 w-4 sm:mr-1" />
<span className="hidden sm:inline">返回列表</span>
</Button>
<Button
variant="outline"
@@ -192,19 +192,19 @@ export function ChatHistory() {
className="text-destructive hover:text-destructive"
onClick={() => setDeleteTarget(currentSession)}
>
<Trash2 className="mr-1 h-4 w-4" />
删除
<Trash2 className="h-4 w-4 sm:mr-1" />
<span className="hidden sm:inline">删除</span>
</Button>
</div>
}
>
<Card>
<CardContent className="p-4">
<div className="mb-4 flex items-center gap-3 border-b pb-3">
<modeCfg.icon className="h-5 w-5 text-muted-foreground" />
<div className="flex-1">
<p className="font-medium">{currentSession.title || '未命名对话'}</p>
<div className="mt-0.5 flex flex-wrap items-center gap-2">
<div className="mb-4 flex items-center gap-2 border-b pb-3 sm:gap-3">
<modeCfg.icon className="h-4 w-4 shrink-0 text-muted-foreground sm:h-5 sm:w-5" />
<div className="min-w-0 flex-1">
<p className="truncate font-medium">{currentSession.title || '未命名对话'}</p>
<div className="mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1">
<span className="text-xs text-muted-foreground">{modeCfg.label}</span>
{currentSession.scene && (
<Badge variant="secondary" className="text-xs">
@@ -212,8 +212,7 @@ export function ChatHistory() {
</Badge>
)}
<span className="text-xs text-muted-foreground">
{formatTime(currentSession.first_message_at)} ~ {formatTime(currentSession.last_message_at)}
{' · '}{currentSession.message_count} 条消息
{currentSession.message_count} 条 · {formatTime(currentSession.last_message_at)}
</span>
</div>
</div>
@@ -291,13 +290,13 @@ export function ChatHistory() {
title="对话历史"
description="普通模式可直接查看,保密模式需密码验证,阅后即焚不落库"
actions={
<div className="flex flex-wrap items-center gap-1 rounded-md border bg-card p-1">
<div className="flex items-center gap-1 self-start rounded-md border bg-card p-1 sm:self-auto">
{(['all', 'normal', 'confidential'] as const).map((m) => (
<Button
key={m}
variant={modeFilter === m ? 'default' : 'ghost'}
size="sm"
className="h-7 text-xs"
className="h-7 px-2.5 text-xs"
onClick={() => setModeFilter(m)}
>
{m === 'all' ? '全部' : m === 'normal' ? '普通' : '保密'}
@@ -354,13 +353,13 @@ export function ChatHistory() {
className="cursor-pointer transition-colors hover:bg-accent/50"
onClick={() => handleView(session)}
>
<CardContent className="flex items-center gap-3 p-4">
<div className={cn('flex h-10 w-10 items-center justify-center rounded-lg', modeCfg.color)}>
<modeCfg.icon className="h-5 w-5" />
<CardContent className="flex items-center gap-2 p-3 sm:gap-3 sm:p-4">
<div className={cn('flex h-9 w-9 shrink-0 items-center justify-center rounded-lg sm:h-10 sm:w-10', modeCfg.color)}>
<modeCfg.icon className="h-4 w-4 sm:h-5 sm:w-5" />
</div>
<div className="min-w-0 flex-1">
<p className="truncate text-sm font-medium">{session.title || '未命名对话'}</p>
<div className="mt-0.5 flex flex-wrap items-center gap-2">
<div className="mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5">
<span className="text-xs text-muted-foreground">{modeCfg.label}</span>
<span className="text-xs text-muted-foreground">
{session.message_count} 条 · {formatTime(session.last_message_at)}
@@ -374,7 +373,7 @@ export function ChatHistory() {
>
<Trash2 className="h-4 w-4" />
</button>
<ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground" />
<ChevronRight className="hidden h-4 w-4 shrink-0 text-muted-foreground sm:block" />
</CardContent>
</Card>
)
@@ -402,7 +401,7 @@ function MessageBubble({ message }: { message: HistoryMessage }) {
const riskLevel = message.risk?.level
return (
<div className={cn('flex', isUser ? 'justify-end' : 'justify-start')}>
<div className={cn('max-w-[80%] rounded-lg p-3', isUser ? 'bg-primary text-primary-foreground' : 'bg-muted')}>
<div className={cn('max-w-[92%] rounded-lg p-3 sm:max-w-[80%]', isUser ? 'bg-primary text-primary-foreground' : 'bg-muted')}>
{/* 消息正文:用户消息纯文本,AI 消息 Markdown 渲染 */}
{isUser ? (
<p className="whitespace-pre-wrap text-sm">{message.content}</p>
@@ -440,7 +439,7 @@ function MessageBubble({ message }: { message: HistoryMessage }) {
{!isUser && (
<div className="mt-2 border-t border-border/30 pt-2">
<div className="mb-1 flex items-center gap-1 text-[10px] text-muted-foreground">
<BookOpen className="h-3 w-3" /> 参考来源
<BookOpen className="h-3 w-3 shrink-0" /> 参考来源
</div>
{message.meta?.rag_context && message.meta.rag_context.length > 0 ? (
<div className="space-y-1">