ERP-node/frontend/lib/registry/components/v2-item-routing/hooks/useItemRouting.ts

240 lines
7.1 KiB
TypeScript

"use client";
import { useState, useCallback, useEffect, useMemo, useRef } from "react";
import { apiClient } from "@/lib/api/client";
import { ItemRoutingConfig, ItemData, RoutingVersionData, RoutingDetailData } from "../types";
import { defaultConfig } from "../config";
const API_BASE = "/process-work-standard";
export function useItemRouting(configPartial: Partial<ItemRoutingConfig>) {
const configKey = useMemo(
() => JSON.stringify(configPartial),
[configPartial]
);
const config: ItemRoutingConfig = useMemo(() => ({
...defaultConfig,
...configPartial,
dataSource: { ...defaultConfig.dataSource, ...configPartial?.dataSource },
modals: { ...defaultConfig.modals, ...configPartial?.modals },
processColumns: configPartial?.processColumns?.length
? configPartial.processColumns
: defaultConfig.processColumns,
}), [configKey]);
const configRef = useRef(config);
configRef.current = config;
const [items, setItems] = useState<ItemData[]>([]);
const [versions, setVersions] = useState<RoutingVersionData[]>([]);
const [details, setDetails] = useState<RoutingDetailData[]>([]);
const [loading, setLoading] = useState(false);
// 선택 상태
const [selectedItemCode, setSelectedItemCode] = useState<string | null>(null);
const [selectedItemName, setSelectedItemName] = useState<string | null>(null);
const [selectedVersionId, setSelectedVersionId] = useState<string | null>(null);
// 품목 목록 조회
const fetchItems = useCallback(
async (search?: string) => {
try {
setLoading(true);
const ds = configRef.current.dataSource;
const params = new URLSearchParams({
tableName: ds.itemTable,
nameColumn: ds.itemNameColumn,
codeColumn: ds.itemCodeColumn,
routingTable: ds.routingVersionTable,
routingFkColumn: ds.routingVersionFkColumn,
...(search ? { search } : {}),
});
const res = await apiClient.get(`${API_BASE}/items?${params}`);
if (res.data?.success) {
setItems(res.data.data || []);
}
} catch (err) {
console.error("품목 조회 실패", err);
} finally {
setLoading(false);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[configKey]
);
// 라우팅 버전 목록 조회
const fetchVersions = useCallback(
async (itemCode: string) => {
try {
const ds = configRef.current.dataSource;
const params = new URLSearchParams({
routingVersionTable: ds.routingVersionTable,
routingDetailTable: ds.routingDetailTable,
routingFkColumn: ds.routingVersionFkColumn,
processTable: ds.processTable,
processNameColumn: ds.processNameColumn,
processCodeColumn: ds.processCodeColumn,
});
const res = await apiClient.get(
`${API_BASE}/items/${encodeURIComponent(itemCode)}/routings?${params}`
);
if (res.data?.success) {
const routingData = res.data.data || [];
setVersions(routingData);
return routingData;
}
} catch (err) {
console.error("라우팅 버전 조회 실패", err);
}
return [];
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[configKey]
);
// 공정 상세 목록 조회 (특정 버전의 공정들)
const fetchDetails = useCallback(
async (versionId: string) => {
try {
setLoading(true);
const ds = configRef.current.dataSource;
const res = await apiClient.get("/table-data/entity-join-api/data-with-joins", {
params: {
tableName: ds.routingDetailTable,
searchConditions: JSON.stringify({
[ds.routingDetailFkColumn]: {
value: versionId,
operator: "equals",
},
}),
sortColumn: "seq_no",
sortDirection: "ASC",
},
});
if (res.data?.success) {
setDetails(res.data.data || []);
}
} catch (err) {
console.error("공정 상세 조회 실패", err);
} finally {
setLoading(false);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[configKey]
);
// 품목 선택
const selectItem = useCallback(
async (itemCode: string, itemName: string) => {
setSelectedItemCode(itemCode);
setSelectedItemName(itemName);
setSelectedVersionId(null);
setDetails([]);
const versionList = await fetchVersions(itemCode);
// 첫번째 버전 자동 선택
if (config.autoSelectFirstVersion && versionList.length > 0) {
const firstVersion = versionList[0];
setSelectedVersionId(firstVersion.id);
await fetchDetails(firstVersion.id);
}
},
[fetchVersions, fetchDetails, config.autoSelectFirstVersion]
);
// 버전 선택
const selectVersion = useCallback(
async (versionId: string) => {
setSelectedVersionId(versionId);
await fetchDetails(versionId);
},
[fetchDetails]
);
// 모달에서 데이터 변경 후 새로고침
const refreshVersions = useCallback(async () => {
if (selectedItemCode) {
const versionList = await fetchVersions(selectedItemCode);
if (selectedVersionId) {
await fetchDetails(selectedVersionId);
} else if (versionList.length > 0) {
const lastVersion = versionList[versionList.length - 1];
setSelectedVersionId(lastVersion.id);
await fetchDetails(lastVersion.id);
}
}
}, [selectedItemCode, selectedVersionId, fetchVersions, fetchDetails]);
const refreshDetails = useCallback(async () => {
if (selectedVersionId) {
await fetchDetails(selectedVersionId);
}
}, [selectedVersionId, fetchDetails]);
// 공정 삭제
const deleteDetail = useCallback(
async (detailId: string) => {
try {
const ds = configRef.current.dataSource;
const res = await apiClient.delete(
`/table-data/${ds.routingDetailTable}/${detailId}`
);
if (res.data?.success) {
await refreshDetails();
return true;
}
} catch (err) {
console.error("공정 삭제 실패", err);
}
return false;
},
[refreshDetails]
);
// 버전 삭제
const deleteVersion = useCallback(
async (versionId: string) => {
try {
const ds = configRef.current.dataSource;
const res = await apiClient.delete(
`/table-data/${ds.routingVersionTable}/${versionId}`
);
if (res.data?.success) {
if (selectedVersionId === versionId) {
setSelectedVersionId(null);
setDetails([]);
}
await refreshVersions();
return true;
}
} catch (err) {
console.error("버전 삭제 실패", err);
}
return false;
},
[selectedVersionId, refreshVersions]
);
return {
config,
items,
versions,
details,
loading,
selectedItemCode,
selectedItemName,
selectedVersionId,
fetchItems,
selectItem,
selectVersion,
refreshVersions,
refreshDetails,
deleteDetail,
deleteVersion,
};
}