diff --git a/frontend/src/pages/Deploy/Team/List/components/MemberManageDialog.tsx b/frontend/src/pages/Deploy/Team/List/components/MemberManageDialog.tsx index 7d7fe43a..b2b5f30b 100644 --- a/frontend/src/pages/Deploy/Team/List/components/MemberManageDialog.tsx +++ b/frontend/src/pages/Deploy/Team/List/components/MemberManageDialog.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useMemo, useRef } from 'react'; import { Dialog, DialogContent, @@ -8,14 +8,7 @@ import { import { ConfirmDialog } from '@/components/ui/confirm-dialog'; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; +import { PaginatedTable, type ColumnDef, type SearchFieldDef, type PaginatedTableRef } from '@/components/ui/paginated-table'; import { Command, CommandEmpty, @@ -31,13 +24,10 @@ import { import { Checkbox } from "@/components/ui/checkbox"; import { Badge } from "@/components/ui/badge"; import { useToast } from "@/components/ui/use-toast"; -import { DataTablePagination } from '@/components/ui/pagination'; -import { DEFAULT_PAGE_SIZE, DEFAULT_PAGE_NUM } from '@/utils/page'; import { Plus, Edit, Trash2, - Search, Loader2, Users, Check, @@ -53,7 +43,6 @@ import type { TeamMemberResponse, TeamMemberQuery } from '../../Member/types'; -import type { Page } from '@/types/base'; import type { UserResponse } from '@/pages/System/User/List/types'; interface MemberManageDialogProps { @@ -79,9 +68,8 @@ const MemberManageDialog: React.FC = ({ onSuccess }) => { const { toast } = useToast(); - const [loading, setLoading] = useState(false); - const [data, setData] = useState | null>(null); - const [searchText, setSearchText] = useState(''); + const tableRef = useRef>(null); + const [memberData, setMemberData] = useState([]); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [deleteRecord, setDeleteRecord] = useState(null); const [selectedUserIds, setSelectedUserIds] = useState([]); @@ -90,48 +78,16 @@ const MemberManageDialog: React.FC = ({ const [editDialogOpen, setEditDialogOpen] = useState(false); const [editRecord, setEditRecord] = useState(null); const [editRole, setEditRole] = useState(''); - - // 分页状态 - const [pageNum, setPageNum] = useState(DEFAULT_PAGE_NUM); - const [pageSize] = useState(DEFAULT_PAGE_SIZE); - - // 加载成员列表 - const loadMembers = async () => { - if (!teamId) return; - - setLoading(true); - try { - const query: TeamMemberQuery = { - teamId: teamId, - userName: searchText || undefined, - pageNum, - pageSize, - }; - const result = await getTeamMembers(query); - setData(result); - } catch (error) { - console.error('加载成员失败:', error); - toast({ - variant: "destructive", - title: "加载失败", - description: error instanceof Error ? error.message : '未知错误', - }); - } finally { - setLoading(false); - } - }; - - useEffect(() => { - if (open) { - loadMembers(); - } - }, [open, pageNum, pageSize]); - - // 搜索 - const handleSearch = () => { - setPageNum(0); - loadMembers(); + // 包装 fetchFn + const fetchData = async (query: TeamMemberQuery) => { + const result = await getTeamMembers({ + ...query, + teamId: teamId, + userName: searchUserName || undefined, + }); + setMemberData(result.content || []); + return result; }; // 切换用户选择 @@ -176,7 +132,7 @@ const MemberManageDialog: React.FC = ({ setSelectedUserIds([]); setPopoverOpen(false); - loadMembers(); + tableRef.current?.refresh(); onSuccess?.(); } catch (error) { console.error('批量添加失败:', error); @@ -215,7 +171,7 @@ const MemberManageDialog: React.FC = ({ setEditDialogOpen(false); setEditRecord(null); setEditRole(''); - loadMembers(); + tableRef.current?.refresh(); onSuccess?.(); } catch (error) { console.error('更新失败:', error); @@ -241,9 +197,46 @@ const MemberManageDialog: React.FC = ({ // 过滤出未加入的用户(排除负责人和已加入的成员) const availableUsers = users.filter(user => - user.id !== ownerId && !data?.content?.some(member => member.userId === user.id) + user.id !== ownerId && !memberData.some(member => member.userId === user.id) ); + // 搜索状态 + const [searchUserName, setSearchUserName] = useState(''); + + // 列定义 + const columns: ColumnDef[] = useMemo(() => [ + { key: 'userId', title: '用户ID', dataIndex: 'userId', width: '100px' }, + { key: 'userName', title: '用户名', dataIndex: 'userName', width: '150px' }, + { key: 'roleInTeam', title: '团队角色', dataIndex: 'roleInTeam', width: '150px' }, + { key: 'joinTime', title: '加入时间', dataIndex: 'joinTime', width: '180px' }, + { + key: 'actions', + title: '操作', + width: '120px', + sticky: true, + render: (_, record) => ( +
+ + +
+ ), + }, + ], []); + return ( <> @@ -259,17 +252,19 @@ const MemberManageDialog: React.FC = ({
{/* 操作栏 */}
-
- - setSearchText(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && handleSearch()} - className="pl-10" - /> -
- + {/* 搜索框 */} + setSearchUserName(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + tableRef.current?.refresh(); + } + }} + className="flex-1" + /> + {/* 多选下拉框 */} @@ -277,7 +272,7 @@ const MemberManageDialog: React.FC = ({ variant="outline" role="combobox" aria-expanded={popoverOpen} - className="w-[280px] justify-between" + className="w-[200px] justify-between" disabled={availableUsers.length === 0} > {selectedUserIds.length > 0 ? ( @@ -340,89 +335,14 @@ const MemberManageDialog: React.FC = ({ {/* 表格 */}
-
- - - - 用户ID - 用户名 - 团队角色 - 加入时间 - 操作 - - - - {loading ? ( - - -
- - 加载中... -
-
-
- ) : data?.content && data.content.length > 0 ? ( - data.content.map((record) => ( - - - {record.userId} - - - {record.userName || '-'} - - - {record.roleInTeam || '-'} - - - {record.joinTime || '-'} - - -
- - -
-
-
- )) - ) : ( - - -
- -

暂无成员

-
-
-
- )} -
-
-
- - {/* 分页 */} - {data && data.totalElements > 0 && ( -
- setPageNum(newPage)} - /> -
- )} + + ref={tableRef} + fetchFn={fetchData} + columns={columns} + rowKey="id" + minWidth="680px" + pageSize={10} + />
@@ -474,7 +394,7 @@ const MemberManageDialog: React.FC = ({ description: `成员 "${deleteRecord?.userName}" 已移除`, }); setDeleteRecord(null); - loadMembers(); + tableRef.current?.refresh(); onSuccess?.(); }} variant="destructive"