티스토리 뷰

WEB/JavaScript

결재선 지정 선택 팝업

silverline79 2026. 3. 5. 07:00

 

결재팝업.html
0.01MB

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>전자결재 라인 지정</title>
    <style>
        /* --- 기본 레이아웃 설정 --- */
        body {
            margin: 0;
            padding: 0;
            font-family: 'Pretendard', sans-serif;
            font-size: 14px;
            background-color: #f5f6f7;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .popup-window {
            width: 1000px;
            height: 800px;
            background: #fff;
            display: flex;
            box-shadow: 0 10px 30px rgba(0,0,0,0.2);
            border-radius: 8px;
            overflow: hidden;
        }

        /* --- 왼쪽 패널 (결재선 지정) --- */
        .left-panel {
            width: 350px;
            border-right: 1px solid #ddd;
            display: flex;
            flex-direction: column;
            background-color: #fff;
        }

        .panel-header {
            padding: 15px;
            background: #f8f9fa;
            border-bottom: 1px solid #eee;
            font-weight: bold;
        }

        .org-tree-area {
            flex: 1;
            overflow-y: auto;
            padding: 10px;
        }

        /* 간단한 트리 메뉴 스타일 */
        .tree-node { cursor: pointer; padding: 5px; list-style: none; }
        .tree-node:hover { background: #f0f0f0; }
        .user-item { padding-left: 20px; color: #555; border-radius: 4px; }
        .user-item.active { background: #007bff; color: #fff; }

        /* 중간 버튼 영역 */
        .button-group {
            padding: 10px;
            text-align: center;
            background: #fdfdfd;
            border-top: 1px solid #eee;
            border-bottom: 1px solid #eee;
        }

        .btn {
            padding: 6px 12px;
            cursor: pointer;
            border: 1px solid #ccc;
            background: #fff;
            border-radius: 4px;
            font-size: 12px;
        }
        .btn:hover { background: #f0f0f0; }

        .selected-list-area {
            flex: 1;
            overflow-y: auto;
            padding: 10px;
        }

        .approval-table {
            width: 100%;
            border-collapse: collapse;
            font-size: 12px;
        }
        .approval-table th, .approval-table td {
            border: 1px solid #eee;
            padding: 8px;
            text-align: center;
        }
        .approval-table th { background: #f8f9fa; }

        /* --- 오른쪽 패널 (보고서 미리보기) --- */
        .right-panel {
            flex: 1;
            display: flex;
            flex-direction: column;
            background-color: #666; /* 배경을 어둡게 하여 문서 강조 */
        }

        .viewer-toolbar {
            padding: 10px;
            background: #444;
            color: white;
            display: flex;
            gap: 10px;
            align-items: center;
        }

        .report-container {
            flex: 1;
            overflow: auto;
            padding: 30px;
            display: flex;
            justify-content: center;
        }

        /* 확대/축소의 핵심 대상 */
        .report-paper {
            background: white;
            width: 500px;
            min-height: 700px;
            padding: 40px;
            box-shadow: 0 0 15px rgba(0,0,0,0.3);
            transform-origin: top center;
            transition: transform 0.2s ease-out;
        }

        .report-content h2 { text-align: center; text-decoration: underline; }
    </style>
</head>
<body>

<div class="popup-window">
    <aside class="left-panel">
        <div class="panel-header">조직도 선택</div>
        <div class="org-tree-area">
            <ul id="orgTree">
                <li class="tree-node">▶ 경영관리부
                    <ul>
                        <li class="tree-node user-item" data-id="A01" data-name="홍길동" data-pos="팀장">👤 홍길동 팀장</li>
                        <li class="tree-node user-item" data-id="A02" data-name="김철수" data-pos="과장">👤 김철수 과장</li>
                    </ul>
                </li>
                <li class="tree-node">▶ IT개발부
                    <ul>
                        <li class="tree-node user-item" data-id="B01" data-name="이영희" data-pos="본부장">👤 이영희 본부장</li>
                        <li class="tree-node user-item" data-id="B02" data-name="박디자" data-pos="대리">👤 박디자 대리</li>
                    </ul>
                </li>
            </ul>
        </div>

        <div class="button-group">
            <button class="btn" onclick="addApprover()">추가 ▼</button>
            <button class="btn" onclick="removeApprover()">삭제 ▲</button>
        </div>

        <div class="panel-header">결재선</div>
        <div class="selected-list-area">
            <table class="approval-table">
                <thead>
                    <tr>
                        <th>순번</th>
                        <th>성명</th>
                        <th>직급</th>
                    </tr>
                </thead>
                <tbody id="approvalListBody">
                    </tbody>
            </table>
        </div>
    </aside>

    <main class="right-panel">
        <div class="viewer-toolbar">
            <span>보고서 미리보기</span>
            <button class="btn" onclick="zoom(0.1)">확대 +</button>
            <button class="btn" onclick="zoom(-0.1)">축소 -</button>
            <button class="btn" onclick="zoom(0, true)">100%</button>
        </div>
        <div class="report-container">
            <div id="reportPaper" class="report-paper">
                <div class="report-content">
                    <h2>기 안 용 지</h2>
                    <p><strong>발신:</strong> IT개발부</p>
                    <p><strong>제목:</strong> 결재 시스템 팝업 UI 개발의 건</p>
                    <hr>
                    <p>1. 개요: 결재선의 효율적인 관리를 위한 좌우 분할 방식의 팝업창을 구성함.</p>
                    <p>2. 주요기능:</p>
                    <ul>
                        <li>트리 구조 조직도 연동</li>
                        <li>결재자 추가/삭제 기능</li>
                        <li>보고서 확대/축소(Scale) 기능</li>
                    </ul>
                    <div style="margin-top: 50px; border: 1px solid #eee; height: 200px; padding: 10px;">
                        상기 내용과 같이 보고하오니 검토 후 재가 바랍니다.
                    </div>
                </div>
            </div>
        </div>
    </main>
</div>

<script>
    // --- 결재자 관리 로직 ---
    let selectedUser = null;
    const approvalList = [];

    // 조직도에서 사용자 클릭 이벤트
    document.getElementById('orgTree').addEventListener('click', function(e) {
        if (e.target.classList.contains('user-item')) {
            // 선택 효과 초기화
            document.querySelectorAll('.user-item').forEach(el => el.classList.remove('active'));
            // 현재 선택 강조
            e.target.classList.add('active');
            
            selectedUser = {
                id: e.target.dataset.id,
                name: e.target.dataset.name,
                pos: e.target.dataset.pos
            };
        }
    });

    // 결재선에 추가
    function addApprover() {
        if (!selectedUser) {
            alert("조직도에서 인원을 선택해주세요.");
            return;
        }
        // 중복 체크
        if (approvalList.find(u => u.id === selectedUser.id)) {
            alert("이미 추가된 인원입니다.");
            return;
        }

        approvalList.push({...selectedUser});
        renderApprovalList();
    }

    // 마지막 결재자 삭제
    function removeApprover() {
        approvalList.pop();
        renderApprovalList();
    }

    // 테이블 렌더링
    function renderApprovalList() {
        const tbody = document.getElementById('approvalListBody');
        tbody.innerHTML = approvalList.map((user, index) => `
            <tr>
                <td>${index + 1}</td>
                <td>${user.name}</td>
                <td>${user.pos}</td>
            </tr>
        `).join('');
    }

    // --- 확대/축소 로직 ---
    let currentScale = 1.0;
    const paper = document.getElementById('reportPaper');

    function zoom(delta, reset = false) {
        if (reset) {
            currentScale = 1.0;
        } else {
            currentScale += delta;
        }
        
        // 최소/최대 제한
        if (currentScale < 0.5) currentScale = 0.5;
        if (currentScale > 2.0) currentScale = 2.0;
        
        paper.style.transform = `scale(${currentScale})`;
    }
</script>

</body>
</html>
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2026/03   »
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
글 보관함