feat: Implement pagination and enhanced keyword search in work instruction retrieval

- Added pagination support to the `getList` function in the work instruction controller, allowing for efficient data retrieval with `page` and `pageSize` parameters.
- Enhanced the keyword search functionality to include checks for item numbers in the work instruction details, improving search accuracy.
- Updated the frontend components to utilize the new `SmartSelect` component for supplier and partner selection, enhancing user experience.
- Adjusted the `EDataTable` component to support server-side pagination, ensuring better performance with large datasets.
This commit is contained in:
kjs
2026-04-20 14:51:32 +09:00
parent 377e3e51e8
commit 68bc857eae
19 changed files with 260 additions and 158 deletions

View File

@@ -83,6 +83,15 @@ export interface EDataTableProps<T extends Record<string, any> = any> {
showPagination?: boolean;
defaultPageSize?: number;
// ─── 서버사이드 페이지네이션 모드 ───
// serverPagination=true 일 때: 내부 slice/filter/sort 미사용, data는 이미 해당 페이지 분량
serverPagination?: boolean;
serverCurrentPage?: number;
serverPageSize?: number;
serverTotalCount?: number;
onServerPageChange?: (page: number) => void;
onServerPageSizeChange?: (size: number) => void;
className?: string;
}
@@ -275,6 +284,12 @@ export function EDataTable<T extends Record<string, any> = any>({
showRowNumber = false,
showPagination = true,
defaultPageSize = 50,
serverPagination = false,
serverCurrentPage,
serverPageSize,
serverTotalCount,
onServerPageChange,
onServerPageSizeChange,
className,
}: EDataTableProps<T>) {
const [columns, setColumns] = useState(initialColumns);
@@ -287,10 +302,21 @@ export function EDataTable<T extends Record<string, any> = any>({
// 헤더 필터
const [headerFilters, setHeaderFilters] = useState<Record<string, Set<string>>>({});
// 페이지네이션
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(defaultPageSize);
const [pageSizeInput, setPageSizeInput] = useState(String(defaultPageSize));
// 페이지네이션 — 서버사이드 모드면 외부 state 사용
const [internalCurrentPage, setInternalCurrentPage] = useState(1);
const [internalPageSize, setInternalPageSize] = useState(defaultPageSize);
const currentPage = serverPagination ? (serverCurrentPage ?? 1) : internalCurrentPage;
const pageSize = serverPagination ? (serverPageSize ?? defaultPageSize) : internalPageSize;
const setCurrentPage = (next: number | ((prev: number) => number)) => {
const resolved = typeof next === "function" ? (next as (p: number) => number)(currentPage) : next;
if (serverPagination) onServerPageChange?.(resolved);
else setInternalCurrentPage(resolved);
};
const setPageSize = (n: number) => {
if (serverPagination) onServerPageSizeChange?.(n);
else setInternalPageSize(n);
};
const [pageSizeInput, setPageSizeInput] = useState(String(serverPagination ? (serverPageSize ?? defaultPageSize) : defaultPageSize));
// 그룹 접기/펼치기
const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(new Set());
@@ -394,8 +420,9 @@ export function EDataTable<T extends Record<string, any> = any>({
});
};
// 필터 + 정렬
// 필터 + 정렬 (서버사이드 모드면 원본 data 그대로 사용)
const processedData = useMemo(() => {
if (serverPagination) return data;
let result = [...data];
// 헤더 필터
@@ -425,24 +452,28 @@ export function EDataTable<T extends Record<string, any> = any>({
}
return result;
}, [data, headerFilters, sortState, onSortChange]);
}, [data, headerFilters, sortState, onSortChange, serverPagination]);
// 필터/데이터 건수 변경 시 1페이지 리셋 (참조만 바뀐 경우는 리셋 안 함)
useEffect(() => { setCurrentPage(1); }, [data.length, headerFilters]);
// 필터/데이터 건수 변경 시 1페이지 리셋 (서버사이드에선 외부가 제어)
useEffect(() => {
if (!serverPagination) setCurrentPage(1);
}, [data.length, headerFilters, serverPagination]);
// 페이지네이션
const totalItems = processedData.length;
const totalItems = serverPagination ? (serverTotalCount ?? data.length) : processedData.length;
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
const safePage = Math.min(currentPage, totalPages);
useEffect(() => {
if (currentPage > totalPages) setCurrentPage(totalPages);
}, [currentPage, totalPages]);
if (!serverPagination && currentPage > totalPages) setCurrentPage(totalPages);
}, [currentPage, totalPages, serverPagination]);
const pageOffset = (safePage - 1) * pageSize;
const paginatedDataRaw = showPagination
? processedData.slice(pageOffset, pageOffset + pageSize)
: processedData;
const paginatedDataRaw = serverPagination
? processedData
: showPagination
? processedData.slice(pageOffset, pageOffset + pageSize)
: processedData;
// 접힌 그룹의 데이터 행 숨김
const paginatedData = useMemo(() => {