사용자 상태 변경 구현
This commit is contained in:
parent
b43a88a045
commit
4f6be8f551
|
|
@ -3,6 +3,7 @@ import { logger } from "../utils/logger";
|
|||
import { AuthenticatedRequest } from "../types/auth";
|
||||
import { ApiResponse } from "../types/common";
|
||||
import { Client } from "pg";
|
||||
import config from "../config/environment";
|
||||
import { AdminService } from "../services/adminService";
|
||||
import { EncryptUtil } from "../utils/encryptUtil";
|
||||
|
||||
|
|
@ -1984,6 +1985,140 @@ export const getUserHistory = async (
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* PATCH /api/admin/users/:userId/status
|
||||
* 사용자 상태 변경 API (부분 수정)
|
||||
* 기존 Java AdminController.changeUserStatus() 포팅
|
||||
*/
|
||||
export const changeUserStatus = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
) => {
|
||||
try {
|
||||
const { userId } = req.params;
|
||||
const { status } = req.body;
|
||||
|
||||
logger.info("사용자 상태 변경 요청", { userId, status, user: req.user });
|
||||
|
||||
// 필수 파라미터 검증
|
||||
if (!userId || !status) {
|
||||
res.status(400).json({
|
||||
result: false,
|
||||
msg: "사용자 ID와 상태는 필수입니다.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 상태 값 검증
|
||||
if (!["active", "inactive"].includes(status)) {
|
||||
res.status(400).json({
|
||||
result: false,
|
||||
msg: "유효하지 않은 상태값입니다. (active, inactive만 허용)",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const client = new Client({
|
||||
connectionString: config.databaseUrl,
|
||||
});
|
||||
|
||||
try {
|
||||
await client.connect();
|
||||
|
||||
// 1. 사용자 존재 여부 확인
|
||||
const userCheckResult = await client.query(
|
||||
"SELECT user_id, user_name, status FROM user_info WHERE user_id = $1",
|
||||
[userId]
|
||||
);
|
||||
|
||||
if (userCheckResult.rows.length === 0) {
|
||||
res.status(404).json({
|
||||
result: false,
|
||||
msg: "사용자를 찾을 수 없습니다.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const currentUser = userCheckResult.rows[0];
|
||||
|
||||
// 2. 상태 변경 쿼리 실행
|
||||
let updateQuery = `
|
||||
UPDATE user_info
|
||||
SET status = $1
|
||||
`;
|
||||
|
||||
const queryParams = [status];
|
||||
|
||||
// active/inactive에 따른 END_DATE 처리
|
||||
if (status === "inactive") {
|
||||
updateQuery += `, end_date = NOW()`;
|
||||
} else if (status === "active") {
|
||||
updateQuery += `, end_date = NULL`;
|
||||
}
|
||||
|
||||
updateQuery += ` WHERE user_id = $2`;
|
||||
queryParams.push(userId);
|
||||
|
||||
const updateResult = await client.query(updateQuery, queryParams);
|
||||
|
||||
if (updateResult.rowCount && updateResult.rowCount > 0) {
|
||||
// 3. 사용자 이력 저장 (선택적)
|
||||
try {
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO user_info_history
|
||||
(user_id, user_name, dept_code, dept_name, user_type_name, history_type, writer, reg_date, status, sabun)
|
||||
VALUES ($1, $2, '', '', '', '사용자 상태 변경', $3, NOW(), $4, '')
|
||||
`,
|
||||
[
|
||||
userId,
|
||||
currentUser.user_name || userId,
|
||||
req.user?.userId || "system",
|
||||
status,
|
||||
]
|
||||
);
|
||||
} catch (historyError) {
|
||||
logger.warn("사용자 이력 저장 실패", {
|
||||
error: historyError,
|
||||
userId,
|
||||
status,
|
||||
});
|
||||
// 이력 저장 실패는 치명적이지 않으므로 계속 진행
|
||||
}
|
||||
|
||||
logger.info("사용자 상태 변경 성공", {
|
||||
userId,
|
||||
oldStatus: currentUser.status,
|
||||
newStatus: status,
|
||||
updatedBy: req.user?.userId,
|
||||
});
|
||||
|
||||
res.json({
|
||||
result: true,
|
||||
msg: `사용자 상태가 ${status === "active" ? "활성" : "비활성"}으로 변경되었습니다.`,
|
||||
});
|
||||
} else {
|
||||
res.status(400).json({
|
||||
result: false,
|
||||
msg: "사용자 상태 변경에 실패했습니다.",
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
await client.end();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("사용자 상태 변경 중 오류 발생", {
|
||||
error,
|
||||
userId: req.params.userId,
|
||||
status: req.body.status,
|
||||
});
|
||||
res.status(500).json({
|
||||
result: false,
|
||||
msg: "시스템 오류가 발생했습니다.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const saveUser = async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
const userData = req.body;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
getUserList,
|
||||
getUserInfo, // 사용자 상세 조회
|
||||
getUserHistory, // 사용자 변경이력 조회
|
||||
changeUserStatus, // 사용자 상태 변경
|
||||
getDepartmentList, // 부서 목록 조회
|
||||
checkDuplicateUserId, // 사용자 ID 중복 체크
|
||||
saveUser, // 사용자 등록/수정
|
||||
|
|
@ -41,6 +42,7 @@ router.delete("/menus/:menuId", deleteMenu); // 메뉴 삭제
|
|||
router.get("/users", getUserList);
|
||||
router.get("/users/:userId", getUserInfo); // 사용자 상세 조회
|
||||
router.get("/users/:userId/history", getUserHistory); // 사용자 변경이력 조회
|
||||
router.patch("/users/:userId/status", changeUserStatus); // 사용자 상태 변경
|
||||
router.post("/users", saveUser); // 사용자 등록/수정
|
||||
router.post("/users/check-duplicate", checkDuplicateUserId); // 사용자 ID 중복 체크
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Key, FileText, History } from "lucide-react";
|
||||
import { Key, History } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { User } from "@/types/user";
|
||||
import { USER_TABLE_COLUMNS } from "@/constants/user";
|
||||
|
|
@ -198,11 +198,6 @@ export function UserTable({ users, isLoading, paginationInfo, onStatusToggle, on
|
|||
onCheckedChange={(checked) => handleStatusToggle(user, checked)}
|
||||
aria-label={`${user.userName} 상태 토글`}
|
||||
/>
|
||||
<span
|
||||
className={`text-sm font-medium ${user.status === "active" ? "text-blue-600" : "text-gray-500"}`}
|
||||
>
|
||||
{user.status === "active" ? "활성" : "비활성"}
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
|
|
|
|||
|
|
@ -181,10 +181,10 @@ export const useUserManagement = () => {
|
|||
// 사용자 상태 토글 핸들러
|
||||
const handleStatusToggle = useCallback(async (user: User, newStatus: string) => {
|
||||
try {
|
||||
console.log(`🎛️ 상태 변경: ${user.user_name} (${user.user_id}) → ${newStatus}`);
|
||||
console.log(`🎛️ 상태 변경: ${user.userName} (${user.userId}) → ${newStatus}`);
|
||||
|
||||
// 백엔드 API 호출
|
||||
const response = await userAPI.updateStatus(user.user_id, newStatus);
|
||||
const response = await userAPI.updateStatus(user.userId, newStatus);
|
||||
|
||||
// 백엔드 응답 구조: { result: boolean, msg: string }
|
||||
if (response && typeof response === "object" && "result" in response) {
|
||||
|
|
@ -194,7 +194,7 @@ export const useUserManagement = () => {
|
|||
console.log("✅ 상태 변경 성공:", apiResponse.msg);
|
||||
|
||||
// 전체 목록 새로고침 대신 개별 사용자 상태만 업데이트
|
||||
setUsers((prevUsers) => prevUsers.map((u) => (u.user_id === user.user_id ? { ...u, status: newStatus } : u)));
|
||||
setUsers((prevUsers) => prevUsers.map((u) => (u.userId === user.userId ? { ...u, status: newStatus } : u)));
|
||||
} else {
|
||||
console.error("❌ 상태 변경 실패:", apiResponse.msg);
|
||||
alert(apiResponse.msg || "상태 변경에 실패했습니다.");
|
||||
|
|
|
|||
|
|
@ -78,10 +78,10 @@ export async function createUser(userData: any) {
|
|||
// 사용자 수정 기능 제거됨
|
||||
|
||||
/**
|
||||
* 사용자 상태 변경
|
||||
* 사용자 상태 변경 (부분 수정)
|
||||
*/
|
||||
export async function updateUserStatus(userId: string, status: string) {
|
||||
const response = await apiClient.put(`/admin/users/${userId}/status`, { status });
|
||||
const response = await apiClient.patch(`/admin/users/${userId}/status`, { status });
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue