91 lines
2.6 KiB
TypeScript
91 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useMemo, useState } from "react";
|
|
import { apiClient } from "@/lib/api/client";
|
|
|
|
export type CategoryLabelMap = Record<string, string>; // value_code -> value_label
|
|
|
|
export interface CategoryTarget {
|
|
table: string;
|
|
column: string;
|
|
}
|
|
|
|
/**
|
|
* 여러 (table, column) 쌍의 카테고리 값을 한 번에 조회해서
|
|
* value_code -> value_label 통합 맵을 반환한다.
|
|
*/
|
|
export function useCategoryLabelMap(targets: CategoryTarget[]): CategoryLabelMap {
|
|
const [map, setMap] = useState<CategoryLabelMap>({});
|
|
const key = useMemo(() => JSON.stringify(targets), [targets]);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
(async () => {
|
|
const merged: CategoryLabelMap = {};
|
|
for (const { table, column } of targets) {
|
|
try {
|
|
const res = await apiClient.get(
|
|
`/table-categories/${table}/${column}/values`,
|
|
);
|
|
if (res.data?.success && Array.isArray(res.data.data)) {
|
|
const flatten = (vals: any[]) => {
|
|
for (const v of vals) {
|
|
if (v.valueCode && v.valueLabel) {
|
|
merged[v.valueCode] = v.valueLabel;
|
|
}
|
|
if (v.children?.length) flatten(v.children);
|
|
}
|
|
};
|
|
flatten(res.data.data);
|
|
}
|
|
} catch {
|
|
/* skip */
|
|
}
|
|
}
|
|
if (!cancelled) setMap(merged);
|
|
})();
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [key]);
|
|
|
|
return map;
|
|
}
|
|
|
|
/**
|
|
* remark 원문을 화면 표시용 문자열로 변환하는 파서 팩토리.
|
|
* - JSON remark → 사람 읽을 수 있는 한글 (창고이동/재고조정/재고확인/공정입고)
|
|
* - value_code → codeLabelMap 에서 찾은 value_label
|
|
* - 매칭 없음 → 원문 그대로 (과거 한글 레코드 호환)
|
|
*/
|
|
export function makeParseRemark(codeLabelMap: CategoryLabelMap) {
|
|
return (remark: string | null | undefined): string => {
|
|
if (!remark) return "";
|
|
const trimmed = remark.trim();
|
|
|
|
if (trimmed.startsWith("{")) {
|
|
try {
|
|
const d = JSON.parse(trimmed);
|
|
switch (d.type) {
|
|
case "move":
|
|
return `창고이동 (${d.from_warehouse} → ${d.to_warehouse})`;
|
|
case "adjust":
|
|
return `재고조정 (${d.reason || "사유 없음"}, ${d.system_qty}→${d.actual_qty}, 차이:${d.diff >= 0 ? "+" : ""}${d.diff})`;
|
|
case "confirm":
|
|
return `재고확인 (${d.reason || "이상없음"})`;
|
|
case "process_inbound":
|
|
return "공정입고";
|
|
default:
|
|
return d.reason || d.memo || trimmed;
|
|
}
|
|
} catch {
|
|
return trimmed;
|
|
}
|
|
}
|
|
|
|
if (codeLabelMap[trimmed]) return codeLabelMap[trimmed];
|
|
return trimmed;
|
|
};
|
|
}
|