1
This commit is contained in:
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -28,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script type="module" crossorigin src="/assets/index-CI8eObtr.js"></script>
|
<script type="module" crossorigin src="/assets/index-BaN8_2WC.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-D7ShJUt4.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-D7ShJUt4.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -36,10 +36,15 @@ const AdminTeams: React.FC = () => {
|
|||||||
|
|
||||||
// 管理人弹窗状态
|
// 管理人弹窗状态
|
||||||
const [managerModal, setManagerModal] = useState<{ open: boolean; team: AdminTeam | null }>({ open: false, team: null });
|
const [managerModal, setManagerModal] = useState<{ open: boolean; team: AdminTeam | null }>({ open: false, team: null });
|
||||||
const [members, setMembers] = useState<AdminUser[]>([]);
|
const [managerMembers, setManagerMembers] = useState<AdminUser[]>([]);
|
||||||
const [managerLoading, setManagerLoading] = useState(false);
|
const [managerLoading, setManagerLoading] = useState(false);
|
||||||
const [selectedManagerId, setSelectedManagerId] = useState<string | null>(null);
|
const [selectedManagerId, setSelectedManagerId] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// 查看成员弹窗状态
|
||||||
|
const [membersModal, setMembersModal] = useState<{ open: boolean; team: AdminTeam | null }>({ open: false, team: null });
|
||||||
|
const [teamMembers, setTeamMembers] = useState<AdminUser[]>([]);
|
||||||
|
const [membersLoading, setMembersLoading] = useState(false);
|
||||||
|
|
||||||
const query = useMemo(() => ({
|
const query = useMemo(() => ({
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
@@ -113,19 +118,31 @@ const AdminTeams: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadTeamMembers = async (teamId: string): Promise<AdminUser[]> => {
|
||||||
|
try {
|
||||||
|
const res = await getTeamMembersForAdmin(teamId);
|
||||||
|
return res.items || [];
|
||||||
|
} catch (e: any) {
|
||||||
|
message.error(e?.message || '加载成员失败');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const openManagerModal = async (team: AdminTeam) => {
|
const openManagerModal = async (team: AdminTeam) => {
|
||||||
setManagerModal({ open: true, team });
|
setManagerModal({ open: true, team });
|
||||||
setSelectedManagerId(team.managerId || null);
|
setSelectedManagerId(team.managerId || null);
|
||||||
setManagerLoading(true);
|
setManagerLoading(true);
|
||||||
try {
|
const data = await loadTeamMembers(team.id);
|
||||||
const res = await getTeamMembersForAdmin(team.id);
|
setManagerMembers(data);
|
||||||
setMembers(res.items || []);
|
setManagerLoading(false);
|
||||||
} catch (e: any) {
|
};
|
||||||
message.error(e?.message || '加载成员失败');
|
|
||||||
setMembers([]);
|
const openMembersModal = async (team: AdminTeam) => {
|
||||||
} finally {
|
setMembersModal({ open: true, team });
|
||||||
setManagerLoading(false);
|
setMembersLoading(true);
|
||||||
}
|
const data = await loadTeamMembers(team.id);
|
||||||
|
setTeamMembers(data);
|
||||||
|
setMembersLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSetManager = async () => {
|
const handleSetManager = async () => {
|
||||||
@@ -203,10 +220,11 @@ const AdminTeams: React.FC = () => {
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
width: 160,
|
width: 230,
|
||||||
fixed: 'right' as const,
|
fixed: 'right' as const,
|
||||||
render: (_: any, r: AdminTeam) => (
|
render: (_: any, r: AdminTeam) => (
|
||||||
<Space size={4}>
|
<Space size={4}>
|
||||||
|
<Button type="link" size="small" icon={<UserOutlined />} onClick={() => openMembersModal(r)}>成员</Button>
|
||||||
<Button type="link" size="small" icon={<SettingOutlined />} onClick={() => openManagerModal(r)}>管理人</Button>
|
<Button type="link" size="small" icon={<SettingOutlined />} onClick={() => openManagerModal(r)}>管理人</Button>
|
||||||
<Button type="link" size="small" icon={<EditOutlined />} onClick={() => openEdit(r)}>编辑</Button>
|
<Button type="link" size="small" icon={<EditOutlined />} onClick={() => openEdit(r)}>编辑</Button>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
@@ -313,7 +331,7 @@ const AdminTeams: React.FC = () => {
|
|||||||
allowClear
|
allowClear
|
||||||
loading={managerLoading}
|
loading={managerLoading}
|
||||||
optionFilterProp="label"
|
optionFilterProp="label"
|
||||||
options={members.map((m) => ({
|
options={managerMembers.map((m) => ({
|
||||||
value: m.id,
|
value: m.id,
|
||||||
label: `${m.username}${m.phone ? ` (${m.phone})` : ''}`,
|
label: `${m.username}${m.phone ? ` (${m.phone})` : ''}`,
|
||||||
}))}
|
}))}
|
||||||
@@ -321,6 +339,38 @@ const AdminTeams: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
{/* 查看成员弹窗 */}
|
||||||
|
<Modal
|
||||||
|
title={<Space><UserOutlined />团队成员 - {membersModal.team?.name}</Space>}
|
||||||
|
open={membersModal.open}
|
||||||
|
onCancel={() => setMembersModal({ open: false, team: null })}
|
||||||
|
footer={null}
|
||||||
|
width={600}
|
||||||
|
>
|
||||||
|
<div style={{ marginTop: 8 }}>
|
||||||
|
{membersModal.team && (
|
||||||
|
<Table
|
||||||
|
size="small"
|
||||||
|
rowKey="id"
|
||||||
|
loading={membersLoading}
|
||||||
|
dataSource={teamMembers}
|
||||||
|
pagination={false}
|
||||||
|
scroll={{ y: 400 }}
|
||||||
|
columns={[
|
||||||
|
{ title: '用户名', dataIndex: 'username', width: 140, render: (v: string) => <Typography.Text strong>{v}</Typography.Text> },
|
||||||
|
{ title: '手机号', dataIndex: 'phone', width: 130, render: (v: string) => v || '-' },
|
||||||
|
{ title: '积分', dataIndex: 'credits', width: 100, render: (v: number) => <Typography.Text style={{ color: '#6366f1' }}>{(v ?? 0).toFixed(2)}</Typography.Text> },
|
||||||
|
{
|
||||||
|
title: '状态', dataIndex: 'isActive', width: 80,
|
||||||
|
render: (v: boolean) => <Tag color={v ? 'green' : 'red'}>{v ? '启用' : '禁用'}</Tag>,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
locale={{ emptyText: '该团队暂无成员' }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ def _team_snapshot(team: Team | None) -> dict[str, Any]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _team_out_payload(team: Team, member_count: int = 0) -> dict[str, Any]:
|
def _team_out_payload(team: Team, member_count: int = 0, manager_name: str | None = None) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"id": team.id,
|
"id": team.id,
|
||||||
"name": team.name,
|
"name": team.name,
|
||||||
@@ -42,6 +42,8 @@ def _team_out_payload(team: Team, member_count: int = 0) -> dict[str, Any]:
|
|||||||
"member_count": int(member_count or 0),
|
"member_count": int(member_count or 0),
|
||||||
"created_at": team.created_at,
|
"created_at": team.created_at,
|
||||||
"updated_at": team.updated_at,
|
"updated_at": team.updated_at,
|
||||||
|
"manager_id": getattr(team, "manager_id", None),
|
||||||
|
"manager_name": manager_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -112,8 +114,25 @@ async def list_teams(
|
|||||||
.group_by(User.team_id)
|
.group_by(User.team_id)
|
||||||
)
|
)
|
||||||
member_map = {row[0]: int(row[1] or 0) for row in member_result.all()}
|
member_map = {row[0]: int(row[1] or 0) for row in member_result.all()}
|
||||||
|
|
||||||
|
# 批量获取管理人用户名
|
||||||
|
manager_ids = [getattr(t, "manager_id", None) for t in teams if getattr(t, "manager_id", None)]
|
||||||
|
manager_name_map: dict[str, str] = {}
|
||||||
|
if manager_ids:
|
||||||
|
mgr_result = await db.execute(
|
||||||
|
select(User.id, User.username).where(User.id.in_(manager_ids))
|
||||||
|
)
|
||||||
|
manager_name_map = {row[0]: row[1] for row in mgr_result.all()}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"items": [_team_out_payload(team, member_map.get(team.id, 0)) for team in teams],
|
"items": [
|
||||||
|
_team_out_payload(
|
||||||
|
team,
|
||||||
|
member_map.get(team.id, 0),
|
||||||
|
manager_name_map.get(getattr(team, "manager_id", None)),
|
||||||
|
)
|
||||||
|
for team in teams
|
||||||
|
],
|
||||||
"total": total,
|
"total": total,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user