diff --git a/backend-node/src/controllers/adminController.ts b/backend-node/src/controllers/adminController.ts index 667637c8..0ec055ba 100644 --- a/backend-node/src/controllers/adminController.ts +++ b/backend-node/src/controllers/adminController.ts @@ -1739,6 +1739,7 @@ export const getUserInfo = async (req: AuthenticatedRequest, res: Response) => { u.fax_no, u.partner_objid, u.rank, + u.photo, u.locale, u.company_code, u.data_type, @@ -1791,6 +1792,9 @@ export const getUserInfo = async (req: AuthenticatedRequest, res: Response) => { faxNo: user.fax_no, partnerObjid: user.partner_objid, rank: user.rank, + photo: user.photo + ? `data:image/jpeg;base64,${user.photo.toString("base64")}` + : null, locale: user.locale, companyCode: user.company_code, dataType: user.data_type, @@ -2724,7 +2728,24 @@ export const updateProfile = async ( if (email !== undefined) updateData.email = email; if (tel !== undefined) updateData.tel = tel; if (cellPhone !== undefined) updateData.cell_phone = cellPhone; - if (photo !== undefined) updateData.photo = photo; + + // photo 데이터 처리 (Base64를 Buffer로 변환하여 저장) + if (photo !== undefined) { + if (photo && typeof photo === "string") { + try { + // Base64 헤더 제거 (data:image/jpeg;base64, 등) + const base64Data = photo.replace(/^data:image\/[a-z]+;base64,/, ""); + // Base64를 Buffer로 변환 + updateData.photo = Buffer.from(base64Data, "base64"); + } catch (error) { + console.error("Base64 이미지 처리 오류:", error); + updateData.photo = null; + } + } else { + updateData.photo = null; // 빈 값이면 null로 설정 + } + } + if (locale !== undefined) updateData.locale = locale; // 업데이트할 데이터가 없으면 에러 @@ -2767,10 +2788,18 @@ export const updateProfile = async ( }, }); + // photo가 Buffer 타입인 경우 Base64로 변환 + const responseData = { + ...updatedUser, + photo: updatedUser?.photo + ? `data:image/jpeg;base64,${updatedUser.photo.toString("base64")}` + : null, + }; + res.json({ result: true, message: "프로필이 성공적으로 업데이트되었습니다.", - data: updatedUser, + data: responseData, }); } catch (error) { console.error("프로필 업데이트 오류:", error); diff --git a/backend-node/src/controllers/authController.ts b/backend-node/src/controllers/authController.ts index c9e5b6ce..43a82f2e 100644 --- a/backend-node/src/controllers/authController.ts +++ b/backend-node/src/controllers/authController.ts @@ -166,15 +166,33 @@ export class AuthController { const userInfo = JwtUtils.verifyToken(token); + // DB에서 최신 사용자 정보 조회 (locale 포함) + const dbUserInfo = await AuthService.getUserInfo(userInfo.userId); + + if (!dbUserInfo) { + res.status(401).json({ + success: false, + message: "사용자 정보를 찾을 수 없습니다.", + error: { + code: "USER_NOT_FOUND", + details: "사용자 정보가 삭제되었거나 존재하지 않습니다.", + }, + }); + return; + } + const userInfoResponse: UserInfo = { - userId: userInfo.userId, - userName: userInfo.userName || "", - deptName: userInfo.deptName || "", - companyCode: userInfo.companyCode || "ILSHIN", - userType: userInfo.userType || "USER", - userTypeName: userInfo.userTypeName || "일반사용자", + userId: dbUserInfo.userId, + userName: dbUserInfo.userName || "", + deptName: dbUserInfo.deptName || "", + companyCode: dbUserInfo.companyCode || "ILSHIN", + userType: dbUserInfo.userType || "USER", + userTypeName: dbUserInfo.userTypeName || "일반사용자", + email: dbUserInfo.email || "", + photo: dbUserInfo.photo, + locale: dbUserInfo.locale || "KR", // locale 정보 추가 isAdmin: - userInfo.userType === "ADMIN" || userInfo.userId === "plm_admin", + dbUserInfo.userType === "ADMIN" || dbUserInfo.userId === "plm_admin", }; res.status(200).json({ diff --git a/backend-node/src/services/authService.ts b/backend-node/src/services/authService.ts index 5aafc132..a7e32d5c 100644 --- a/backend-node/src/services/authService.ts +++ b/backend-node/src/services/authService.ts @@ -146,6 +146,8 @@ export class AuthService { user_type_name: true, partner_objid: true, company_code: true, + locale: true, + photo: true, }, }); @@ -189,6 +191,8 @@ export class AuthService { partnerObjid: userInfo.partner_objid || undefined, authName: authInfo.length > 0 ? authInfo[0].auth_name : undefined, companyCode: userInfo.company_code || "ILSHIN", + photo: userInfo.photo ? `data:image/jpeg;base64,${userInfo.photo.toString('base64')}` : undefined, + locale: userInfo.locale || "KR", }; logger.info(`사용자 정보 조회 완료: ${userId}`); diff --git a/backend-node/src/types/auth.ts b/backend-node/src/types/auth.ts index 785157f9..c1384b51 100644 --- a/backend-node/src/types/auth.ts +++ b/backend-node/src/types/auth.ts @@ -15,6 +15,9 @@ export interface UserInfo { companyCode: string; userType?: string; userTypeName?: string; + email?: string; + photo?: string; + locale?: string; isAdmin?: boolean; } @@ -47,6 +50,8 @@ export interface PersonBean { partnerObjid?: string; authName?: string; companyCode?: string; + photo?: string; + locale?: string; } // 로그인 결과 타입 (기존 LoginService.loginPwdCheck 반환값) diff --git a/frontend/components/layout/AppLayout.tsx b/frontend/components/layout/AppLayout.tsx index 35597eb3..9a4d6207 100644 --- a/frontend/components/layout/AppLayout.tsx +++ b/frontend/components/layout/AppLayout.tsx @@ -204,6 +204,7 @@ export function AppLayout({ children }: AppLayoutProps) { formData, selectedImage, isSaving, + departments, alertModal, closeAlert, openProfileModal, @@ -394,6 +395,7 @@ export function AppLayout({ children }: AppLayoutProps) { formData={formData} selectedImage={selectedImage} isSaving={isSaving} + departments={departments} alertModal={alertModal} onClose={closeProfileModal} onFormChange={updateFormData} diff --git a/frontend/components/layout/ProfileModal.tsx b/frontend/components/layout/ProfileModal.tsx index a99fd23d..d2467bac 100644 --- a/frontend/components/layout/ProfileModal.tsx +++ b/frontend/components/layout/ProfileModal.tsx @@ -53,6 +53,10 @@ interface ProfileModalProps { formData: ProfileFormData; selectedImage: string; isSaving: boolean; + departments: Array<{ + deptCode: string; + deptName: string; + }>; alertModal: { isOpen: boolean; title: string; @@ -76,6 +80,7 @@ export function ProfileModal({ formData, selectedImage, isSaving, + departments, alertModal, onClose, onFormChange, @@ -99,12 +104,14 @@ export function ProfileModal({ {selectedImage ? ( + ) : user?.photo ? ( + ) : ( {formData.userName?.substring(0, 1) || "U"} )} - {selectedImage && ( + {(selectedImage || user?.photo) && (