import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Alert, Button, Card, Form, Input, InputNumber, message, Modal, Popconfirm, Select, Space, Table, Tabs, Tag, Typography } from 'antd'; import { DeleteOutlined, EditOutlined, EyeOutlined, PlusOutlined, ReloadOutlined, SearchOutlined, TeamOutlined, UserSwitchOutlined } from '@ant-design/icons'; import { deleteAdminTeam, getAdminTeamManagerHistory, getAdminTeamMemberUsage, getAdminTeams, getAdminTeamSubscriptions, getTeamMembersForAdmin, saveAdminTeam, setTeamManager, } from '../api'; import type { AdminTeam, AdminUser } from '../types'; const STATUS = { active: '启用', disabled: '禁用' } as Record; const fmt = (v?: string | null) => v ? new Date(v).toLocaleString('zh-CN', { hour12: false }) : '-'; const AdminTeams: React.FC = () => { const [items, setItems] = useState([]); const [loading,setLoading]=useState(false); const [page,setPage]=useState(1); const [pageSize,setPageSize]=useState(20); const [total,setTotal]=useState(0); const [keyword,setKeyword]=useState(''); const [status,setStatus]=useState(); const [form]=Form.useForm(); const [edit,setEdit]=useState(null); const [editOpen,setEditOpen]=useState(false); const [detail,setDetail]=useState(null); const [members,setMembers]=useState([]); const [subscriptions,setSubscriptions]=useState([]); const [usage,setUsage]=useState([]); const [history,setHistory]=useState([]); const [detailLoading,setDetailLoading]=useState(false); const query=useMemo(()=>({page,pageSize,keyword:keyword||undefined,status}),[page,pageSize,keyword,status]); const load=useCallback(async()=>{setLoading(true);try{const r=await getAdminTeams(query);setItems(r.items||[]);setTotal(Number(r.total||0));}catch(e:any){message.error(e?.message||'团队列表加载失败');}finally{setLoading(false);}},[query]); useEffect(()=>{void load();},[load]); const openEdit=(team?:AdminTeam)=>{const item=team||null;setEdit(item);form.resetFields();form.setFieldsValue(item?{name:item.name,code:item.code,description:item.description,status:item.status,sortOrder:item.sortOrder}:{status:'active',sortOrder:0});setEditOpen(true);}; const save=async()=>{try{const v=await form.validateFields();await saveAdminTeam({id:edit?.id,name:v.name,code:v.code||null,description:v.description||null,status:v.status,sort_order:Number(v.sortOrder||0)});message.success(edit?'团队已更新':'团队已创建');setEditOpen(false);await load();}catch(e:any){if(!e?.errorFields)message.error(e?.message||'保存失败');}}; const openDetail=async(team:AdminTeam)=>{setDetail(team);setDetailLoading(true);try{const [m,s,u,h]=await Promise.all([getTeamMembersForAdmin(team.id,1,500),getAdminTeamSubscriptions(team.id),getAdminTeamMemberUsage(team.id),getAdminTeamManagerHistory(team.id)]);setMembers(m.items||[]);setSubscriptions(s||[]);setUsage(u||[]);setHistory(h||[]);}catch(e:any){message.error(e?.message||'团队详情加载失败');}finally{setDetailLoading(false);}}; const columns=[ {title:'团队',dataIndex:'name',width:220,render:(v:string,r:AdminTeam)=>
{v}
{r.code||'-'}
}, {title:'状态',dataIndex:'status',width:100,render:(v:string,r:AdminTeam)=>{r.statusLabel||STATUS[v]||'其他状态'}}, {title:'成员数',dataIndex:'memberCount',width:90,align:'right' as const}, {title:'当前队长',dataIndex:'managerName',width:140,render:(v:string)=>v||'-'}, {title:'团队首购时间',dataIndex:'firstSubscriptionPaidAt',width:180,render:(v:string)=>fmt(v)}, {title:'排序',dataIndex:'sortOrder',width:80}, {title:'备注',dataIndex:'description',ellipsis:true,render:(v:string)=>v||'-'}, {title:'操作',fixed:'right' as const,width:220,render:(_:any,r:AdminTeam)=>{try{await deleteAdminTeam(r.id);message.success('团队已删除');await load();}catch(e:any){message.error(e?.message||'删除失败');}}}>}, ]; const subColumns=[ {title:'订阅实例',width:190,render:(_:any,r:any)=>{r.subscription?.subscriptionNo||'-'}}, {title:'套餐',render:(_:any,r:any)=>r.subscription?.productNameSnapshot||'-'}, {title:'状态',render:(_:any,r:any)=>{r.subscription?.statusLabel||'其他状态'}}, {title:'数量N',render:(_:any,r:any)=>r.subscription?.quantitySnapshot||1}, {title:'席位',render:(_:any,r:any)=>`${r.activeSeatCount||0}/${r.seatLimit||0}`}, {title:'本期总积分',dataIndex:'periodTotalCredits',align:'right' as const},{title:'本期剩余',dataIndex:'periodUnspentCredits',align:'right' as const},{title:'未分配',dataIndex:'periodUnallocatedCredits',align:'right' as const}, {title:'订阅到期',render:(_:any,r:any)=>fmt(r.subscription?.expiresAt)}, ]; const memberColumns=[{title:'用户名',dataIndex:'username'},{title:'手机号',dataIndex:'phone',render:(v:string)=>v||'-'},{title:'个人积分',dataIndex:'personalCredits',align:'right' as const,render:(v:number)=>Number(v||0).toLocaleString()},{title:'团队可用',dataIndex:'teamAvailableCredits',align:'right' as const,render:(v:number)=>Number(v||0).toLocaleString()},{title:'团队冻结',dataIndex:'teamFrozenCredits',align:'right' as const,render:(v:number)=>Number(v||0).toLocaleString()},{title:'设为队长',render:(_:any,r:AdminUser)=>r.id===detail?.managerId? 当前队长:{if(!detail)return;try{await setTeamManager(detail.id,r.id);message.success('队长已更换');await openDetail({...detail,managerId:r.id,managerName:r.username});await load();}catch(e:any){message.error(e?.message||'更换队长失败');}}}>}]; return
{setKeyword(e.target.value);setPage(1);}} placeholder="团队名称/编码/备注" prefix={} style={{width:260}}/>