티스토리 뷰
결재팝업_체크선택_직속 상관부터 최하단 파트원까지.html
0.01MB
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>전단계 결재자 포함 조직도</title>
<style>
/* (기존 스타일 유지 및 일부 최적화) */
:root { --primary: #007bff; --bg: #f4f7f9; --border: #ced4da; }
body { margin: 0; font-family: 'Malgun Gothic', sans-serif; background: var(--bg); display: flex; justify-content: center; align-items: center; height: 100vh; }
.popup { width: 1100px; height: 850px; background: #fff; display: flex; box-shadow: 0 10px 25px rgba(0,0,0,0.1); border-radius: 8px; overflow: hidden; }
.left-panel { width: 420px; border-right: 1px solid var(--border); display: flex; flex-direction: column; }
.panel-title { padding: 12px; background: #f8f9fa; font-weight: bold; font-size: 14px; border-bottom: 1px solid var(--border); }
.tree-container { flex: 1; overflow-y: auto; padding: 15px; background: #fff; }
ul { list-style: none; padding-left: 20px; margin: 5px 0; border-left: 1px dotted #ccc; }
.tree-item { display: flex; align-items: center; gap: 8px; padding: 4px 0; }
.toggle-btn { width: 16px; cursor: pointer; font-weight: bold; color: #666; font-size: 16px; }
.nested { display: none; }
.active { display: block; }
input[type="checkbox"] { cursor: pointer; }
.user-node { background: #f9f9f9; border-radius: 4px; margin: 2px 0; }
.user-node label { color: #2c3e50; font-weight: normal; }
.dept-label { font-weight: bold; color: #333; cursor: pointer; }
/* 버튼 및 테이블 스타일 */
.controls { padding: 15px; text-align: center; background: #f1f3f5; border-top: 1px solid #ddd; }
.btn { padding: 8px 20px; cursor: pointer; border: 1px solid var(--border); background: #fff; border-radius: 4px; font-weight: bold; }
.btn-primary { background: var(--primary); color: white; border-color: var(--primary); }
.list-container { height: 220px; overflow-y: auto; padding: 10px; }
table { width: 100%; border-collapse: collapse; font-size: 12px; }
th, td { border: 1px solid #eee; padding: 8px; text-align: center; }
/* 오른쪽 패널 */
.right-panel { flex: 1; display: flex; flex-direction: column; background: #525659; }
.toolbar { padding: 10px; background: #333; color: white; display: flex; gap: 10px; align-items: center; }
.paper { background: white; width: 500px; min-height: 650px; padding: 40px; margin: 40px auto; transform-origin: top center; transition: 0.2s; }
</style>
</head>
<body>
<div class="popup">
<aside class="left-panel">
<div class="panel-title">🏢 전단계 결재자 포함 조직도</div>
<div class="tree-container" id="orgTree">
<ul>
<li>
<div class="tree-item">
<span class="toggle-btn" onclick="toggleNode(this)">-</span>
<input type="checkbox" class="dept-check">
<label class="dept-label">(주)글로벌네트워크</label>
</div>
<ul class="nested active">
<li class="tree-item user-node"><input type="checkbox" class="user-check" data-name="김회장" data-rank="대표이사"><label>👤 김회장 대표이사</label></li>
<li>
<div class="tree-item">
<span class="toggle-btn" onclick="toggleNode(this)">+</span>
<input type="checkbox" class="dept-check">
<label class="dept-label">기술개발본부</label>
</div>
<ul class="nested">
<li class="tree-item user-node"><input type="checkbox" class="user-check" data-name="이본부" data-rank="본부장"><label>👤 이본부 본부장</label></li>
<li>
<div class="tree-item">
<span class="toggle-btn" onclick="toggleNode(this)">+</span>
<input type="checkbox" class="dept-check">
<label class="dept-label">플랫폼개발팀</label>
</div>
<ul class="nested">
<li class="tree-item user-node"><input type="checkbox" class="user-check" data-name="박팀장" data-rank="팀장"><label>👤 박팀장 팀장</label></li>
<li>
<div class="tree-item">
<span class="toggle-btn" onclick="toggleNode(this)">+</span>
<input type="checkbox" class="dept-check">
<label class="dept-label">백엔드파트</label>
</div>
<ul class="nested">
<li class="tree-item user-node"><input type="checkbox" class="user-check" data-name="최파트" data-rank="파트장"><label>👤 최파트 파트장</label></li>
<li class="tree-item user-node"><input type="checkbox" class="user-check" data-name="정개발" data-rank="사원"><label>👤 정개발 사원</label></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<div class="controls">
<button class="btn btn-primary" onclick="addSelected()">결재선 추가 ▼</button>
<button class="btn" onclick="clearList()">초기화</button>
</div>
<div class="panel-title">결재선 명단</div>
<div class="list-container">
<table>
<thead>
<tr><th>순서</th><th>이름</th><th>직급</th><th>삭제</th></tr>
</thead>
<tbody id="approvalTable"></tbody>
</table>
</div>
</aside>
<main class="right-panel">
<div class="toolbar">
<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="viewer">
<div id="paper" class="paper">
<h2>전단계 결재자 포함 UI</h2>
<p>각 부서(본부, 팀, 파트) 바로 아래에 소속 결재자가 배치되어 있습니다.</p>
<p>상위 부서 체크 시 하위 부서원과 하위 조직이 모두 선택됩니다.</p>
</div>
</div>
</main>
</div>
<script>
// 1. 트리 토글
function toggleNode(btn) {
const nestedUl = btn.closest('li').querySelector('.nested');
if (nestedUl) {
nestedUl.classList.toggle('active');
btn.textContent = nestedUl.classList.contains('active') ? '-' : '+';
}
}
// 2. 부서 체크 시 하위 모든 요소(사람+하위부서) 선택
document.addEventListener('change', function(e) {
if (e.target.classList.contains('dept-check')) {
const parentLi = e.target.closest('li');
const allChildCheckboxes = parentLi.querySelectorAll('input[type="checkbox"]');
allChildCheckboxes.forEach(cb => cb.checked = e.target.checked);
}
});
// 3. 결재선 추가 로직
let approvalList = [];
function addSelected() {
const userCheckboxes = document.querySelectorAll('.user-check:checked');
userCheckboxes.forEach(cb => {
const name = cb.getAttribute('data-name');
const rank = cb.getAttribute('data-rank');
if (!approvalList.some(u => u.name === name)) {
approvalList.push({ name, rank });
}
});
document.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = false);
renderTable();
}
function renderTable() {
const tbody = document.getElementById('approvalTable');
tbody.innerHTML = approvalList.map((user, i) => `
<tr><td>${i + 1}</td><td>${user.name}</td><td>${user.rank}</td><td><button onclick="removeItem(${i})">x</button></td></tr>
`).join('');
}
function removeItem(index) {
approvalList.splice(index, 1);
renderTable();
}
function clearList() {
approvalList = [];
renderTable();
}
// 4. 확대/축소
let currentScale = 1.0;
function zoom(delta, reset = false) {
currentScale = reset ? 1.0 : currentScale + delta;
document.getElementById('paper').style.transform = `scale(${currentScale})`;
}
</script>
</body>
</html>'WEB > JavaScript' 카테고리의 다른 글
| 결재팝업 결재자 체크 선택 펼침 포함 (0) | 2026.03.05 |
|---|---|
| 결재선 지정 선택 팝업 (0) | 2026.03.05 |
| 6주 카테고리 달력 (0) | 2026.03.04 |
| 카테고리 기능이 추가된 달력 스크립트 (년/월 이동 + 오늘 일정 자동 표시) (0) | 2026.03.03 |
| 통합 달력 스크립트 (년/월 이동 + 오늘 일정 자동 표시) (0) | 2026.03.03 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- ajax
- 정보처리기사 #정보처리기사요약 #정보처리기사요점정리
- 자바스크립트break
- 무료폰트 #무료웹폰트 #한수원한돋움 #한수원한울림 #한울림체 #한돋움체
- jQuery #jQuery이미지슬라이드 #이미지슬라이드
- sw기술자평균임금 #2025년 sw기술자 평균임금
- css미디어쿼리 #미디어쿼리 #mediaquery
- 광주분식 #광주분식맛집 #상추튀김 #상추튀김맛집 #광주상추튀김
- iptime와이파이증폭기 #와이파이증폭기설치
- echart
- 자바스크립트정규표현식
- 파비콘사이즈
- 자바스크립트countiue
- 테스크탑무선랜카드 #무선랜카드 #아이피타이무선랜카드 #a3000mini #무선랜카드추천
- 썬크림 #닥터지썬크림 #내돈내산 #내돈내산썬크림 #썬크림추천 #spf50썬크림 #닥터지메디유브이울트라선
- 바지락칼국수 #월곡동칼국수 #칼국수맛집
- 좋은책 #밥프록터 #부의원리
- SQL명령어 #SQL
- 파비콘 #파비콘 사이트에 적용
- lg그램pro #lg그램 #노트북 #노트북추천 #lg노트북
- jdk #jre
- 와이파이증폭기추천 #와이파이설치
- 연명의료결정제도 #사전연명의료의향서 #사전연명의료의향서등록기관 #광주사전연명의료의향서
- thymeleaf
- // 사진직: 데이터가 없으면 DEFAULT_IMG 사용 const profileSrc = (d.img && d.img !== "") ? d.img : DEFAULT_IMG;('#user-photo').attr('src'
- 쇼팬하우어 #좋은책
- 탭메뉴자바스크립트
- 자바스크립트 #javascript #math
- 좋은책
- 증폭기 #아이피타임증폭기
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
글 보관함

