From d715b630fe1078523ea2f3cfae8a080bc1753a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=8B=9C=EA=B3=A8=EC=95=BD=EC=82=AC?= Date: Fri, 23 Jan 2026 22:06:47 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B5=AC=EB=A7=A4=EC=9D=B4=EB=A0=A5=20?= =?UTF-8?q?=EC=A0=95=EB=A0=AC=20=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20=EC=83=81?= =?UTF-8?q?=ED=92=88=EA=B2=80=EC=83=89=20=EC=8B=9C=EA=B0=84=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 관리자 페이지 사용자 상세 모달에 날짜별/금액별 정렬 버튼 추가 - 구매 이력 정렬 기능 구현 (날짜순/금액순) - 상품 검색 결과에 구매일시/적립일시 모두 표시 주요 변경사항: 1. 구매 이력 정렬 기능 (admin.html) - 날짜별 정렬: 최신순 정렬 - 금액별 정렬: 구매금액 높은 순 정렬 - 정렬 버튼 UI: 우측 정렬, 토글 방식 - 탭 전환 시 정렬 버튼 자동 표시/숨김 2. 상품 검색 시간 표시 개선 (app.py, admin.html) - 구매일시: MSSQL InsertTime (실제 거래 시간) - 적립일시: SQLite claimed_at (QR 적립 시간) - 두 시간 모두 테이블에 표시 (구분 명확화) 3. UI/UX 개선 - 정렬 버튼 스타일: search-type-btn과 동일한 패턴 - 적립일시: 회색(#868e96)으로 구매일시와 시각적 구분 - 정렬 상태 유지: 버튼 클릭 시 active 클래스 토글 기술 구현: - renderPurchaseHistory() 함수로 구매 이력 동적 렌더링 - sortPurchases(type) 함수로 정렬 로직 처리 - 전역 변수로 현재 사용자 데이터 및 정렬 타입 관리 - JavaScript 배열 복사 후 정렬하여 원본 데이터 보존 Co-Authored-By: Claude Sonnet 4.5 --- backend/app.py | 3 +- backend/templates/admin.html | 176 ++++++++++++++++++++++++++--------- 2 files changed, 133 insertions(+), 46 deletions(-) diff --git a/backend/app.py b/backend/app.py index a7ba557..69651c3 100644 --- a/backend/app.py +++ b/backend/app.py @@ -807,7 +807,8 @@ def admin_search_product(): 'user_id': claim_row['claimed_by_user_id'], 'user_name': claim_row['nickname'], 'user_phone': claim_row['phone'], - 'purchase_date': claim_row['claimed_at'][:16].replace('T', ' ') if claim_row['claimed_at'] else '-', + 'purchase_date': str(mssql_row.InsertTime)[:16].replace('T', ' ') if mssql_row.InsertTime else '-', # MSSQL 실제 거래 시간 + 'claimed_date': str(claim_row['claimed_at'])[:16].replace('T', ' ') if claim_row['claimed_at'] else '-', # 적립 시간 'quantity': float(mssql_row.SL_NM_item or 0), 'total_amount': int(claim_row['total_amount']) }) diff --git a/backend/templates/admin.html b/backend/templates/admin.html index 4453979..54499d1 100644 --- a/backend/templates/admin.html +++ b/backend/templates/admin.html @@ -254,6 +254,28 @@ color: #6366f1; } + .sort-btn { + padding: 8px 16px; + border: 2px solid #e9ecef; + background: #fff; + border-radius: 8px; + cursor: pointer; + font-size: 13px; + font-weight: 600; + color: #868e96; + transition: all 0.2s; + } + + .sort-btn:hover { + border-color: #ced4da; + } + + .sort-btn.active { + border-color: #6366f1; + background: #f8f9ff; + color: #6366f1; + } + .search-input-wrapper { position: relative; } @@ -709,7 +731,14 @@ // ===== 사용자 상세 모달 함수 ===== + // 전역 변수: 현재 사용자 데이터 저장 + let currentUserData = null; + let currentSortType = 'date'; // 'date' 또는 'amount' + function showUserDetail(userId) { + // 정렬 타입 초기화 + currentSortType = 'date'; + document.getElementById('userDetailModal').style.display = 'block'; document.getElementById('userDetailContent').innerHTML = '
불러오는 중...
'; @@ -742,6 +771,9 @@ } function renderUserDetail(data) { + // 전역 변수에 데이터 저장 + currentUserData = data; + const user = data.user; const mileageHistory = data.mileage_history; const purchases = data.purchases; @@ -784,11 +816,89 @@ + +
+ + +
+
+
+
+ + + + `; + + document.getElementById('userDetailContent').innerHTML = html; + + // 구매 이력 렌더링 (정렬 적용) + renderPurchaseHistory(); + } + + function renderPurchaseHistory() { + if (!currentUserData) return; + + const purchases = [...currentUserData.purchases]; // 복사본 생성 + + // 정렬 적용 + if (currentSortType === 'date') { + // 날짜별 정렬 (최신순) + purchases.sort((a, b) => { + const dateA = new Date(a.date); + const dateB = new Date(b.date); + return dateB - dateA; + }); + } else if (currentSortType === 'amount') { + // 금액별 정렬 (높은 순) + purchases.sort((a, b) => b.amount - a.amount); + } + + // HTML 생성 + let html = ''; if (purchases.length > 0) { purchases.forEach((purchase, index) => { const accordionId = `accordion-${index}`; @@ -849,55 +959,23 @@ `; }); } else { - html += '

구매 이력이 없습니다.

'; + html = '

구매 이력이 없습니다.

'; } - html += ` - + document.getElementById('purchase-history-container').innerHTML = html; + } - - - `; - - document.getElementById('userDetailContent').innerHTML = html; + // 구매 이력 다시 렌더링 + renderPurchaseHistory(); } function toggleAccordion(accordionId) { @@ -931,6 +1009,12 @@ document.getElementById('tab-' + tabName).style.borderBottom = '3px solid #6366f1'; document.getElementById('tab-' + tabName).style.color = '#6366f1'; document.getElementById('tab-content-' + tabName).style.display = 'block'; + + // 정렬 버튼 표시/숨기기 (구매 이력 탭에만 표시) + const sortButtons = document.getElementById('sort-buttons'); + if (sortButtons) { + sortButtons.style.display = (tabName === 'purchases') ? 'flex' : 'none'; + } } // ===== 포인트 사용 기능 ===== @@ -1190,6 +1274,7 @@ 이름 전화번호 구매일시 + 적립일시 수량 구매금액 @@ -1203,6 +1288,7 @@ ${result.user_name} ${result.user_phone} ${result.purchase_date} + ${result.claimed_date} ${result.quantity} ${result.total_amount.toLocaleString()}원