feat: update shipping-plan page and FieldDetailSettingsModal
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
48af85c713
commit
e67e43cd7d
|
|
@ -315,15 +315,15 @@ export default function ShippingPlanPage() {
|
|||
onCheckedChange={handleCheckAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead className="w-[160px]">수주번호</TableHead>
|
||||
<TableHead className="w-[100px] text-center">납기일</TableHead>
|
||||
<TableHead className="w-[120px]">거래처</TableHead>
|
||||
<TableHead className="w-[100px]">품목코드</TableHead>
|
||||
<TableHead>품목명</TableHead>
|
||||
<TableHead className="w-[80px] text-right">수주수량</TableHead>
|
||||
<TableHead className="w-[80px] text-right">계획수량</TableHead>
|
||||
<TableHead className="w-[100px] text-center">출하계획일</TableHead>
|
||||
<TableHead className="w-[80px] text-center">상태</TableHead>
|
||||
<TableHead className="w-[10%]">수주번호</TableHead>
|
||||
<TableHead className="w-[8%] text-center">납기일</TableHead>
|
||||
<TableHead className="w-[12%]">거래처</TableHead>
|
||||
<TableHead className="w-[20%]">품목코드</TableHead>
|
||||
<TableHead className="w-[20%]">품목명</TableHead>
|
||||
<TableHead className="w-[7%] text-right">수주수량</TableHead>
|
||||
<TableHead className="w-[7%] text-right">계획수량</TableHead>
|
||||
<TableHead className="w-[8%] text-center">출하계획일</TableHead>
|
||||
<TableHead className="w-[6%] text-center">상태</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
|
|
|
|||
|
|
@ -109,6 +109,11 @@ export function FieldDetailSettingsModal({
|
|||
const [cascadingRelationOpen, setCascadingRelationOpen] = useState(false);
|
||||
const [parentFieldOpen, setParentFieldOpen] = useState(false);
|
||||
|
||||
// 기본 선택값용 옵션 목록 상태
|
||||
const [defaultValueCategoryValues, setDefaultValueCategoryValues] = useState<{value: string; label: string}[]>([]);
|
||||
const [defaultValueTableOptions, setDefaultValueTableOptions] = useState<{value: string; label: string}[]>([]);
|
||||
const [loadingDefaultValueOptions, setLoadingDefaultValueOptions] = useState(false);
|
||||
|
||||
// Combobox 열림 상태
|
||||
const [sourceTableOpen, setSourceTableOpen] = useState(false);
|
||||
const [targetColumnOpenMap, setTargetColumnOpenMap] = useState<Record<number, boolean>>({});
|
||||
|
|
@ -209,6 +214,69 @@ export function FieldDetailSettingsModal({
|
|||
loadCascadingRelations();
|
||||
}, [open]);
|
||||
|
||||
// 기본 선택값용: code 타입 카테고리 값 로드
|
||||
useEffect(() => {
|
||||
const loadCategoryValues = async () => {
|
||||
const categoryKey = localField.selectOptions?.categoryKey;
|
||||
if (!open || localField.selectOptions?.type !== "code" || !categoryKey) {
|
||||
setDefaultValueCategoryValues([]);
|
||||
return;
|
||||
}
|
||||
setLoadingDefaultValueOptions(true);
|
||||
try {
|
||||
const [tableName, columnName] = categoryKey.split(".");
|
||||
const response = await apiClient.get(`/table-categories/${tableName}/${columnName}/values`);
|
||||
if (response.data?.success && response.data?.data) {
|
||||
setDefaultValueCategoryValues(
|
||||
response.data.data.map((item: any) => ({
|
||||
value: item.valueCode || item.value_code,
|
||||
label: item.valueLabel || item.value_label,
|
||||
}))
|
||||
);
|
||||
} else {
|
||||
setDefaultValueCategoryValues([]);
|
||||
}
|
||||
} catch {
|
||||
setDefaultValueCategoryValues([]);
|
||||
} finally {
|
||||
setLoadingDefaultValueOptions(false);
|
||||
}
|
||||
};
|
||||
loadCategoryValues();
|
||||
}, [open, localField.selectOptions?.type, localField.selectOptions?.categoryKey]);
|
||||
|
||||
// 기본 선택값용: table 타입 옵션 로드
|
||||
useEffect(() => {
|
||||
const loadTableOptions = async () => {
|
||||
const opts = localField.selectOptions;
|
||||
if (!open || opts?.type !== "table" || !opts?.tableName || !opts?.valueColumn || !opts?.labelColumn) {
|
||||
setDefaultValueTableOptions([]);
|
||||
return;
|
||||
}
|
||||
setLoadingDefaultValueOptions(true);
|
||||
try {
|
||||
const response = await apiClient.post(`/table-management/tables/${opts.tableName}/data`, {
|
||||
page: 1,
|
||||
size: 200,
|
||||
autoFilter: { enabled: true, filterColumn: "company_code" },
|
||||
});
|
||||
const dataArray = response.data?.data?.data || response.data?.data || [];
|
||||
setDefaultValueTableOptions(
|
||||
dataArray.map((row: any) => ({
|
||||
value: String(row[opts.valueColumn!] || ""),
|
||||
label: String(row[opts.labelColumn!] || ""),
|
||||
}))
|
||||
);
|
||||
} catch {
|
||||
setDefaultValueTableOptions([]);
|
||||
} finally {
|
||||
setLoadingDefaultValueOptions(false);
|
||||
}
|
||||
};
|
||||
loadTableOptions();
|
||||
}, [open, localField.selectOptions?.type, localField.selectOptions?.tableName,
|
||||
localField.selectOptions?.valueColumn, localField.selectOptions?.labelColumn]);
|
||||
|
||||
// 관계 코드 선택 시 상세 설정 자동 채움
|
||||
const handleRelationCodeSelect = async (relationCode: string) => {
|
||||
if (!relationCode) return;
|
||||
|
|
@ -1181,6 +1249,80 @@ export function FieldDetailSettingsModal({
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 기본 선택값 설정 (cascading 제외) */}
|
||||
{(() => {
|
||||
const effectiveType = localField.selectOptions?.type || "static";
|
||||
if (effectiveType === "cascading") return null;
|
||||
return (
|
||||
<div className="border-t pt-3 mt-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-[10px] font-medium">기본 선택값</span>
|
||||
{/* static 타입 */}
|
||||
{effectiveType === "static" && (localField.selectOptions?.staticOptions?.length || 0) > 0 && (
|
||||
<Select
|
||||
value={localField.defaultValue || "_none_"}
|
||||
onValueChange={(value) => updateField({ defaultValue: value === "_none_" ? "" : value })}
|
||||
>
|
||||
<SelectTrigger className="h-7 w-[180px] text-xs">
|
||||
<SelectValue placeholder="선택 안함" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="_none_">선택 안함</SelectItem>
|
||||
{(localField.selectOptions?.staticOptions || []).map((opt, idx) => (
|
||||
<SelectItem key={`default-${idx}`} value={opt.value}>
|
||||
{opt.label || opt.value}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
{/* code 타입 */}
|
||||
{effectiveType === "code" && defaultValueCategoryValues.length > 0 && (
|
||||
<Select
|
||||
value={localField.defaultValue || "_none_"}
|
||||
onValueChange={(value) => updateField({ defaultValue: value === "_none_" ? "" : value })}
|
||||
>
|
||||
<SelectTrigger className="h-7 w-[180px] text-xs">
|
||||
<SelectValue placeholder="선택 안함" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="_none_">선택 안함</SelectItem>
|
||||
{defaultValueCategoryValues.map((cv) => (
|
||||
<SelectItem key={cv.value} value={cv.value}>
|
||||
{cv.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
{/* table 타입 */}
|
||||
{effectiveType === "table" && defaultValueTableOptions.length > 0 && (
|
||||
<Select
|
||||
value={localField.defaultValue || "_none_"}
|
||||
onValueChange={(value) => updateField({ defaultValue: value === "_none_" ? "" : value })}
|
||||
>
|
||||
<SelectTrigger className="h-7 w-[180px] text-xs">
|
||||
<SelectValue placeholder="선택 안함" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="_none_">선택 안함</SelectItem>
|
||||
{defaultValueTableOptions.map((opt, idx) => (
|
||||
<SelectItem key={`default-table-${idx}`} value={opt.value}>
|
||||
{opt.label} ({opt.value})
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
{loadingDefaultValueOptions && (
|
||||
<span className="text-[9px] text-muted-foreground">로딩 중...</span>
|
||||
)}
|
||||
</div>
|
||||
<HelpText>폼이 열릴 때 자동으로 선택될 기본값을 설정합니다</HelpText>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Reference in New Issue