import { useState, useCallback, useEffect } from 'react' import { createPortal } from 'react-dom' import { isElectron } from '../utils/electronBridge' interface Host { anchorId: string country: string invitationType: number // 1=普票, 2=金票 state: number onlineFans?: number hostsLevel?: string } interface HostListDialogProps { visible: boolean onClose: () => void onSave: (hosts: Host[]) => void } // 等级数据定义 const LEVEL_OPTIONS = [ { label: 'A', value: 'A', children: [ { label: 'A1', value: 'A1' }, { label: 'A2', value: 'A2' }, { label: 'A3', value: 'A3' }, ] }, { label: 'B', value: 'B', children: [ { label: 'B1', value: 'B1' }, { label: 'B2', value: 'B2' }, { label: 'B3', value: 'B3' }, { label: 'B4', value: 'B4' }, { label: 'B5', value: 'B5' }, ] }, { label: 'C', value: 'C', children: [ { label: 'C1', value: 'C1' }, { label: 'C2', value: 'C2' }, { label: 'C3', value: 'C3' }, { label: 'C4', value: 'C4' }, { label: 'C5', value: 'C5' }, ] }, { label: 'D', value: 'D', children: [ { label: 'D1', value: 'D1' }, { label: 'D2', value: 'D2' }, { label: 'D3', value: 'D3' }, { label: 'D4', value: 'D4' }, { label: 'D5', value: 'D5' }, ] } ] // 获取所有子级等级值 const getAllChildLevels = (parentValue: string): string[] => { const parent = LEVEL_OPTIONS.find(p => p.value === parentValue) return parent ? parent.children.map(c => c.value) : [] } function HostListDialog({ visible, onClose, onSave }: HostListDialogProps) { const [hosts, setHosts] = useState([]) const [selected, setSelected] = useState>(new Set()) const [filters, setFilters] = useState({ gold: true, ordinary: true, minOnlineFans: '', maxOnlineFans: '', }) const [maxCount, setMaxCount] = useState(100) const [selectedLevels, setSelectedLevels] = useState>(new Set()) // 选中的等级 const [showLevelDropdown, setShowLevelDropdown] = useState(false) // 锁定 Body 滚动 useEffect(() => { if (visible) { document.body.style.overflow = 'hidden' } else { document.body.style.overflow = '' } return () => { document.body.style.overflow = '' } }, [visible]) // 加载主播数据和配置 useEffect(() => { if (visible) { loadHosts() loadConfig() } }, [visible]) const loadHosts = async () => { if (!isElectron()) return try { const data = await window.electronAPI!.loadAnchorData() setHosts(data as Host[]) setSelected(new Set()) } catch (e) { console.error('加载主播数据失败:', e) } } // 从后端加载配置(包括 maxAnchorCount 和 hostsLevelList) const loadConfig = async () => { if (!isElectron()) return try { const config = await window.electronAPI!.getAutomationConfig() if ((config as any)?.maxAnchorCount !== undefined) { setMaxCount((config as any).maxAnchorCount) } // 加载等级过滤配置 if (config?.filters?.hostsLevelList) { setSelectedLevels(new Set(config.filters.hostsLevelList)) } } catch (e) { console.error('加载配置失败:', e) } } // 更新等级过滤配置到后端 const updateLevelFilter = async (levels: Set) => { setSelectedLevels(levels) if (!isElectron()) return try { await window.electronAPI!.updateAutomationConfig({ filters: { hostsLevelList: Array.from(levels) } } as any) console.log('[HostListDialog] 等级过滤已更新:', Array.from(levels)) } catch (e) { console.error('更新等级配置失败:', e) } } // 切换单个等级选中状态 const toggleLevel = (level: string) => { const newSet = new Set(selectedLevels) if (newSet.has(level)) { newSet.delete(level) } else { newSet.add(level) } updateLevelFilter(newSet) } // 切换整个大类 const toggleParentLevel = (parentValue: string) => { const childLevels = getAllChildLevels(parentValue) const allSelected = childLevels.every(l => selectedLevels.has(l)) const newSet = new Set(selectedLevels) if (allSelected) { // 全部取消 childLevels.forEach(l => newSet.delete(l)) } else { // 全部选中 childLevels.forEach(l => newSet.add(l)) } updateLevelFilter(newSet) } // 更新 maxAnchorCount 到后端 const updateMaxCount = async (value: number) => { setMaxCount(value) if (!isElectron()) return try { await window.electronAPI!.updateAutomationConfig({ maxAnchorCount: value } as any) console.log('[HostListDialog] 主播数据上限已更新:', value) } catch (e) { console.error('更新配置失败:', e) } } // 筛选后的主播列表 const filteredHosts = hosts.filter(h => { if (!filters.gold && h.invitationType === 2) return false if (!filters.ordinary && h.invitationType === 1) return false if (filters.minOnlineFans && h.onlineFans !== undefined) { if (h.onlineFans < parseInt(filters.minOnlineFans)) return false } if (filters.maxOnlineFans && h.onlineFans !== undefined) { if (h.onlineFans > parseInt(filters.maxOnlineFans)) return false } // 等级过滤:如果选择了等级,则只显示选中等级的主播 if (selectedLevels.size > 0 && h.hostsLevel) { if (!selectedLevels.has(h.hostsLevel)) return false } return true }) const selectedCount = selected.size const toggleSelect = useCallback((id: string) => { setSelected(prev => { const next = new Set(prev) if (next.has(id)) next.delete(id) else next.add(id) return next }) }, []) const selectAll = () => { setSelected(new Set(filteredHosts.map(h => h.anchorId))) } const selectNone = () => { setSelected(new Set()) } const invertSelect = () => { setSelected(prev => { const next = new Set() filteredHosts.forEach(h => { if (!prev.has(h.anchorId)) next.add(h.anchorId) }) return next }) } const deleteSelected = () => { if (!selected.size) return if (!confirm(`确认删除选中的 ${selected.size} 项吗?`)) return const remaining = hosts.filter(h => !selected.has(h.anchorId)) setHosts(remaining) setSelected(new Set()) } const handleSave = async () => { if (isElectron()) { await window.electronAPI!.saveAnchorData(hosts) } onSave(hosts) onClose() } if (!visible) return null return createPortal(
{/* 头部 */}

主播管理

已选 {selectedCount} / 共 {filteredHosts.length}
{/* 工具栏 */}
{/* 筛选 */}
在线人数 setFilters(f => ({ ...f, minOnlineFans: e.target.value }))} className="w-20 px-2 py-1 border border-gray-300 rounded text-sm" /> ~ setFilters(f => ({ ...f, maxOnlineFans: e.target.value }))} className="w-20 px-2 py-1 border border-gray-300 rounded text-sm" /> {/* 等级过滤 */}
{/* 下拉菜单 */} {showLevelDropdown && (
选择接收的主播等级(不选则接收全部)
{LEVEL_OPTIONS.map(parent => { const childLevels = parent.children.map(c => c.value) const selectedChildCount = childLevels.filter(l => selectedLevels.has(l)).length const allSelected = selectedChildCount === childLevels.length const partialSelected = selectedChildCount > 0 && !allSelected return (
{parent.children.map(child => ( ))}
) })}
)}
{/* 接收上限 - 紧凑布局 */}
接收上限 { const val = parseInt(e.target.value) updateMaxCount(isNaN(val) ? 0 : val) }} className="w-20 px-2 py-1 border border-gray-300 rounded text-sm focus:border-blue-500 focus:outline-none" />
{/* 主播列表 */}
{filteredHosts.map(host => (
toggleSelect(host.anchorId)} className={`p-3 rounded-lg border cursor-pointer transition-all ${selected.has(host.anchorId) ? 'border-blue-500 bg-blue-50 shadow' : 'border-gray-200 hover:border-gray-300 hover:shadow-sm' }`} >
{host.anchorId} {host.state ? '✓' : '✗'}
{host.country || '—'}
{host.hostsLevel && ( {host.hostsLevel} )} {host.invitationType === 2 ? '金票' : '普票'}
))}
{filteredHosts.length === 0 && (
暂无主播数据
)}
{/* 底部 */}
, document.body ) } export default HostListDialog