Improve web ui

This commit is contained in:
Xin Wang
2026-02-07 14:28:54 +08:00
parent dc3130d387
commit 2725d2fe20
10 changed files with 232 additions and 94 deletions

View File

@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { Download, Search, Calendar, Filter, MessageSquare, Mic, Video, Eye, X, Play } from 'lucide-react';
import { Download, Search, Calendar, Filter, MessageSquare, Mic, Video, Eye, X, Play, User, Bot, Clock } from 'lucide-react';
import { Button, Input, TableHeader, TableRow, TableHead, TableCell, Badge, Drawer } from '../components/UI';
import { mockCallLogs } from '../services/mockData';
import { CallLog, InteractionType } from '../types';
@@ -66,7 +66,7 @@ export const HistoryPage: React.FC = () => {
<div className="flex items-center space-x-2">
<Filter className="h-4 w-4 text-muted-foreground" />
<select
className="flex h-9 w-full rounded-md border-0 bg-white/5 px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/50 [&>option]:bg-card"
className="flex h-9 w-full rounded-md border-0 bg-white/5 px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/50 [&>option]:bg-card text-foreground"
value={sourceFilter}
onChange={(e) => setSourceFilter(e.target.value as any)}
>
@@ -77,7 +77,7 @@ export const HistoryPage: React.FC = () => {
</div>
<div className="flex items-center space-x-2">
<select
className="flex h-9 w-full rounded-md border-0 bg-white/5 px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/50 [&>option]:bg-card"
className="flex h-9 w-full rounded-md border-0 bg-white/5 px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/50 [&>option]:bg-card text-foreground"
value={typeFilter}
onChange={(e) => setTypeFilter(e.target.value as any)}
>
@@ -89,7 +89,7 @@ export const HistoryPage: React.FC = () => {
</div>
<div className="flex items-center space-x-2">
<select
className="flex h-9 w-full rounded-md border-0 bg-white/5 px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/50 [&>option]:bg-card"
className="flex h-9 w-full rounded-md border-0 bg-white/5 px-3 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/50 [&>option]:bg-card text-foreground"
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value as any)}
>
@@ -157,7 +157,7 @@ export const HistoryPage: React.FC = () => {
<Drawer
isOpen={!!selectedLog}
onClose={() => setSelectedLog(null)}
title="历史记录详情"
title="通话详情与对话记录"
>
<div className="flex flex-col h-full overflow-hidden">
<div className="shrink-0 mb-4 p-4 bg-white/5 rounded-xl border border-white/10 space-y-3">
@@ -173,68 +173,62 @@ export const HistoryPage: React.FC = () => {
</div>
</div>
<div className="flex-1 overflow-y-auto space-y-4 pr-1 custom-scrollbar pb-6">
<div className="flex-1 overflow-y-auto space-y-6 pr-2 custom-scrollbar pb-6 px-1">
{(selectedLog.details && selectedLog.details.length > 0) ? (
selectedLog.details.map((detail, index) => (
<div key={index} className={`flex flex-col gap-1 ${detail.role === 'user' ? 'items-end' : 'items-start'}`}>
<div className={`max-w-[85%] rounded-2xl p-4 shadow-sm border ${
detail.role === 'user'
? 'bg-primary/10 border-primary/20 rounded-tr-none'
: 'bg-card border-white/10 rounded-tl-none'
}`}>
<div className="flex items-center gap-2 mb-2 opacity-70">
<span className="text-[10px] font-bold uppercase tracking-wider text-primary">
{detail.role === 'user' ? 'User' : 'AI Assistant'}
</span>
<span className="text-[10px] text-muted-foreground">{detail.timestamp}</span>
<div key={index} className={`flex gap-3 ${detail.role === 'user' ? 'flex-row-reverse' : 'flex-row'}`}>
<div className={`w-8 h-8 rounded-full flex items-center justify-center shrink-0 border border-white/10 ${detail.role === 'user' ? 'bg-primary/20 text-primary' : 'bg-white/5 text-muted-foreground'}`}>
{detail.role === 'user' ? <User className="w-4 h-4" /> : <Bot className="w-4 h-4" />}
</div>
<div className={`flex flex-col max-w-[85%] ${detail.role === 'user' ? 'items-end' : 'items-start'}`}>
<div className="flex items-center gap-2 mb-1 opacity-60">
<span className="text-[10px] uppercase font-bold tracking-wider">{detail.role === 'user' ? 'User' : 'Assistant'}</span>
<span className="text-[10px] font-mono">{detail.timestamp}</span>
</div>
{/* Video Frames */}
{selectedLog.type === 'video' && detail.role === 'user' && detail.imageUrls && detail.imageUrls.length > 0 && (
<div className="flex gap-2 overflow-x-auto mb-3 pb-2">
{detail.imageUrls.map((url, i) => (
<div key={i} className="relative h-20 w-32 rounded-lg overflow-hidden border border-white/10 bg-black/50 shrink-0 group">
<img src={url} alt={`Frame ${i}`} className="h-full w-full object-cover" />
<div className="absolute inset-0 flex items-center justify-center bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity">
<Eye className="w-5 h-5 text-white" />
<div className={`rounded-2xl p-3 shadow-sm text-sm leading-relaxed border ${
detail.role === 'user'
? 'bg-primary/10 border-primary/20 text-white rounded-tr-none'
: 'bg-card border-white/10 text-white/90 rounded-tl-none'
}`}>
{/* Video Frames */}
{selectedLog.type === 'video' && detail.role === 'user' && detail.imageUrls && detail.imageUrls.length > 0 && (
<div className="flex gap-2 overflow-x-auto mb-2 pb-1 custom-scrollbar">
{detail.imageUrls.map((url, i) => (
<div key={i} className="relative h-16 w-24 rounded-lg overflow-hidden border border-white/10 bg-black/50 shrink-0 group">
<img src={url} alt={`Frame ${i}`} className="h-full w-full object-cover" />
<div className="absolute inset-0 flex items-center justify-center bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity">
<Eye className="w-4 h-4 text-white" />
</div>
</div>
</div>
))}
</div>
)}
{/* Content / Transcript */}
<div className="text-sm leading-relaxed text-white/90">
{selectedLog.type !== 'text' && (
<div className="flex items-center gap-2 mb-1.5">
<div className={`p-1.5 rounded-full ${detail.role === 'user' ? 'bg-primary/20' : 'bg-white/10'}`}>
{selectedLog.type === 'audio' ? <Mic size={12} /> : <Video size={12} />}
</div>
<span className="text-[10px] uppercase font-mono text-muted-foreground">Transcript</span>
))}
</div>
)}
{detail.content}
</div>
{/* Audio Player Placeholder for Audio/Video types */}
{selectedLog.type !== 'text' && (
<div className="mt-3 flex items-center gap-2 p-2 rounded-lg bg-black/20 border border-white/5">
<button className="w-6 h-6 rounded-full bg-white/10 hover:bg-primary hover:text-white flex items-center justify-center transition-colors">
<Play size={10} className="ml-0.5" />
</button>
<div className="h-1 flex-1 bg-white/10 rounded-full overflow-hidden">
<div className="h-full w-1/3 bg-primary/50"></div>
{/* Content */}
<div>{detail.content}</div>
{/* Audio Player Placeholder */}
{selectedLog.type !== 'text' && (
<div className="mt-2 flex items-center gap-2 p-1.5 rounded-lg bg-black/20 border border-white/5 w-full min-w-[160px]">
<button className="w-5 h-5 rounded-full bg-white/10 hover:bg-primary hover:text-white flex items-center justify-center transition-colors shrink-0">
<Play size={8} className="ml-0.5" />
</button>
<div className="h-1 flex-1 bg-white/10 rounded-full overflow-hidden">
<div className="h-full w-1/3 bg-primary/50"></div>
</div>
<span className="text-[9px] font-mono text-muted-foreground">00:05</span>
</div>
<span className="text-[10px] font-mono text-muted-foreground">00:05</span>
</div>
)}
)}
</div>
</div>
</div>
))
) : (
<div className="h-full flex flex-col items-center justify-center text-muted-foreground opacity-50 space-y-2">
<MessageSquare className="w-10 h-10" />
<p className="text-sm"></p>
<div className="h-full flex flex-col items-center justify-center text-muted-foreground opacity-40 space-y-3">
<MessageSquare className="w-12 h-12 stroke-1" />
<p className="text-sm font-medium"></p>
</div>
)}
</div>