거래처별 품목정보 검색바 및 카테고박스 추가

This commit is contained in:
SeongHyun Kim 2025-11-14 16:49:49 +09:00
parent 361cb56a1d
commit 4fa57d67d6
4 changed files with 209 additions and 58 deletions

View File

@ -103,42 +103,48 @@ export const CustomerItemMappingComponent: React.FC<CustomerItemMappingComponent
<div className="w-full border-border bg-muted flex h-12 flex-shrink-0 items-center justify-between border-b px-4 sm:h-14 sm:px-6">
<h3 className="text-sm font-semibold sm:text-base">
- {finalConfig.selectedTable || "[테이블 선택]"}
{finalConfig.showCompanyName && finalConfig.companyNameColumn && (
<span className="text-muted-foreground ml-2 text-xs font-normal sm:text-sm">
| {finalConfig.companyNameColumn}
</span>
)}
</h3>
<button className="hover:bg-muted-foreground/10 rounded p-1">
<X className="h-4 w-4 sm:h-5 sm:w-5" />
</button>
</div>
{/* 검색/카테고리 영역 - 회색 배경 */}
{/* 검색/카테고리 영역 */}
{finalConfig.showSearchArea && (
<div
className="w-full border-border bg-muted flex-shrink-0 border-b"
style={{ height: finalConfig.searchAreaHeight || 80 }}
>
<div className="flex h-full w-full items-center justify-center p-4">
<div className="text-muted-foreground flex flex-col items-center gap-2 text-center">
<div className="bg-background/50 rounded-full p-3">
<svg
className="h-5 w-5 sm:h-6 sm:w-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
<div className="w-full border-border bg-background flex-shrink-0 border-b p-3 sm:p-4">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:gap-4">
{/* 검색 입력 */}
<div className="flex-1">
<div className="relative">
<input
type="text"
placeholder={finalConfig.searchPlaceholder || "품목코드, 품목명, 규격 검색"}
className="border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring h-9 w-full rounded-md border px-3 py-1 text-xs focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 sm:h-10 sm:text-sm"
disabled={isDesignMode}
/>
</div>
<p className="text-xs font-medium sm:text-sm">
</p>
<p className="text-[10px] text-muted-foreground/70 sm:text-xs">
</p>
</div>
{/* 카테고리 필터 */}
{finalConfig.enableCategoryFilter && (
<div className="w-full sm:w-auto sm:min-w-[160px]">
<select
className="border-input bg-background ring-offset-background focus-visible:ring-ring h-9 w-full rounded-md border px-3 py-1 text-xs focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 sm:h-10 sm:text-sm"
disabled={isDesignMode}
>
{(finalConfig.categories || ["전체"]).map((category, idx) => (
<option key={idx} value={category}>
{category}
</option>
))}
</select>
</div>
)}
</div>
</div>
)}

View File

