import { useEffect, useState, useMemo } from 'react'; import { Card, Table, Button, Select, Input, Tag, Row, Col, Statistic, message, Space, Tabs, Typography, Badge, theme, } from 'antd'; import { UserOutlined, CheckCircleOutlined, TeamOutlined, SwapOutlined, ClearOutlined, UsergroupAddOutlined, } from '@ant-design/icons'; import { accountApi, type AccountItem, type SupportUserItem } from '../api/modules'; import { getErrorMessage } from '../utils/error'; const { Text } = Typography; const STORAGE_KEY_SELECTED_USER = 'assignments_selected_user_id'; export default function AssignmentsPage() { const { token } = theme.useToken(); const [accounts, setAccounts] = useState([]); const [supportUsers, setSupportUsers] = useState([]); const [selectedUser, setSelectedUser] = useState(null); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [searchText, setSearchText] = useState(''); const [filterTag, setFilterTag] = useState(undefined); const [activeTab, setActiveTab] = useState('unassigned'); const [assigning, setAssigning] = useState(false); // 加载分配概览 const loadSummary = async () => { try { const data = await accountApi.assignmentsSummary(); setSupportUsers(data.support_users); return data.support_users; } catch (e: unknown) { message.error(getErrorMessage(e)); return []; } }; // 加载账号(仅已成功登录过的) const loadAccounts = async () => { try { const all = await accountApi.list({ has_cookie: true }); setAccounts(all); } catch (e: unknown) { message.error(getErrorMessage(e)); } }; // 初始化加载 + 自动选中客服 useEffect(() => { const init = async () => { loadAccounts(); const users = await loadSummary(); if (users.length > 0) { const savedId = localStorage.getItem(STORAGE_KEY_SELECTED_USER); const savedUser = savedId ? users.find((u: SupportUserItem) => u.id === Number(savedId)) : null; setSelectedUser(savedUser || users[0]); } }; init(); }, []); // 标签列表 const allTags = useMemo(() => { const tags = [...new Set(accounts.map((a) => (a.tag || '').trim()).filter(Boolean))]; return tags.sort(); }, [accounts]); // 未分配账号 const unassignedAccounts = useMemo(() => { return accounts.filter((a) => !a.assigned_to); }, [accounts]); // 当前选中客服的已分配账号 const assignedAccounts = useMemo(() => { if (!selectedUser) return []; return accounts.filter((a) => a.assigned_to === selectedUser.id); }, [accounts, selectedUser]); // 当前显示的账号集合 const displayAccounts = useMemo(() => { let list = activeTab === 'unassigned' ? unassignedAccounts : assignedAccounts; if (searchText) { const s = searchText.toLowerCase(); list = list.filter((a) => a.username.toLowerCase().includes(s)); } if (filterTag) { list = list.filter((a) => (a.tag || '').trim() === filterTag); } return list; }, [activeTab, unassignedAccounts, assignedAccounts, searchText, filterTag]); // 切换客服 const handleSelectUser = (user: SupportUserItem) => { setSelectedUser(user); setSelectedRowKeys([]); setActiveTab('unassigned'); setSearchText(''); setFilterTag(undefined); localStorage.setItem(STORAGE_KEY_SELECTED_USER, String(user.id)); }; // 批量分配 const handleBatchAssign = async () => { if (selectedRowKeys.length === 0) { message.warning('请先选择账号'); return; } if (!selectedUser) { message.warning('请先选择客服'); return; } setAssigning(true); try { await accountApi.batchAssign(selectedRowKeys, selectedUser.id); message.success(`已将 ${selectedRowKeys.length} 个账号分配给 ${selectedUser.username}`); setSelectedRowKeys([]); await loadAccounts(); const users = await loadSummary(); const refreshed = users.find((u: SupportUserItem) => u.id === selectedUser.id); if (refreshed) setSelectedUser(refreshed); } catch (e: unknown) { message.error(getErrorMessage(e)); } finally { setAssigning(false); } }; // 批量取消分配 const handleBatchUnassign = async () => { if (selectedRowKeys.length === 0) { message.warning('请先选择账号'); return; } setAssigning(true); try { await accountApi.batchAssign(selectedRowKeys, null); message.success(`已取消 ${selectedRowKeys.length} 个账号的分配`); setSelectedRowKeys([]); await loadAccounts(); const users = await loadSummary(); const refreshed = users.find((u: SupportUserItem) => u.id === selectedUser?.id); if (refreshed) setSelectedUser(refreshed); } catch (e: unknown) { message.error(getErrorMessage(e)); } finally { setAssigning(false); } }; // 一键将未分配账号全部分配给选中客服 const handleAssignAllUnassigned = async () => { if (!selectedUser) { message.warning('请先选择客服'); return; } const ids = unassignedAccounts .filter((a) => { if (searchText && !a.username.toLowerCase().includes(searchText.toLowerCase())) return false; if (filterTag && (a.tag || '').trim() !== filterTag) return false; return true; }) .map((a) => a.id); if (ids.length === 0) { message.info('没有未分配的账号'); return; } setAssigning(true); try { await accountApi.batchAssign(ids, selectedUser.id); message.success(`已将 ${ids.length} 个账号分配给 ${selectedUser.username}`); await loadAccounts(); const users = await loadSummary(); const refreshed = users.find((u: SupportUserItem) => u.id === selectedUser.id); if (refreshed) setSelectedUser(refreshed); } catch (e: unknown) { message.error(getErrorMessage(e)); } finally { setAssigning(false); } }; // 统计 const assignedCount = accounts.filter((a) => !!a.assigned_to).length; const unassignedCount = accounts.length - assignedCount; const columns = [ { title: 'ID', dataIndex: 'id', width: 60 }, { title: '用户名', dataIndex: 'username' }, { title: '标签', dataIndex: 'tag', width: 100, render: (tag: string) => tag ? {tag} : -, }, ]; return (

分配管理

{/* 统计卡片 */} } /> } /> } /> } /> {/* 主体区域 */} {/* 左栏:客服列表 */}
{supportUsers.map((user) => { const isSelected = selectedUser?.id === user.id; return (
handleSelectUser(user)} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 14px', borderRadius: 6, cursor: 'pointer', border: `1px solid ${isSelected ? token.colorPrimary : token.colorBorderSecondary}`, background: isSelected ? token.colorPrimaryBg : token.colorBgContainer, transition: 'all 0.2s', }} onMouseEnter={(e) => { if (!isSelected) (e.currentTarget as HTMLElement).style.borderColor = token.colorPrimary; }} onMouseLeave={(e) => { if (!isSelected) (e.currentTarget as HTMLElement).style.borderColor = token.colorBorderSecondary; }} > {user.username}
); })} {supportUsers.length === 0 && ( 暂无客服用户 )}
{/* 右栏:账号表格 */} {selectedUser ? ( <> 已选中客服: {selectedUser.username}(已分配 {selectedUser.assigned_count} 个) ) : ( 请选择左侧客服进行操作 )} } style={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }} bodyStyle={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, padding: 0 }} > {/* 筛选栏 */}
setSearchText(e.target.value)} style={{ width: 200 }} size="small" />