feat(chat): add sns timeline entry for private sessions

This commit is contained in:
aits2026
2026-03-06 10:41:06 +08:00
parent ef05466d6d
commit 8d9a042489

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react' import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'
import { Search, MessageSquare, AlertCircle, Loader2, RefreshCw, X, ChevronDown, ChevronLeft, Info, Calendar, Database, Hash, Play, Pause, Image as ImageIcon, Link, Mic, CheckCircle, Copy, Check, CheckSquare, Download, BarChart3, Edit2, Trash2, BellOff, Users, FolderClosed, UserCheck, Crown } from 'lucide-react' import { Search, MessageSquare, AlertCircle, Loader2, RefreshCw, X, ChevronDown, ChevronLeft, Info, Calendar, Database, Hash, Play, Pause, Image as ImageIcon, Link, Mic, CheckCircle, Copy, Check, CheckSquare, Download, BarChart3, Edit2, Trash2, BellOff, Users, FolderClosed, UserCheck, Crown, Aperture } from 'lucide-react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { createPortal } from 'react-dom' import { createPortal } from 'react-dom'
import { useChatStore } from '../stores/chatStore' import { useChatStore } from '../stores/chatStore'
@@ -11,6 +11,8 @@ import { VoiceTranscribeDialog } from '../components/VoiceTranscribeDialog'
import { LivePhotoIcon } from '../components/LivePhotoIcon' import { LivePhotoIcon } from '../components/LivePhotoIcon'
import { AnimatedStreamingText } from '../components/AnimatedStreamingText' import { AnimatedStreamingText } from '../components/AnimatedStreamingText'
import JumpToDatePopover from '../components/JumpToDatePopover' import JumpToDatePopover from '../components/JumpToDatePopover'
import { ContactSnsTimelineDialog } from '../components/Sns/ContactSnsTimelineDialog'
import { type ContactSnsTimelineTarget, isSingleContactSession } from '../components/Sns/contactSnsTimeline'
import * as configService from '../services/config' import * as configService from '../services/config'
import { import {
emitOpenSingleExport, emitOpenSingleExport,
@@ -520,6 +522,7 @@ function ChatPage(props: ChatPageProps) {
const [pendingVoiceTranscriptRequest, setPendingVoiceTranscriptRequest] = useState<{ sessionId: string; messageId: string } | null>(null) const [pendingVoiceTranscriptRequest, setPendingVoiceTranscriptRequest] = useState<{ sessionId: string; messageId: string } | null>(null)
const [inProgressExportSessionIds, setInProgressExportSessionIds] = useState<Set<string>>(new Set()) const [inProgressExportSessionIds, setInProgressExportSessionIds] = useState<Set<string>>(new Set())
const [isPreparingExportDialog, setIsPreparingExportDialog] = useState(false) const [isPreparingExportDialog, setIsPreparingExportDialog] = useState(false)
const [chatSnsTimelineTarget, setChatSnsTimelineTarget] = useState<ContactSnsTimelineTarget | null>(null)
const [exportPrepareHint, setExportPrepareHint] = useState('') const [exportPrepareHint, setExportPrepareHint] = useState('')
// 消息右键菜单 // 消息右键菜单
@@ -2982,6 +2985,20 @@ function ChatPage(props: ChatPageProps) {
) )
) )
) )
const isCurrentSessionPrivateSnsSupported = Boolean(
currentSession &&
isSingleContactSession(currentSession.username) &&
!isCurrentSessionGroup
)
const openCurrentSessionSnsTimeline = useCallback(() => {
if (!currentSession || !isCurrentSessionPrivateSnsSupported) return
setChatSnsTimelineTarget({
username: currentSession.username,
displayName: currentSession.displayName || currentSession.username,
avatarUrl: currentSession.avatarUrl
})
}, [currentSession, isCurrentSessionPrivateSnsSupported])
useEffect(() => { useEffect(() => {
if (!standaloneSessionWindow) return if (!standaloneSessionWindow) return
@@ -3904,6 +3921,16 @@ function ChatPage(props: ChatPageProps) {
)} )}
</button> </button>
)} )}
{!standaloneSessionWindow && isCurrentSessionPrivateSnsSupported && (
<button
className="icon-btn chat-sns-timeline-btn"
onClick={openCurrentSessionSnsTimeline}
disabled={!currentSessionId}
title="查看对方朋友圈"
>
<Aperture size={18} />
</button>
)}
{!standaloneSessionWindow && ( {!standaloneSessionWindow && (
<button <button
className={`icon-btn batch-transcribe-btn${isBatchTranscribing ? ' transcribing' : ''}`} className={`icon-btn batch-transcribe-btn${isBatchTranscribing ? ' transcribing' : ''}`}
@@ -4007,6 +4034,11 @@ function ChatPage(props: ChatPageProps) {
</div> </div>
)} )}
<ContactSnsTimelineDialog
target={chatSnsTimelineTarget}
onClose={() => setChatSnsTimelineTarget(null)}
/>
<div className={`message-content-wrapper ${hasInitialMessages ? 'loaded' : 'loading'} ${isSessionSwitching ? 'switching' : ''}`}> <div className={`message-content-wrapper ${hasInitialMessages ? 'loaded' : 'loading'} ${isSessionSwitching ? 'switching' : ''}`}>
{standaloneSessionWindow && standaloneLoadStage !== 'ready' && ( {standaloneSessionWindow && standaloneLoadStage !== 'ready' && (
<div className="standalone-phase-overlay" role="status" aria-live="polite"> <div className="standalone-phase-overlay" role="status" aria-live="polite">