티스토리 뷰

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>HR 조직도 관리 시스템 - 프로필 이미지 추가</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
        /* [1] 기존 스타일 유지 및 이미지 관련 추가 */
        body { font-family: 'Pretendard', sans-serif; margin: 0; display: flex; height: 100vh; background: #f4f7f6; }
        .sidebar { width: 400px; background: #fff; border-right: 1px solid #e0e0e0; padding: 25px; overflow-y: auto; }
        .detail-view { flex: 1; padding: 50px; background: #fff; display: flex; flex-direction: column; align-items: center; }

        /* 검색 영역 */
        .search-container { display: flex; gap: 6px; margin-bottom: 20px; }
        .search-container input { flex: 1; padding: 12px; border: 1px solid #ddd; border-radius: 8px; outline: none; }
        .btn { padding: 8px 16px; border: none; border-radius: 8px; cursor: pointer; font-weight: 600; }
        .btn-search { background: #007bff; color: white; }
        .btn-reset { background: #6c757d; color: white; }

        /* 트리 메뉴 */
        ul.tree, ul.tree ul { list-style: none; padding-left: 20px; margin: 0; }
        .dept, .user { padding: 8px 12px; cursor: pointer; border-radius: 6px; display: inline-block; font-size: 14px; margin: 4px 0; }
        .dept { font-weight: bold; background: #f8f9fa; }
        .dept.collapsed + ul { display: none; }
        .active-item { background-color: #007bff !important; color: white !important; }
        .highlight { background-color: #fff3cd !important; border: 1px solid #ffeeba; }

        /* 🖼️ 프로필 카드 스타일 */
        .user-card { border: 1px solid #eee; padding: 40px; border-radius: 15px; box-shadow: 0 10px 25px rgba(0,0,0,0.05); width: 100%; max-width: 500px; text-align: center; }
        .profile-img-area { width: 120px; height: 120px; margin: 0 auto 20px; border-radius: 50%; overflow: hidden; border: 3px solid #f0f0f0; background: #f9f9f9; display: flex; align-items: center; justify-content: center; }
        .profile-img-area img { width: 100%; height: 100%; object-fit: cover; }
        
        /* 상세 정보 텍스트 */
        .info-list { text-align: left; margin-top: 25px; line-height: 2; border-top: 1px solid #eee; padding-top: 20px; }
        .info-item { display: flex; border-bottom: 1px id #f9f9f9; }
        .info-label { width: 100px; color: #888; font-weight: bold; }
    </style>
</head>
<body>

    <div class="sidebar">
        <h2 style="margin-top: 0;">🏢 조직도 탐색</h2>
        <div class="search-container">
            <input type="text" id="tree-search" placeholder="이름 입력...">
            <button id="btn-search-trigger" class="btn btn-search">검색</button>
            <button id="btn-search-reset" class="btn btn-reset">초기화</button>
        </div>
        <ul class="tree" id="main-tree"></ul>
    </div>

    <div class="detail-view">
        <div id="view-empty" style="text-align: center; margin-top: 150px; color: #ccc;">
            <p style="font-size: 80px; margin: 0;">👤</p>
            <p>사원을 선택하면 상세 정보가 표시됩니다.</p>
        </div>

        <div id="view-detail" style="display: none;">
            <div class="user-card">
                <div class="profile-img-area">
                    <img id="user-photo" src="" alt="프로필">
                </div>

                <span id="user-dept-tag" style="background:#e7f1ff; color:#007bff; padding:4px 12px; border-radius:20px; font-size:12px; font-weight:bold;">부서</span>
                <h1 id="user-name" style="margin: 10px 0 0 0; font-size: 28px;">이름</h1>
                <p id="user-title" style="margin: 0 0 10px 0; color: #666;">직급</p>

                <div class="info-list">
                    <div class="info-item"><span class="info-label">사번</span><span id="user-id"></span></div>
                    <div class="info-item"><span class="info-label">이메일</span><span id="user-email"></span></div>
                    <div class="info-item"><span class="info-label">담당업무</span><span id="user-task"></span></div>
                </div>
            </div>
        </div>
    </div>

<script>
$(document).ready(function() {
    // 1. 샘플 데이터 (img 경로가 없으면 기본 이미지로 대체됨)
    const orgData = [
        {
            "name": "플랫폼사업부",
            "type": "dept",
            "children": [
                {
                    "name": "개발팀",
                    "type": "dept",
                    "children": [
                        { "name": "최자바", "type": "user", "title": "수석연구원", "id": "IT-101", "email": "java@work.com", "task": "서버 아키텍처", "img": "https://i.pravatar.cc/150?u=101" },
                        { "name": "김리액", "type": "user", "title": "선임연구원", "id": "IT-105", "email": "react@work.com", "task": "UI 개발", "img": "" } // 사진 없음 예시
                    ]
                }
            ]
        },
        { "name": "인사팀", "type": "dept", "children": [
            { "name": "박인사", "type": "user", "title": "과장", "id": "HR-001", "email": "park@work.com", "task": "채용 관리", "img": "https://i.pravatar.cc/150?u=001" }
        ]}
    ];

    // 기본 이미지 경로 설정
    const DEFAULT_IMG = "https://via.placeholder.com/150/f0f0f0/999999?text=no-img";

    function buildTree(data, path = "") {
        let html = "";
        data.forEach(item => {
            if (item.type === "dept") {
                html += `<li><div class="dept">🏢 ${item.name}</div><ul>${buildTree(item.children, item.name)}</ul></li>`;
            } else {
                // 데이터 속성에 이미지 경로도 포함
                html += `<li class="user" 
                            data-name="${item.name}" data-title="${item.title}" data-id="${item.id}" 
                            data-dept="${path}" data-email="${item.email}" data-task="${item.task}"
                            data-img="${item.img || ''}">👤 ${item.name} ${item.title}</li>`;
            }
        });
        return html;
    }
    $('#main-tree').html(buildTree(orgData));

    // [클릭 이벤트] 사원 정보 출력
    $(document).on('click', '.user', function() {
        $('.user').removeClass('active-item');
        $(this).addClass('active-item');

        const d = $(this).data();
        $('#view-empty').hide();
        $('#view-detail').fadeIn(200);

        // 사진 처리 로직: 데이터가 없으면 DEFAULT_IMG 사용
        const profileSrc = (d.img && d.img !== "") ? d.img : DEFAULT_IMG;
        $('#user-photo').attr('src', profileSrc);

        $('#user-name').text(d.name);
        $('#user-title').text(d.title);
        $('#user-id').text(d.id);
        $('#user-dept-tag').text(d.dept);
        $('#user-email').text(d.email);
        $('#user-task').text(d.task);
    });

    // 폴더 토글
    $(document).on('click', '.dept', function() {
        $(this).toggleClass('collapsed').next('ul').slideToggle(200);
    });

    // 검색 로직
    $('#btn-search-trigger').click(function() {
        const val = $('#tree-search').val().trim().toLowerCase();
        $('#main-tree li').hide();
        $('.dept, .user').removeClass('highlight');
        
        $('#main-tree li').each(function() {
            if ($(this).text().toLowerCase().indexOf(val) !== -1) {
                $(this).show().parents('li').show();
                $(this).parents('ul').show().prev('.dept').removeClass('collapsed');
                $(this).children('.user').filter(':contains('+val+')').addClass('highlight');
            }
        });
    });

    // 초기화
    $('#btn-search-reset').click(function() {
        $('#tree-search').val('');
        $('#main-tree li').show();
        $('.dept').removeClass('collapsed').next('ul').show();
        $('.highlight, .active-item').removeClass('highlight active-item');
        $('#view-detail').hide();
        $('#view-empty').show();
    });
});
</script>
</body>
</html>

프로필 이미지 기능이 포함된 인사 관리 시스템.html
0.01MB

 

CSS

 /* 🖼️ 프로필 카드 스타일 */

.profile-img-area { width: 120px; height: 120px; margin: 0 auto 20px; border-radius: 50%; overflow: hidden; border: 3px solid #f0f0f0; background: #f9f9f9; display: flex; align-items: center; justify-content: center; }
        .profile-img-area img { width: 100%; height: 100%; object-fit: cover; }

 

json

이미지 있을때

"img": "https://i.pravatar.cc/150?u=101이미지경로"

 

이미지 없을때

 "img": "" 

 

jQuery

 

// 기본 이미지 경로 설정
    const DEFAULT_IMG = "no-img경로";

 

 

 // 사진 처리 로직: 데이터가 없으면 DEFAULT_IMG 사용
        const profileSrc = (d.img && d.img !== "") ? d.img : DEFAULT_IMG;
        $('#user-photo').attr('src', profileSrc);

 

 

💡 달라진 포인트 (이미지 로직)

  1. 데이터 속성 추가: data-img="${item.img || ''}"를 통해 각 사용자 항목에 이미지 경로 정보를 심어두었습니다.
  2. 기본 이미지(DEFAULT_IMG) 설정: 상수로 no-img 역할을 할 이미지 경로를 선언했습니다. 실제 서버 환경이라면 "/images/no-img.png"와 같이 경로를 수정하시면 됩니다.
  3. 삼항 연산자 판별:
    • const profileSrc = (d.img && d.img !== "") ? d.img : DEFAULT_IMG;
    • 이 코드가 핵심입니다. 이미지 경로값이 존재하고 비어있지 않을 때만 해당 사진을 쓰고, 아니면 기본 이미지를 로드합니다.
  4. UI 디자인: 사진이 중앙에 원형으로 예쁘게 배치되도록 object-fit: cover; 스타일을 적용했습니다.

 

※ 해당 내용은 Google Gmini3.0에서 작성되었습니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함