# 출석 조회 화면 신규회원 탭 개선 완료 ## 요청 사항 1. **신규회원 탭 데이터 표시 개선** - 신규회원 탭도 출석현황처럼 데이터를 보여주기 - 신규회원 리스트를 출석순으로 나열 2. **기본 탭 변경** - 현재: 출석현황 탭이 기본 선택 - 변경: 대기 현황 탭이 기본 선택되도록 ## 수정 내용 ### 1. 백엔드 API 수정 - [routers/attendance.py](routers/attendance.py:310-360) #### `/api/attendance/new-members` 엔드포인트 개선 **Before (기존):** ```python # 가입일 기준 정렬 new_members = db.query(Member).filter(...).order_by(desc(Member.created_at)).all() # 최초 출석일만 조회 for member in new_members: first_attendance = db.query(WaitingList).filter(...).first() result.append({ "name": member.name, "phone": member.phone, "joined_at": member.created_at.strftime("%Y-%m-%d"), "first_attendance": first_attendance.attended_at.strftime("%Y-%m-%d") if first_attendance else None }) return { "count": len(new_members), "members": result } ``` **After (개선):** ```python # 가입일 필터링만 (정렬은 나중에) new_members = db.query(Member).filter(...).all() result = [] total_attendance = 0 for member in new_members: # ✅ 출석 횟수 조회 attendance_count = db.query(func.count(WaitingList.id)).filter( WaitingList.member_id == member.id, WaitingList.status == 'attended' ).scalar() or 0 # 최초 출석일 조회 first_attendance = db.query(WaitingList).filter(...).first() # ✅ 최근 출석일 조회 last_attendance = db.query(WaitingList).filter( WaitingList.member_id == member.id, WaitingList.status == 'attended' ).order_by(desc(WaitingList.attended_at)).first() total_attendance += attendance_count result.append({ "name": member.name, "phone": member.phone, "joined_at": member.created_at.strftime("%Y-%m-%d"), "first_attendance": first_attendance.attended_at.strftime("%Y-%m-%d") if first_attendance else None, "last_attendance": last_attendance.attended_at.strftime("%Y-%m-%d") if last_attendance else None, "attendance_count": attendance_count # ✅ 출석 횟수 추가 }) # ✅ 출석순으로 정렬 (출석 횟수가 많은 순) result.sort(key=lambda x: x['attendance_count'], reverse=True) # ✅ 평균 출석 횟수 계산 avg_attendance = round(total_attendance / len(new_members), 1) if new_members else 0 return { "count": len(new_members), "total_attendance": total_attendance, # ✅ 총 출석 횟수 "avg_attendance": avg_attendance, # ✅ 평균 출석 횟수 "members": result } ``` **주요 개선 사항:** - ✅ 각 회원의 **출석 횟수** 조회 및 반환 - ✅ 각 회원의 **최근 출석일** 조회 및 반환 - ✅ **출석순으로 정렬** (출석 횟수 내림차순) - ✅ **총 출석 횟수** 계산 및 반환 - ✅ **평균 출석 횟수** 계산 및 반환 ### 2. 프론트엔드 수정 - [templates/attendance.html](templates/attendance.html) #### 2-1. 통계 카드 추가 (lines 331-344) **Before:** ```html
신규 가입 회원
0명
``` **After:** ```html
신규 가입 회원
0명
총 출석 횟수
0회
평균 출석 횟수
0회
``` #### 2-2. 테이블 구조 변경 (lines 346-361) **Before:** ```html
가입일시 이름 전화번호 최초 출석일
``` **After:** ```html
순위 이름 전화번호 출석 횟수 가입일 최초 출석일 최근 출석일
``` #### 2-3. loadNewMembers() 함수 개선 (lines 658-693) **Before:** ```javascript async function loadNewMembers() { const period = document.getElementById('newMemberPeriod').value; const date = document.getElementById('newMemberDate').value; const response = await fetch(`/api/attendance/new-members?period=${period}&date=${date}`, { headers: getHeaders() }); const data = await response.json(); document.getElementById('newMemberCount').textContent = `${data.count}명`; const tbody = document.getElementById('newMemberList'); tbody.innerHTML = data.members.map(m => ` ${m.joined_at} ${m.name} ${m.phone} ${m.first_attendance || '-'} `).join(''); } ``` **After:** ```javascript async function loadNewMembers() { const period = document.getElementById('newMemberPeriod').value; const date = document.getElementById('newMemberDate').value; const response = await fetch(`/api/attendance/new-members?period=${period}&date=${date}`, { headers: getHeaders() }); const data = await response.json(); // ✅ 통계 데이터 표시 document.getElementById('newMemberCount').textContent = `${data.count}명`; document.getElementById('newMemberTotalAttendance').textContent = `${data.total_attendance}회`; document.getElementById('newMemberAvgAttendance').textContent = `${data.avg_attendance}회`; const tbody = document.getElementById('newMemberList'); tbody.innerHTML = data.members.map((m, index) => { // ✅ 순위 배지 스타일 적용 let rankClass = 'rank-other'; if (index === 0) rankClass = 'rank-1'; if (index === 1) rankClass = 'rank-2'; if (index === 2) rankClass = 'rank-3'; return ` ${index + 1} ${m.name} ${m.phone} ${m.attendance_count}회 ${m.joined_at} ${m.first_attendance || '-'} ${m.last_attendance || '-'} `; }).join(''); } ``` #### 2-4. 기본 탭 변경 (lines 169, 177, 221) **탭 버튼 (line 169):** ```html ``` **탭 컨텐츠 (lines 177, 221):** ```html
``` ## 변경 사항 요약 ### 신규회원 탭 개선 | 항목 | Before | After | |------|--------|-------| | **통계 카드** | 신규 가입 회원 수만 표시 | 신규 가입 회원, 총 출석 횟수, 평균 출석 횟수 표시 | | **테이블 컬럼** | 가입일시, 이름, 전화번호, 최초 출석일 | 순위, 이름, 전화번호, 출석 횟수, 가입일, 최초 출석일, 최근 출석일 | | **정렬 기준** | 가입일 기준 (최신순) | **출석 횟수 기준 (많은 순)** ✅ | | **순위 표시** | 없음 | 1-3위는 금/은/동 배지, 나머지는 일반 배지 | ### 기본 탭 변경 | 항목 | Before | After | |------|--------|-------| | **기본 선택 탭** | 출석현황 | **대기 현황** ✅ | ## 결과 ### 신규회원 탭 화면 **통계 표시:** ``` ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │ 신규 가입 회원 │ │ 총 출석 횟수 │ │ 평균 출석 횟수 │ │ 15명 │ │ 45회 │ │ 3.0회 │ └────────────────┘ └────────────────┘ └────────────────┘ ``` **리스트 표시 (출석순 정렬):** ``` ┌────┬────────┬──────────────┬──────────┬────────────┬──────────────┬──────────────┐ │순위│ 이름 │ 전화번호 │출석 횟수 │ 가입일 │ 최초 출석일 │ 최근 출석일 │ ├────┼────────┼──────────────┼──────────┼────────────┼──────────────┼──────────────┤ │ 🥇 │ 홍길동 │ 010-1234-5678│ 10회 │ 2025-11-01 │ 2025-11-02 │ 2025-12-03 │ │ 🥈 │ 김철수 │ 010-2345-6789│ 8회 │ 2025-11-05 │ 2025-11-06 │ 2025-12-01 │ │ 🥉 │ 이영희 │ 010-3456-7890│ 7회 │ 2025-11-10 │ 2025-11-11 │ 2025-11-30 │ │ 4 │ 박민수 │ 010-4567-8901│ 5회 │ 2025-11-15 │ 2025-11-16 │ 2025-11-28 │ │ 5 │ 최지은 │ 010-5678-9012│ 3회 │ 2025-11-20 │ 2025-11-21 │ 2025-11-25 │ └────┴────────┴──────────────┴──────────┴────────────┴──────────────┴──────────────┘ ``` ### 기본 탭 화면 진입 시 **대기 현황 탭**이 자동으로 선택됩니다. ``` ┌────────────────────────────────────────────────────┐ │ [대기현황*] [출석현황] [개인별 출석] [신규회원] [출석순위] │ └────────────────────────────────────────────────────┘ ``` ## 영향 범위 ### 수정된 파일 1. ✅ `routers/attendance.py` - `/api/attendance/new-members` 엔드포인트 2. ✅ `templates/attendance.html` - 신규회원 탭 UI 및 기본 탭 설정 ### 영향받는 기능 - ✅ 출석 조회 > 신규회원 탭 - 통계 데이터 표시 - 출석순 정렬 - 순위 배지 표시 - ✅ 출석 조회 화면 진입 시 기본 탭 ### 영향받지 않는 기능 - ✅ 대기 현황 탭 - ✅ 출석현황 탭 - ✅ 개인별 출석 탭 - ✅ 출석순위 탭 ## 결론 **신규회원 탭이 출석현황 탭처럼 풍부한 데이터를 보여줍니다:** 1. ✅ 통계 카드 3개 표시 (신규 회원 수, 총 출석, 평균 출석) 2. ✅ 출석순으로 정렬 (출석 횟수가 많은 순) 3. ✅ 순위 표시 (1-3위는 금/은/동 배지) 4. ✅ 상세 정보 표시 (출석 횟수, 가입일, 최초/최근 출석일) 5. ✅ 기본 탭이 "대기 현황"으로 변경 **신규회원의 출석 활동을 한눈에 파악할 수 있습니다!**