@ -19,11 +19,33 @@ import { Plus, X } from "lucide-react";
export interface CustomerItemMappingConfigPanelProps {
config: CustomerItemMappingConfig;
onChange: (config: CustomerItemMappingConfig) => void;
onConfigChange?: (config: CustomerItemMappingConfig) => void;
screenTableName?: string;
tableColumns?: any[];
tables?: any[];
allTables?: any[];
onTableChange?: (tableName: string) => void;
menuObjid?: number;
}
export const CustomerItemMappingConfigPanel: React.FC<
CustomerItemMappingConfigPanelProps
> = ({ config, onChange }) => {
> = ({
config,
onChange,
onConfigChange,
screenTableName,
tableColumns: propTableColumns,
tables: propTables,
allTables,
onTableChange: propOnTableChange,
menuObjid,
}) => {
// onChange와 onConfigChange를 통합
const handleChange = (newConfig: CustomerItemMappingConfig) => {
onChange?.(newConfig);
onConfigChange?.(newConfig);
};
const [tables, setTables] = useState<any[]>([]);
const [availableColumns, setAvailableColumns] = useState<any[]>([]);
@ -56,16 +78,18 @@ export const CustomerItemMappingConfigPanel: React.FC<
}, [config.selectedTable]);
const handleTableChange = (tableName: string) => {
onChange({
const newConfig = {
...config,
selectedTable: tableName,
columns: [], // 테이블 변경 시 컬럼 초기화
});
};
handleChange(newConfig);
propOnTableChange?.(tableName);
};
const handleAddColumn = (columnName: string) => {
if (!config.columns.includes(columnName)) {
onChange({
handleChange({
...config,
columns: [...config.columns, columnName],
});
@ -73,7 +97,7 @@ export const CustomerItemMappingConfigPanel: React.FC<
};
const handleRemoveColumn = (columnName: string) => {
onChange({
handleChange({
...config,
columns: config.columns.filter((col) => col !== columnName),
});
@ -152,7 +176,7 @@ export const CustomerItemMappingConfigPanel: React.FC<
<Checkbox
checked={config.checkbox?.enabled !== false}
onCheckedChange={(checked) =>
onChange({
handleChange({
...config,
checkbox: {
...config.checkbox,
@ -168,7 +192,7 @@ export const CustomerItemMappingConfigPanel: React.FC<
<Checkbox
checked={config.checkbox?.selectAll !== false}
onCheckedChange={(checked) =>
onChange({
handleChange({
...config,
checkbox: {
...config.checkbox,
@ -184,7 +208,7 @@ export const CustomerItemMappingConfigPanel: React.FC<
<Checkbox
checked={config.checkbox?.multiple !== false}
onCheckedChange={(checked) =>
onChange({
handleChange({
...config,
checkbox: {
...config.checkbox,
@ -198,6 +222,52 @@ export const CustomerItemMappingConfigPanel: React.FC<
</div>
</div>
{/* 헤더 설정 */}
<div className="space-y-3">
<Label> </Label>
<label className="flex items-center gap-2">
<Checkbox
checked={config.showCompanyName === true}
onCheckedChange={(checked) =>
handleChange({
...config,
showCompanyName: checked as boolean,
})
}
/>
<span className="text-sm font-medium"> </span>
</label>
{config.showCompanyName && availableColumns.length > 0 && (
<div className="space-y-2 pl-6">
<Label className="text-xs"> </Label>
<Select
value={config.companyNameColumn || ""}
onValueChange={(value) =>
handleChange({
...config,
companyNameColumn: value,
})
}
>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="컬럼 선택" />
</SelectTrigger>
<SelectContent>
{availableColumns.map((col) => (
<SelectItem key={col.columnName} value={col.columnName} className="text-xs">
{col.displayName || col.columnName}
</SelectItem>
))}
</SelectContent>
</Select>
<p className="text-muted-foreground text-[10px]">
</p>
</div>
)}
</div>
{/* 검색 영역 설정 */}
<div className="space-y-3">
<Label>/ </Label>
@ -206,7 +276,7 @@ export const CustomerItemMappingConfigPanel: React.FC<
<Checkbox
checked={config.showSearchArea === true}
onCheckedChange={(checked) =>
onChange({
handleChange({
...config,
showSearchArea: checked as boolean,
})
@ -218,24 +288,83 @@ export const CustomerItemMappingConfigPanel: React.FC<
</label>
{config.showSearchArea && (
<div className="space-y-2 pl-6">
<Label className="text-xs"> (px)</Label>
<Input
type="number"
value={config.searchAreaHeight || 80}
onChange={(e) =>
onChange({
...config,
searchAreaHeight: parseInt(e.target.value) || 80,
})
}
min={60}
max={200}
className="h-8 text-xs"
/>
<p className="text-muted-foreground text-[10px]">
권장: 80-120px ( )
</p>
<div className="space-y-3 pl-6">
<div className="space-y-2">
<Label className="text-xs"> </Label>
<Input
value={config.searchPlaceholder || ""}
onChange={(e) =>
handleChange({
...config,
searchPlaceholder: e.target.value,
})
}
placeholder="품목코드, 품목명, 규격 검색"
className="h-8 text-xs"
/>
</div>
{/* 카테고리 필터 설정 */}
<div className="space-y-2">
<label className="flex items-center gap-2">
<Checkbox
checked={config.enableCategoryFilter === true}
onCheckedChange={(checked) =>
handleChange({
...config,
enableCategoryFilter: checked as boolean,
})
}
/>
<span className="text-xs font-medium"> </span>
</label>
{config.enableCategoryFilter && (
<div className="space-y-2 pl-6">
<Label className="text-xs"> ( )</Label>
<Input
value={(config.categories || []).join(", ")}
onChange={(e) =>
handleChange({
...config,
categories: e.target.value.split(",").map((c) => c.trim()).filter(Boolean),
})
}
placeholder="전체, 원자재, 반도체, 완제품"
className="h-8 text-xs"
/>
<p className="text-muted-foreground text-[10px]">
: 전체, , ,
</p>
{availableColumns.length > 0 && (
<>
<Label className="text-xs"> </Label>
<Select
value={config.categoryColumn || ""}
onValueChange={(value) =>
handleChange({
...config,
categoryColumn: value,
})
}
>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="컬럼 선택" />
</SelectTrigger>
<SelectContent>
{availableColumns.map((col) => (
<SelectItem key={col.columnName} value={col.columnName} className="text-xs">
{col.displayName || col.columnName}
</SelectItem>
))}
</SelectContent>
</Select>
</>
)}
</div>
)}
</div>
</div>
)}
</div>
@ -246,7 +375,7 @@ export const CustomerItemMappingConfigPanel: React.FC<
<Input
value={config.emptyMessage || ""}
onChange={(e) =>
onChange({ ...config, emptyMessage: e.target.value })
handleChange({ ...config, emptyMessage: e.target.value })
}
placeholder="데이터가 없습니다"
/>
@ -257,7 +386,7 @@ export const CustomerItemMappingConfigPanel: React.FC<
<Input
value={config.emptyDescription || ""}
onChange={(e) =>
onChange({ ...config, emptyDescription: e.target.value })
handleChange({ ...config, emptyDescription: e.target.value })
}
placeholder="품목 데이터가 추가되면 여기에 표시됩니다"
/>

View File

@ -23,8 +23,14 @@ export const CustomerItemMappingDefinition = createComponentDefinition({
multiple: true,
selectAll: true,
},
showSearchArea: false,
showSearchArea: true, // 기본적으로 검색 영역 표시
searchAreaHeight: 80,
searchPlaceholder: "품목코드, 품목명, 규격 검색",
enableCategoryFilter: true, // 기본적으로 카테고리 필터 표시
categoryColumn: undefined,
categories: ["전체", "원자재", "반도체", "완제품"],
showCompanyName: false,
companyNameColumn: undefined,
emptyMessage: "데이터가 없습니다",
emptyDescription: "품목 데이터가 추가되면 여기에 표시됩니다",
} as CustomerItemMappingConfig,

View File

@ -12,9 +12,19 @@ export interface CustomerItemMappingConfig {
selectAll: boolean;
};
// 검색/필터 영역 (나중에 추가할 공간)
// 검색/필터 영역
showSearchArea?: boolean;
searchAreaHeight?: number;
searchPlaceholder?: string; // 검색 플레이스홀더
// 카테고리 필터
enableCategoryFilter?: boolean; // 카테고리 필터 활성화
categoryColumn?: string; // 카테고리 데이터 컬럼명
categories?: string[]; // 카테고리 목록 (예: ["전체", "원자재", "반도체", "완제품"])
// 헤더 설정
showCompanyName?: boolean; // 회사명 표시 여부
companyNameColumn?: string; // 회사명을 가져올 컬럼명
// 빈 데이터 메시지
emptyMessage?: string;