feat: Implement automatic serial number generation and reference handling in mold management

- Enhanced the `createMoldSerial` function to automatically generate serial numbers based on defined numbering rules when the serial number is not provided.
- Integrated error handling for the automatic numbering process, ensuring robust logging for success and failure cases.
- Updated the `NumberingRuleService` to support reference column handling, allowing for dynamic prefix generation based on related data.
- Modified the frontend components to accommodate new reference configurations, improving user experience in managing numbering rules.

These changes significantly enhance the mold management functionality by automating serial number generation and improving the flexibility of numbering rules.
This commit is contained in:
kjs
2026-03-09 15:34:31 +09:00
parent 2b4b7819c5
commit 4d6783e508
10 changed files with 334 additions and 51 deletions

View File

@@ -35,14 +35,16 @@ export const StatusCountComponent: React.FC<StatusCountComponentProps> = ({
setLoading(true);
try {
const res = await apiClient.get(`/table-management/data/${tableName}`, {
params: {
autoFilter: "true",
[relationColumn]: parentValue,
},
const res = await apiClient.post(`/table-management/tables/${tableName}/data`, {
page: 1,
size: 9999,
search: relationColumn ? { [relationColumn]: parentValue } : {},
});
const rows: any[] = res.data?.data || res.data?.rows || res.data || [];
const responseData = res.data?.data;
const rows: any[] = Array.isArray(responseData)
? responseData
: (responseData?.data || responseData?.rows || []);
const grouped: Record<string, number> = {};
for (const row of rows) {
@@ -69,7 +71,7 @@ export const StatusCountComponent: React.FC<StatusCountComponentProps> = ({
};
const getCount = (item: StatusCountItem) => {
if (item.value === "__TOTAL__") {
if (item.value === "__TOTAL__" || item.value === "__ALL__") {
return Object.values(counts).reduce((sum, c) => sum + c, 0);
}
const values = item.value.split(",").map((v) => v.trim());

View File

@@ -233,6 +233,47 @@ export const StatusCountConfigPanel: React.FC<StatusCountConfigPanelProps> = ({
);
};
// 상태 컬럼의 카테고리 값 로드
const [statusCategoryValues, setStatusCategoryValues] = useState<Array<{ value: string; label: string }>>([]);
const [loadingCategoryValues, setLoadingCategoryValues] = useState(false);
useEffect(() => {
if (!config.tableName || !config.statusColumn) {
setStatusCategoryValues([]);
return;
}
const loadCategoryValues = async () => {
setLoadingCategoryValues(true);
try {
const { apiClient } = await import("@/lib/api/client");
const response = await apiClient.get(
`/table-categories/${config.tableName}/${config.statusColumn}/values`
);
if (response.data?.success && response.data?.data) {
const flatValues: Array<{ value: string; label: string }> = [];
const flatten = (items: any[]) => {
for (const item of items) {
flatValues.push({
value: item.valueCode || item.value_code,
label: item.valueLabel || item.value_label,
});
if (item.children?.length > 0) flatten(item.children);
}
};
flatten(response.data.data);
setStatusCategoryValues(flatValues);
}
} catch {
setStatusCategoryValues([]);
} finally {
setLoadingCategoryValues(false);
}
};
loadCategoryValues();
}, [config.tableName, config.statusColumn]);
const tableComboItems = tables.map((t) => ({
value: t.tableName,
label: t.displayName,
@@ -370,15 +411,52 @@ export const StatusCountConfigPanel: React.FC<StatusCountConfigPanelProps> = ({
</Button>
</div>
{loadingCategoryValues && (
<div className="flex items-center gap-1 text-xs text-muted-foreground">
<Loader2 className="h-3 w-3 animate-spin" /> ...
</div>
)}
{items.map((item: StatusCountItem, i: number) => (
<div key={i} className="space-y-1 rounded-md border p-2">
<div className="flex items-center gap-1">
<Input
value={item.value}
onChange={(e) => handleItemChange(i, "value", e.target.value)}
placeholder="상태값 (예: IN_USE)"
className="h-7 text-xs"
/>
{statusCategoryValues.length > 0 ? (
<Select
value={item.value || ""}
onValueChange={(v) => {
handleItemChange(i, "value", v);
if (v === "__ALL__" && !item.label) {
handleItemChange(i, "label", "전체");
} else {
const catVal = statusCategoryValues.find((cv) => cv.value === v);
if (catVal && !item.label) {
handleItemChange(i, "label", catVal.label);
}
}
}}
>
<SelectTrigger className="h-7 flex-1 text-xs">
<SelectValue placeholder="카테고리 값 선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="__ALL__" className="text-xs font-medium">
</SelectItem>
{statusCategoryValues.map((cv) => (
<SelectItem key={cv.value} value={cv.value} className="text-xs">
{cv.label} ({cv.value})
</SelectItem>
))}
</SelectContent>
</Select>
) : (
<Input
value={item.value}
onChange={(e) => handleItemChange(i, "value", e.target.value)}
placeholder="상태값 (예: IN_USE)"
className="h-7 text-xs"
/>
)}
<Button
variant="ghost"
size="sm"
@@ -418,6 +496,12 @@ export const StatusCountConfigPanel: React.FC<StatusCountConfigPanelProps> = ({
</div>
</div>
))}
{!loadingCategoryValues && statusCategoryValues.length === 0 && config.tableName && config.statusColumn && (
<p className="text-[10px] text-amber-600">
. &gt; .
</p>
)}
</div>
</div>
);