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:
@@ -23,7 +23,12 @@ export async function getList(req: AuthenticatedRequest, res: Response) {
|
||||
try {
|
||||
await ensureDetailRoutingColumn();
|
||||
const companyCode = req.user!.companyCode;
|
||||
const { dateFrom, dateTo, status, progressStatus, keyword } = req.query;
|
||||
const { dateFrom, dateTo, status, progressStatus, keyword, page, pageSize } = req.query;
|
||||
|
||||
// 페이지네이션 파라미터 파싱 (page 없으면 전체 반환 — 하위호환)
|
||||
const pageNum = page ? Math.max(1, parseInt(page as string, 10) || 1) : null;
|
||||
const sizeNum = pageSize ? Math.max(1, Math.min(1000, parseInt(pageSize as string, 10) || 20)) : null;
|
||||
const paginated = pageNum !== null && sizeNum !== null;
|
||||
|
||||
const conditions: string[] = [];
|
||||
const params: any[] = [];
|
||||
@@ -54,14 +59,110 @@ export async function getList(req: AuthenticatedRequest, res: Response) {
|
||||
params.push(progressStatus);
|
||||
idx++;
|
||||
}
|
||||
// keyword 검색: wi 자체 필드 + detail.item_number 존재 여부로 EXISTS
|
||||
if (keyword) {
|
||||
conditions.push(`(wi.work_instruction_no ILIKE $${idx} OR wi.worker ILIKE $${idx} OR COALESCE(itm.item_name,'') ILIKE $${idx} OR COALESCE(d.item_number,'') ILIKE $${idx})`);
|
||||
conditions.push(`(
|
||||
wi.work_instruction_no ILIKE $${idx}
|
||||
OR wi.worker ILIKE $${idx}
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM work_instruction_detail dd
|
||||
LEFT JOIN item_info ii ON ii.item_number = dd.item_number AND ii.company_code = wi.company_code
|
||||
WHERE dd.work_instruction_id = wi.id
|
||||
AND (dd.item_number ILIKE $${idx} OR COALESCE(ii.item_name,'') ILIKE $${idx})
|
||||
)
|
||||
)`);
|
||||
params.push(`%${keyword}%`);
|
||||
idx++;
|
||||
}
|
||||
|
||||
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
||||
|
||||
const pool = getPool();
|
||||
|
||||
// 페이지네이션 모드: WI 단위로 페이지 잘라낸 뒤 detail과 JOIN
|
||||
if (paginated) {
|
||||
// 1) 총 WI 개수 카운트
|
||||
const countSql = `
|
||||
SELECT COUNT(*)::int AS cnt
|
||||
FROM work_instruction wi
|
||||
${whereClause}
|
||||
`;
|
||||
const countRes = await pool.query(countSql, params);
|
||||
const totalCount = countRes.rows[0]?.cnt ?? 0;
|
||||
|
||||
// 2) 현재 페이지 WI id 목록
|
||||
const offset = (pageNum! - 1) * sizeNum!;
|
||||
const pageSql = `
|
||||
SELECT wi.id
|
||||
FROM work_instruction wi
|
||||
${whereClause}
|
||||
ORDER BY wi.created_date DESC, wi.id DESC
|
||||
LIMIT ${sizeNum} OFFSET ${offset}
|
||||
`;
|
||||
const pageRes = await pool.query(pageSql, params);
|
||||
const wiIds = pageRes.rows.map((r) => r.id);
|
||||
|
||||
if (wiIds.length === 0) {
|
||||
return res.json({ success: true, data: [], totalCount, page: pageNum, pageSize: sizeNum });
|
||||
}
|
||||
|
||||
// 3) 해당 WI들의 detail + 품목/설비/라우팅 JOIN
|
||||
const dataSql = `
|
||||
SELECT
|
||||
wi.id AS wi_id,
|
||||
wi.work_instruction_no,
|
||||
wi.status,
|
||||
wi.progress_status,
|
||||
wi.qty AS total_qty,
|
||||
wi.completed_qty,
|
||||
wi.start_date,
|
||||
wi.end_date,
|
||||
wi.equipment_id,
|
||||
wi.work_team,
|
||||
wi.worker,
|
||||
wi.remark AS wi_remark,
|
||||
wi.created_date,
|
||||
d.id AS detail_id,
|
||||
d.item_number,
|
||||
d.qty AS detail_qty,
|
||||
d.remark AS detail_remark,
|
||||
d.part_code,
|
||||
d.source_table,
|
||||
d.source_id,
|
||||
d.routing_version_id AS detail_routing_version_id,
|
||||
COALESCE(itm.item_name, '') AS item_name,
|
||||
COALESCE(itm.type, '') AS item_type,
|
||||
COALESCE(itm.size, '') AS item_spec,
|
||||
COALESCE(e.equipment_name, '') AS equipment_name,
|
||||
COALESCE(e.equipment_code, '') AS equipment_code,
|
||||
wi.routing AS routing_version_id,
|
||||
COALESCE(rv.version_name, '') AS routing_name,
|
||||
ROW_NUMBER() OVER (PARTITION BY wi.work_instruction_no ORDER BY d.created_date) AS detail_seq,
|
||||
COUNT(*) OVER (PARTITION BY wi.work_instruction_no) AS detail_count
|
||||
FROM work_instruction wi
|
||||
INNER JOIN work_instruction_detail d
|
||||
ON d.work_instruction_id = wi.id
|
||||
LEFT JOIN item_info itm
|
||||
ON itm.item_number = d.item_number AND itm.company_code = wi.company_code
|
||||
LEFT JOIN equipment_mng e
|
||||
ON wi.equipment_id = e.id AND wi.company_code = e.company_code
|
||||
LEFT JOIN item_routing_version rv
|
||||
ON wi.routing = rv.id AND rv.company_code = wi.company_code
|
||||
WHERE wi.id = ANY($1::varchar[])
|
||||
ORDER BY wi.created_date DESC, wi.id DESC, d.created_date ASC
|
||||
`;
|
||||
const dataRes = await pool.query(dataSql, [wiIds]);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: dataRes.rows,
|
||||
totalCount,
|
||||
page: pageNum,
|
||||
pageSize: sizeNum,
|
||||
});
|
||||
}
|
||||
|
||||
// 비페이지 모드 (하위호환): 기존 방식 유지, LATERAL만 LEFT JOIN으로 교체
|
||||
const query = `
|
||||
SELECT
|
||||
wi.id AS wi_id,
|
||||
@@ -97,17 +198,14 @@ export async function getList(req: AuthenticatedRequest, res: Response) {
|
||||
FROM work_instruction wi
|
||||
INNER JOIN work_instruction_detail d
|
||||
ON d.work_instruction_id = wi.id
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT item_name, size, type FROM item_info
|
||||
WHERE item_number = d.item_number AND company_code = wi.company_code LIMIT 1
|
||||
) itm ON true
|
||||
LEFT JOIN item_info itm
|
||||
ON itm.item_number = d.item_number AND itm.company_code = wi.company_code
|
||||
LEFT JOIN equipment_mng e ON wi.equipment_id = e.id AND wi.company_code = e.company_code
|
||||
LEFT JOIN item_routing_version rv ON wi.routing = rv.id AND rv.company_code = wi.company_code
|
||||
${whereClause}
|
||||
ORDER BY wi.created_date DESC, d.created_date ASC
|
||||
`;
|
||||
|
||||
const pool = getPool();
|
||||
const result = await pool.query(query, params);
|
||||
return res.json({ success: true, data: result.rows });
|
||||
} catch (error: any) {
|
||||
|
||||
Reference in New Issue
Block a user