사용자관리 등록

This commit is contained in:
kjs
2025-08-25 13:12:17 +09:00
parent 8667cb4780
commit ce130ee225
9 changed files with 1256 additions and 170 deletions

View File

@@ -62,10 +62,24 @@ interface CompanyOption {
}
interface DepartmentOption {
CODE: string;
NAME: string;
DEPT_CODE: string;
DEPT_NAME: string;
deptCode?: string;
deptName?: string;
parentDeptCode?: string;
masterSabun?: string;
masterUserId?: string;
location?: string;
locationName?: string;
regdate?: string;
dataType?: string;
status?: string;
salesYn?: string;
companyName?: string;
children?: DepartmentOption[];
// 기존 호환성을 위한 필드들
CODE?: string;
NAME?: string;
DEPT_CODE?: string;
DEPT_NAME?: string;
[key: string]: any; // 기타 필드들
}
@@ -202,20 +216,21 @@ export function UserFormModal({ isOpen, onClose, onSuccess }: UserFormModalProps
try {
const response = await userAPI.checkDuplicateId(formData.userId);
if (response.success && response.data) {
// result는 boolean 타입: true = 사용가능, false = 중복됨
const isAvailable = response.data.result;
// 백엔드 API 응답 구조: { isDuplicate: boolean, message: string }
const isDuplicate = response.data.isDuplicate;
const message = response.data.message;
if (isAvailable) {
// 중복체크 성공 시 상태 업데이트
if (!isDuplicate) {
// 중복되지 않음 (사용 가능)
setIsUserIdChecked(true);
setLastCheckedUserId(formData.userId);
setDuplicateCheckMessage(response.data.msg || "사용 가능한 사용자 ID입니다.");
setDuplicateCheckMessage(message || "사용 가능한 사용자 ID입니다.");
setDuplicateCheckType("success");
} else {
// 중복된 ID인 경우 상태 초기화
// 중복됨 (사용 불가)
setIsUserIdChecked(false);
setLastCheckedUserId("");
setDuplicateCheckMessage(response.data.msg || "이미 사용 중인 사용자 ID입니다.");
setDuplicateCheckMessage(message || "이미 사용 중인 사용자 ID입니다.");
setDuplicateCheckType("error");
}
}
@@ -280,15 +295,15 @@ export function UserFormModal({ isOpen, onClose, onSuccess }: UserFormModalProps
try {
const userDataToSend = {
user_id: formData.userId,
user_password: formData.userPassword,
user_name: formData.userName,
userId: formData.userId,
userPassword: formData.userPassword,
userName: formData.userName,
email: formData.email || null,
tel: formData.tel || null,
cell_phone: formData.cellPhone || null,
position_name: formData.positionName || null,
company_code: formData.companyCode,
dept_code: formData.deptCode || null,
cellPhone: formData.cellPhone || null,
positionName: formData.positionName || null,
companyCode: formData.companyCode,
deptCode: formData.deptCode || null,
sabun: null, // 항상 null (테이블 1번 컬럼)
status: "active", // 기본값 (테이블 18번 컬럼)
};
@@ -460,14 +475,28 @@ export function UserFormModal({ isOpen, onClose, onSuccess }: UserFormModalProps
<SelectValue placeholder="부서 선택" />
</SelectTrigger>
<SelectContent>
{departments.map((department) => (
<SelectItem
key={department.CODE || department.DEPT_CODE}
value={department.CODE || department.DEPT_CODE}
>
{department.NAME || department.DEPT_NAME}
{Array.isArray(departments) && departments.length > 0 ? (
departments
.filter((department) => {
const deptCode = department.deptCode || department.CODE || department.DEPT_CODE;
return deptCode && deptCode.trim() !== "";
})
.map((department) => {
const deptCode = department.deptCode || department.CODE || department.DEPT_CODE || "";
const deptName =
department.deptName || department.NAME || department.DEPT_NAME || "Unknown Department";
return (
<SelectItem key={deptCode} value={deptCode}>
{deptName}
</SelectItem>
);
})
) : (
<SelectItem value="no-data" disabled>
</SelectItem>
))}
)}
</SelectContent>
</Select>
</div>

View File

@@ -180,23 +180,23 @@ export function UserTable({ users, isLoading, paginationInfo, onStatusToggle, on
{users.map((user, index) => (
<TableRow key={`${user.user_id}-${index}`} className="hover:bg-muted/50">
<TableCell className="font-mono text-sm font-medium">{getRowNumber(index)}</TableCell>
<TableCell className="font-mono text-sm">{user.sabun}</TableCell>
<TableCell className="font-medium">{user.company_name || "-"}</TableCell>
<TableCell className="font-medium">{user.dept_name}</TableCell>
<TableCell className="font-medium">{user.position_name || "-"}</TableCell>
<TableCell className="font-mono">{user.user_id}</TableCell>
<TableCell className="font-medium">{user.user_name}</TableCell>
<TableCell>{user.tel || user.cell_phone || "-"}</TableCell>
<TableCell className="font-mono text-sm">{user.sabun || "-"}</TableCell>
<TableCell className="font-medium">{user.companyCode || "-"}</TableCell>
<TableCell className="font-medium">{user.deptName || "-"}</TableCell>
<TableCell className="font-medium">{user.positionName || "-"}</TableCell>
<TableCell className="font-mono">{user.userId}</TableCell>
<TableCell className="font-medium">{user.userName}</TableCell>
<TableCell>{user.tel || user.cellPhone || "-"}</TableCell>
<TableCell className="max-w-[200px] truncate" title={user.email}>
{user.email || "-"}
</TableCell>
<TableCell>{formatDate(user.regdate)}</TableCell>
<TableCell>{formatDate(user.regDate)}</TableCell>
<TableCell>
<div className="flex items-center gap-2">
<Switch
checked={user.status === "active"}
onCheckedChange={(checked) => handleStatusToggle(user, checked)}
aria-label={`${user.user_name} 상태 토글`}
aria-label={`${user.userName} 상태 토글`}
/>
<span
className={`text-sm font-medium ${user.status === "active" ? "text-blue-600" : "text-gray-500"}`}
@@ -210,7 +210,7 @@ export function UserTable({ users, isLoading, paginationInfo, onStatusToggle, on
<Button
variant="ghost"
size="sm"
onClick={() => onPasswordReset(user.user_id, user.user_name || user.user_id)}
onClick={() => onPasswordReset(user.userId, user.userName || user.userId)}
className="h-8 w-8 p-0"
title="비밀번호 초기화"
>