Merge branch 'gbpark-node' of http://39.117.244.52:3000/kjs/ERP-node into jskim-node

This commit is contained in:
kjs
2026-03-11 12:23:52 +09:00
588 changed files with 25062 additions and 13798 deletions

View File

@@ -553,28 +553,28 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
onFocus={() => setIsOpen(true)}
placeholder="코드 또는 코드명 입력..."
className={cn(
"h-10 w-full rounded-lg border border-gray-300 bg-white px-3 py-2 transition-all outline-none",
"h-10 w-full rounded-lg border border-input bg-white px-3 py-2 transition-all outline-none",
!isFieldDisabled && "hover:border-orange-400 focus:border-orange-500 focus:ring-2 focus:ring-orange-200",
isSelected && "ring-2 ring-orange-500",
isFieldDisabled && "cursor-not-allowed !bg-gray-100 opacity-60",
isFieldDisabled && "cursor-not-allowed !bg-muted opacity-60",
)}
readOnly={isFieldDisabled}
disabled={isFieldDisabled}
/>
{isOpen && !isFieldDisabled && filteredOptions.length > 0 && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-input bg-white shadow-lg">
{filteredOptions.map((option, index) => (
<div
key={`${option.value}-${index}`}
className="cursor-pointer bg-white px-3 py-2 hover:bg-gray-100"
className="cursor-pointer bg-white px-3 py-2 hover:bg-muted"
onClick={() => {
setSearchQuery("");
handleOptionSelect(option.value, option.label);
}}
>
<div className="flex items-center justify-between">
<span className="text-sm font-medium text-gray-900">{option.label}</span>
<span className="text-xs text-gray-500">{option.value}</span>
<span className="text-sm font-medium text-foreground">{option.label}</span>
<span className="text-xs text-muted-foreground">{option.value}</span>
</div>
</div>
))}
@@ -590,16 +590,16 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div className="w-full">
<div
className={cn(
"flex h-10 w-full items-center justify-between rounded-lg border border-gray-300 bg-white px-3 py-2",
"flex h-10 w-full items-center justify-between rounded-lg border border-input bg-white px-3 py-2",
!isFieldDisabled && "cursor-pointer hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isOpen && "border-orange-500",
isFieldDisabled && "cursor-not-allowed !bg-gray-100 opacity-60",
isFieldDisabled && "cursor-not-allowed !bg-muted opacity-60",
)}
onClick={handleToggle}
style={{ pointerEvents: isFieldDisabled ? "none" : "auto" }}
>
<span className={selectedLabel ? "text-gray-900" : "text-gray-500"}>{selectedLabel || placeholder}</span>
<span className={selectedLabel ? "text-foreground" : "text-muted-foreground"}>{selectedLabel || placeholder}</span>
<svg
className={`h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`}
fill="none"
@@ -610,21 +610,21 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
</svg>
</div>
{isOpen && !isFieldDisabled && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-input bg-white shadow-lg">
{isLoadingCodes ? (
<div className="bg-white px-3 py-2 text-gray-900"> ...</div>
<div className="bg-white px-3 py-2 text-foreground"> ...</div>
) : allOptions.length > 0 ? (
allOptions.map((option, index) => (
<div
key={`${option.value}-${index}`}
className="cursor-pointer bg-white px-3 py-2 text-gray-900 hover:bg-gray-100"
className="cursor-pointer bg-white px-3 py-2 text-foreground hover:bg-muted"
onClick={() => handleOptionSelect(option.value, option.label)}
>
{option.label}
</div>
))
) : (
<div className="bg-white px-3 py-2 text-gray-900"> </div>
<div className="bg-white px-3 py-2 text-foreground"> </div>
)}
</div>
)}
@@ -638,16 +638,16 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div className="w-full">
<div
className={cn(
"box-border flex h-full w-full flex-wrap gap-2 rounded-lg border border-gray-300 bg-white px-3 py-2",
"box-border flex h-full w-full flex-wrap gap-2 rounded-lg border border-input bg-white px-3 py-2",
!isFieldDisabled && "hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isFieldDisabled && "cursor-not-allowed !bg-gray-100 opacity-60",
isFieldDisabled && "cursor-not-allowed !bg-muted opacity-60",
)}
>
{selectedValues.map((val, idx) => {
const opt = allOptions.find((o) => o.value === val);
return (
<span key={idx} className="flex items-center gap-1 rounded bg-blue-100 px-2 py-1 text-sm text-blue-800">
<span key={idx} className="flex items-center gap-1 rounded bg-primary/10 px-2 py-1 text-sm text-primary">
{opt?.label || val}
<button
type="button"
@@ -658,7 +658,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
onFormDataChange(component.columnName, newVals.join(","));
}
}}
className="ml-1 text-blue-600 hover:text-blue-800"
className="ml-1 text-primary hover:text-primary"
>
×
</button>
@@ -699,20 +699,20 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
onFocus={() => !isFieldDisabled && setIsOpen(true)}
placeholder={placeholder}
className={cn(
"h-10 w-full rounded-lg border border-gray-300 bg-white px-3 py-2 transition-all outline-none",
"h-10 w-full rounded-lg border border-input bg-white px-3 py-2 transition-all outline-none",
!isFieldDisabled && "hover:border-orange-400 focus:border-orange-500 focus:ring-2 focus:ring-orange-200",
isSelected && "ring-2 ring-orange-500",
isFieldDisabled && "cursor-not-allowed !bg-gray-100 opacity-60",
isFieldDisabled && "cursor-not-allowed !bg-muted opacity-60",
)}
readOnly={isFieldDisabled}
disabled={isFieldDisabled}
/>
{isOpen && !isFieldDisabled && filteredOptions.length > 0 && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-input bg-white shadow-lg">
{filteredOptions.map((option, index) => (
<div
key={`${option.value}-${index}`}
className="cursor-pointer bg-white px-3 py-2 text-gray-900 hover:bg-gray-100"
className="cursor-pointer bg-white px-3 py-2 text-foreground hover:bg-muted"
onClick={() => {
setSearchQuery(option.label);
setSelectedValue(option.value);
@@ -738,16 +738,16 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div className="w-full">
<div
className={cn(
"flex h-10 w-full items-center justify-between rounded-lg border border-gray-300 bg-white px-3 py-2",
"flex h-10 w-full items-center justify-between rounded-lg border border-input bg-white px-3 py-2",
!isFieldDisabled && "cursor-pointer hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isOpen && "border-orange-500",
isFieldDisabled && "cursor-not-allowed !bg-gray-100 opacity-60",
isFieldDisabled && "cursor-not-allowed !bg-muted opacity-60",
)}
onClick={handleToggle}
style={{ pointerEvents: isFieldDisabled ? "none" : "auto" }}
>
<span className={selectedLabel ? "text-gray-900" : "text-gray-500"}>{selectedLabel || placeholder}</span>
<span className={selectedLabel ? "text-foreground" : "text-muted-foreground"}>{selectedLabel || placeholder}</span>
<svg
className={`h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`}
fill="none"
@@ -758,13 +758,13 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
</svg>
</div>
{isOpen && !isFieldDisabled && (
<div className="absolute z-[99999] mt-1 w-full rounded-md border border-gray-300 bg-white shadow-lg">
<div className="absolute z-[99999] mt-1 w-full rounded-md border border-input bg-white shadow-lg">
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="검색..."
className="w-full border-b border-gray-300 px-3 py-2 outline-none"
className="w-full border-b border-input px-3 py-2 outline-none"
/>
<div className="max-h-60 overflow-auto">
{allOptions
@@ -776,7 +776,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
.map((option, index) => (
<div
key={`${option.value}-${index}`}
className="cursor-pointer bg-white px-3 py-2 text-gray-900 hover:bg-gray-100"
className="cursor-pointer bg-white px-3 py-2 text-foreground hover:bg-muted"
onClick={() => handleOptionSelect(option.value, option.label)}
>
{option.label || option.value}
@@ -796,10 +796,10 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div className="w-full" style={{ height: "100%" }}>
<div
className={cn(
"box-border flex w-full flex-wrap items-center gap-2 rounded-lg border border-gray-300 bg-white px-3 py-2",
"box-border flex w-full flex-wrap items-center gap-2 rounded-lg border border-input bg-white px-3 py-2",
!isFieldDisabled && "hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isFieldDisabled && "cursor-not-allowed !bg-gray-100 opacity-60",
isFieldDisabled && "cursor-not-allowed !bg-muted opacity-60",
)}
onClick={() => !isFieldDisabled && setIsOpen(true)}
style={{
@@ -810,7 +810,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
{selectedValues.map((val, idx) => {
const opt = allOptions.find((o) => o.value === val);
return (
<span key={idx} className="flex items-center gap-1 rounded bg-blue-100 px-2 py-1 text-sm text-blue-800">
<span key={idx} className="flex items-center gap-1 rounded bg-primary/10 px-2 py-1 text-sm text-primary">
{opt?.label || val}
<button
type="button"
@@ -823,19 +823,19 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
onFormDataChange(component.columnName, newValue);
}
}}
className="ml-1 text-blue-600 hover:text-blue-800"
className="ml-1 text-primary hover:text-primary"
>
×
</button>
</span>
);
})}
{selectedValues.length === 0 && <span className="text-gray-500">{placeholder}</span>}
{selectedValues.length === 0 && <span className="text-muted-foreground">{placeholder}</span>}
</div>
{isOpen && !isFieldDisabled && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-input bg-white shadow-lg">
{isLoadingCodes || isLoadingCategories ? (
<div className="bg-white px-3 py-2 text-gray-900"> ...</div>
<div className="bg-white px-3 py-2 text-foreground"> ...</div>
) : allOptions.length > 0 ? (
(() => {
// 부모별 그룹핑 (카테고리 연쇄관계인 경우)
@@ -856,7 +856,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
return Object.entries(groupedOptions).map(([parentKey, group]) => (
<div key={parentKey}>
{/* 그룹 헤더 */}
<div className="sticky top-0 border-b bg-gray-100 px-3 py-1.5 text-xs font-semibold text-gray-600">
<div className="sticky top-0 border-b bg-muted px-3 py-1.5 text-xs font-semibold text-muted-foreground">
{group.parentLabel}
</div>
{/* 그룹 옵션들 */}
@@ -866,8 +866,8 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div
key={`${option.value}-${index}`}
className={cn(
"cursor-pointer px-3 py-2 text-gray-900 hover:bg-gray-100",
isOptionSelected && "bg-blue-50 font-medium",
"cursor-pointer px-3 py-2 text-foreground hover:bg-muted",
isOptionSelected && "bg-primary/10 font-medium",
)}
onClick={() => {
const newVals = isOptionSelected
@@ -914,8 +914,8 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div
key={`${option.value}-${index}`}
className={cn(
"cursor-pointer px-3 py-2 text-gray-900 hover:bg-gray-100",
isOptionSelected && "bg-blue-50 font-medium",
"cursor-pointer px-3 py-2 text-foreground hover:bg-muted",
isOptionSelected && "bg-primary/10 font-medium",
)}
onClick={() => {
const newVals = isOptionSelected
@@ -953,7 +953,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
});
})()
) : (
<div className="bg-white px-3 py-2 text-gray-900"> </div>
<div className="bg-white px-3 py-2 text-foreground"> </div>
)}
</div>
)}
@@ -966,16 +966,16 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
<div className="w-full">
<div
className={cn(
"flex h-10 w-full items-center justify-between rounded-lg border border-gray-300 bg-white px-3 py-2",
"flex h-10 w-full items-center justify-between rounded-lg border border-input bg-white px-3 py-2",
!isFieldDisabled && "cursor-pointer hover:border-orange-400",
isSelected && "ring-2 ring-orange-500",
isOpen && "border-orange-500",
isFieldDisabled && "cursor-not-allowed !bg-gray-100 opacity-60",
isFieldDisabled && "cursor-not-allowed !bg-muted opacity-60",
)}
onClick={handleToggle}
style={{ pointerEvents: isFieldDisabled ? "none" : "auto" }}
>
<span className={selectedLabel ? "text-gray-900" : "text-gray-500"}>{selectedLabel || placeholder}</span>
<span className={selectedLabel ? "text-foreground" : "text-muted-foreground"}>{selectedLabel || placeholder}</span>
<svg
className={`h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`}
fill="none"
@@ -986,21 +986,21 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
</svg>
</div>
{isOpen && !isFieldDisabled && (
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
<div className="absolute z-[99999] mt-1 max-h-60 w-full overflow-auto rounded-md border border-input bg-white shadow-lg">
{isLoadingCodes ? (
<div className="bg-white px-3 py-2 text-gray-900"> ...</div>
<div className="bg-white px-3 py-2 text-foreground"> ...</div>
) : allOptions.length > 0 ? (
allOptions.map((option, index) => (
<div
key={`${option.value}-${index}`}
className="cursor-pointer bg-white px-3 py-2 text-gray-900 hover:bg-gray-100"
className="cursor-pointer bg-white px-3 py-2 text-foreground hover:bg-muted"
onClick={() => handleOptionSelect(option.value, option.label)}
>
{option.label || option.value}
</div>
))
) : (
<div className="bg-white px-3 py-2 text-gray-900"> </div>
<div className="bg-white px-3 py-2 text-foreground"> </div>
)}
</div>
)}
@@ -1022,7 +1022,7 @@ const SelectBasicComponent: React.FC<SelectBasicComponentProps> = ({
{component.label && (component.style?.labelDisplay ?? true) && (
<label className="absolute -top-6 left-0 text-sm font-medium text-slate-600">
{component.label}
{component.required && <span className="text-red-500">*</span>}
{component.required && <span className="text-destructive">*</span>}
</label>
)}