feat(history): establish Telegram SaaS platform foundation

This commit is contained in:
wmq
2026-07-27 23:03:00 +08:00
parent cf0eed46c3
commit cd06d049fe
92 changed files with 5608 additions and 3749 deletions
@@ -0,0 +1,75 @@
import { Brain, Building2, ChevronRight } from 'lucide-react'
import type { Conversation, Customer, CustomerStage } from '@/types'
import { Avatar } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import { CountryFlag } from '@/components/common/CountryFlag'
import {
CustomerStageBadge,
IntentScoreBadge,
RiskLevelBadge,
SentimentBadge,
} from '@/components/common/StatusBadges'
const validStages = new Set([
'initial', 'comparing', 'sample', 'custom', 'closing',
'fulfillment', 'aftersales', 'repurchase',
])
export function ConversationInsightBar({
customer,
conversation,
onOpenProfile,
}: {
customer: Customer
conversation: Conversation
onOpenProfile: () => void
}) {
const stage = validStages.has(customer.stage) ? customer.stage : 'initial'
const summary = customer.aiProfile?.summary || conversation.summary || 'AI 正在根据会话完善客户画像'
return (
<div data-testid="conversation-insight-bar" className="border-b border-border bg-gradient-to-r from-primary-50/80 via-card to-card px-3 py-2">
<div className="flex min-w-0 items-center gap-2.5">
<Avatar name={customer.name} src={customer.avatarUrl} size="sm" />
<div className="min-w-0">
<div className="flex items-center gap-1.5">
<span className="max-w-40 truncate text-sm font-semibold">{customer.name}</span>
{customer.telegramUsername && (
<span className="max-w-32 truncate text-[11px] text-muted-foreground">
@{customer.telegramUsername}
</span>
)}
<CountryFlag code={customer.country} withName={false} />
{customer.company && (
<span className="hidden items-center gap-1 truncate text-xs text-muted-foreground md:flex">
<Building2 className="h-3 w-3" /> {customer.company}
</span>
)}
</div>
<p className="mt-0.5 max-w-[60vw] truncate text-[11px] text-muted-foreground">
<Brain className="mr-1 inline h-3 w-3 text-primary" />
{summary}
</p>
</div>
<div className="ms-auto hidden items-center gap-2 sm:flex">
<span className="flex items-center gap-1 text-xs text-muted-foreground">
意向 <IntentScoreBadge score={Number(customer.intentScore || 0)} />
</span>
<SentimentBadge sentiment={customer.sentiment || 'neutral'} />
<CustomerStageBadge stage={stage as CustomerStage} />
<RiskLevelBadge level={customer.riskLevel || 'none'} />
</div>
<Button variant="ghost" size="sm" onClick={onOpenProfile}>
<span className="hidden lg:inline">客户画像</span>
<ChevronRight className="h-4 w-4" />
</Button>
</div>
<div className="mt-1.5 flex items-center gap-3 overflow-x-auto sm:hidden">
<span className="flex shrink-0 items-center gap-1 text-xs">意向 <IntentScoreBadge score={Number(customer.intentScore || 0)} /></span>
<SentimentBadge sentiment={customer.sentiment || 'neutral'} />
<CustomerStageBadge stage={stage as CustomerStage} />
<RiskLevelBadge level={customer.riskLevel || 'none'} />
</div>
</div>
)
}