mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-24 23:06:51 +00:00
Merge pull request #444 from 2977094657/fix/issue-400-exited-group-filter-toggle
fix(chat): 增加已退出群聊隐藏开关
This commit is contained in:
@@ -304,11 +304,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.refresh-btn {
|
.refresh-btn,
|
||||||
|
.session-filter-btn {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: 1px solid transparent;
|
||||||
background: var(--bg-tertiary);
|
background: var(--bg-tertiary);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
@@ -324,6 +325,12 @@
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: var(--primary-light);
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
@@ -812,7 +819,7 @@
|
|||||||
.icon-btn {
|
.icon-btn {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border: none;
|
border: 1px solid transparent;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -835,6 +842,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.session-filter-btn {
|
||||||
|
background: var(--bg-primary);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: var(--primary-light);
|
||||||
|
border-color: var(--primary-light);
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.search-row {
|
.search-row {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -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, Aperture } from 'lucide-react'
|
import { Search, MessageSquare, MessageSquareOff, 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'
|
||||||
@@ -34,6 +34,16 @@ const SYSTEM_MESSAGE_TYPES = [
|
|||||||
266287972401, // 拍一拍
|
266287972401, // 拍一拍
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const EXITED_GROUP_SUMMARY_EXACT = '你已退出该群聊'
|
||||||
|
|
||||||
|
function isExitedGroupSession(session: Pick<ChatSession, 'username' | 'lastMsgType' | 'summary'>): boolean {
|
||||||
|
return (
|
||||||
|
session.username.endsWith('@chatroom') &&
|
||||||
|
session.lastMsgType === 10000 &&
|
||||||
|
session.summary.trim() === EXITED_GROUP_SUMMARY_EXACT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
interface XmlField {
|
interface XmlField {
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
@@ -512,6 +522,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
const [groupMembersLoadingHint, setGroupMembersLoadingHint] = useState('')
|
const [groupMembersLoadingHint, setGroupMembersLoadingHint] = useState('')
|
||||||
const [isRefreshingGroupMembers, setIsRefreshingGroupMembers] = useState(false)
|
const [isRefreshingGroupMembers, setIsRefreshingGroupMembers] = useState(false)
|
||||||
const [groupMemberSearchKeyword, setGroupMemberSearchKeyword] = useState('')
|
const [groupMemberSearchKeyword, setGroupMemberSearchKeyword] = useState('')
|
||||||
|
const [hideExitedGroups, setHideExitedGroups] = useState(true)
|
||||||
const [copiedField, setCopiedField] = useState<string | null>(null)
|
const [copiedField, setCopiedField] = useState<string | null>(null)
|
||||||
const [highlightedMessageKeys, setHighlightedMessageKeys] = useState<string[]>([])
|
const [highlightedMessageKeys, setHighlightedMessageKeys] = useState<string[]>([])
|
||||||
const [isRefreshingSessions, setIsRefreshingSessions] = useState(false)
|
const [isRefreshingSessions, setIsRefreshingSessions] = useState(false)
|
||||||
@@ -581,6 +592,25 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
|
|
||||||
|
|
||||||
const highlightedMessageSet = useMemo(() => new Set(highlightedMessageKeys), [highlightedMessageKeys])
|
const highlightedMessageSet = useMemo(() => new Set(highlightedMessageKeys), [highlightedMessageKeys])
|
||||||
|
const exitedGroupCount = useMemo(() => {
|
||||||
|
if (!Array.isArray(sessions)) return 0
|
||||||
|
return sessions.filter(isExitedGroupSession).length
|
||||||
|
}, [sessions])
|
||||||
|
const sessionsAfterExitedGroupFilter = useMemo(() => {
|
||||||
|
if (!Array.isArray(sessions)) return []
|
||||||
|
if (!hideExitedGroups) return sessions
|
||||||
|
return sessions.filter((session) => !isExitedGroupSession(session))
|
||||||
|
}, [sessions, hideExitedGroups])
|
||||||
|
const exitedGroupFilterTitle = useMemo(() => {
|
||||||
|
if (hideExitedGroups) {
|
||||||
|
return exitedGroupCount > 0
|
||||||
|
? `已隐藏 ${exitedGroupCount} 个已退出群聊,点击显示`
|
||||||
|
: '已开启:隐藏已退出群聊'
|
||||||
|
}
|
||||||
|
return exitedGroupCount > 0
|
||||||
|
? `当前显示全部群聊(含 ${exitedGroupCount} 个已退出群聊),点击隐藏`
|
||||||
|
: '当前显示全部群聊,点击隐藏已退出群聊'
|
||||||
|
}, [exitedGroupCount, hideExitedGroups])
|
||||||
const messageKeySetRef = useRef<Set<string>>(new Set())
|
const messageKeySetRef = useRef<Set<string>>(new Set())
|
||||||
const lastMessageTimeRef = useRef(0)
|
const lastMessageTimeRef = useRef(0)
|
||||||
const sessionMapRef = useRef<Map<string, ChatSession>>(new Map())
|
const sessionMapRef = useRef<Map<string, ChatSession>>(new Map())
|
||||||
@@ -2963,16 +2993,16 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
|
|
||||||
// 普通视图:隐藏 isFolded 的群,保留 placeholder_foldgroup 入口
|
// 普通视图:隐藏 isFolded 的群,保留 placeholder_foldgroup 入口
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!Array.isArray(sessions)) {
|
if (!Array.isArray(sessionsAfterExitedGroupFilter)) {
|
||||||
setFilteredSessions([])
|
setFilteredSessions([])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否有折叠的群聊
|
// 检查是否有折叠的群聊
|
||||||
const foldedGroups = sessions.filter(s => s.isFolded && !s.username.toLowerCase().includes('placeholder_foldgroup'))
|
const foldedGroups = sessionsAfterExitedGroupFilter.filter(s => s.isFolded && !s.username.toLowerCase().includes('placeholder_foldgroup'))
|
||||||
const hasFoldedGroups = foldedGroups.length > 0
|
const hasFoldedGroups = foldedGroups.length > 0
|
||||||
|
|
||||||
let visible = sessions.filter(s => {
|
let visible = sessionsAfterExitedGroupFilter.filter(s => {
|
||||||
if (s.isFolded && !s.username.toLowerCase().includes('placeholder_foldgroup')) return false
|
if (s.isFolded && !s.username.toLowerCase().includes('placeholder_foldgroup')) return false
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@@ -3022,12 +3052,12 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
s.username.toLowerCase().includes(lower) ||
|
s.username.toLowerCase().includes(lower) ||
|
||||||
s.summary.toLowerCase().includes(lower)
|
s.summary.toLowerCase().includes(lower)
|
||||||
))
|
))
|
||||||
}, [sessions, searchKeyword, setFilteredSessions])
|
}, [sessionsAfterExitedGroupFilter, searchKeyword, setFilteredSessions])
|
||||||
|
|
||||||
// 折叠群列表(独立计算,供折叠 panel 使用)
|
// 折叠群列表(独立计算,供折叠 panel 使用)
|
||||||
const foldedSessions = useMemo(() => {
|
const foldedSessions = useMemo(() => {
|
||||||
if (!Array.isArray(sessions)) return []
|
if (!Array.isArray(sessionsAfterExitedGroupFilter)) return []
|
||||||
const folded = sessions.filter(s => s.isFolded)
|
const folded = sessionsAfterExitedGroupFilter.filter(s => s.isFolded)
|
||||||
if (!searchKeyword.trim() || !foldedView) return folded
|
if (!searchKeyword.trim() || !foldedView) return folded
|
||||||
const lower = searchKeyword.toLowerCase()
|
const lower = searchKeyword.toLowerCase()
|
||||||
return folded.filter(s =>
|
return folded.filter(s =>
|
||||||
@@ -3035,7 +3065,7 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
s.username.toLowerCase().includes(lower) ||
|
s.username.toLowerCase().includes(lower) ||
|
||||||
s.summary.toLowerCase().includes(lower)
|
s.summary.toLowerCase().includes(lower)
|
||||||
)
|
)
|
||||||
}, [sessions, searchKeyword, foldedView])
|
}, [sessionsAfterExitedGroupFilter, searchKeyword, foldedView])
|
||||||
|
|
||||||
const hasSessionRecords = Array.isArray(sessions) && sessions.length > 0
|
const hasSessionRecords = Array.isArray(sessions) && sessions.length > 0
|
||||||
const shouldShowSessionsSkeleton = isLoadingSessions && !hasSessionRecords
|
const shouldShowSessionsSkeleton = isLoadingSessions && !hasSessionRecords
|
||||||
@@ -3878,6 +3908,15 @@ function ChatPage(props: ChatPageProps) {
|
|||||||
{/* 普通 header */}
|
{/* 普通 header */}
|
||||||
<div className="session-header-panel main-header">
|
<div className="session-header-panel main-header">
|
||||||
<div className="search-row">
|
<div className="search-row">
|
||||||
|
<button
|
||||||
|
className={`icon-btn session-filter-btn ${hideExitedGroups ? 'active' : ''}`}
|
||||||
|
onClick={() => setHideExitedGroups((prev) => !prev)}
|
||||||
|
title={exitedGroupFilterTitle}
|
||||||
|
aria-label={hideExitedGroups ? '显示已退出群聊' : '隐藏已退出群聊'}
|
||||||
|
aria-pressed={hideExitedGroups}
|
||||||
|
>
|
||||||
|
<MessageSquareOff size={15} />
|
||||||
|
</button>
|
||||||
<div className="search-box expanded">
|
<div className="search-box expanded">
|
||||||
<Search size={14} />
|
<Search size={14} />
|
||||||
<input
|
<input
|
||||||
|
|||||||
Reference in New Issue
Block a user