feat: 어드민 집계 페이지에 반려동물 통계 추가

통계 카드:
- 등록 반려동물 총 수
- 강아지/고양이 종류별 수
- 노란색 그라데이션 카드 스타일

최근 등록 반려동물 섹션:
- 최근 10마리 반려동물 카드
- 사진 + 이름 + 품종 + 보호자 정보
- 보호자 전화번호 마스킹 처리
This commit is contained in:
thug0bin 2026-03-02 16:37:25 +09:00
parent a7b3d5b7e0
commit c525632246
2 changed files with 68 additions and 1 deletions

View File

@ -2208,6 +2208,35 @@ def admin():
FROM claim_tokens
""")
token_stats = cursor.fetchone()
# 반려동물 통계
cursor.execute("""
SELECT
COUNT(*) as total_pets,
SUM(CASE WHEN species = 'dog' THEN 1 ELSE 0 END) as dog_count,
SUM(CASE WHEN species = 'cat' THEN 1 ELSE 0 END) as cat_count,
COUNT(DISTINCT user_id) as owners_count
FROM pets
WHERE is_active = 1
""")
pet_stats = cursor.fetchone()
# 최근 등록 반려동물 (10마리)
cursor.execute("""
SELECT p.id, p.name, p.species, p.breed, p.photo_url, p.created_at,
u.nickname as owner_name, u.phone as owner_phone
FROM pets p
JOIN users u ON p.user_id = u.id
WHERE p.is_active = 1
ORDER BY p.created_at DESC
LIMIT 10
""")
recent_pets_raw = cursor.fetchall()
recent_pets = []
for pet in recent_pets_raw:
pet_dict = dict(pet)
pet_dict['created_at'] = utc_to_kst_str(pet['created_at'])
recent_pets.append(pet_dict)
# 최근 QR 발행 내역 (20건)
cursor.execute("""
@ -2237,7 +2266,9 @@ def admin():
recent_users=recent_users,
recent_transactions=recent_transactions,
token_stats=token_stats,
recent_tokens=recent_tokens)
recent_tokens=recent_tokens,
pet_stats=pet_stats,
recent_pets=recent_pets)
# ============================================================================

View File

@ -457,8 +457,44 @@
{% endif %}
</div>
</div>
<div class="stat-card" style="background: linear-gradient(135deg, #fef3c7, #fde68a);">
<div class="stat-label" style="color: #92400e;">🐾 등록 반려동물</div>
<div class="stat-value" style="color: #92400e;">
{{ pet_stats.total_pets or 0 }}마리
<span style="font-size: 14px; font-weight: 500; margin-left: 8px;">
(🐕 {{ pet_stats.dog_count or 0 }} / 🐈 {{ pet_stats.cat_count or 0 }})
</span>
</div>
</div>
</div>
<!-- 최근 등록 반려동물 -->
{% if recent_pets %}
<div class="section">
<div class="section-title">🐾 최근 등록 반려동물 (10마리)</div>
<div style="display: flex; flex-wrap: wrap; gap: 12px;">
{% for pet in recent_pets %}
<div style="display: flex; align-items: center; gap: 12px; padding: 12px 16px; background: linear-gradient(135deg, #fef3c7, #fde68a); border-radius: 14px; min-width: 220px;">
{% if pet.photo_url %}
<img src="{{ pet.photo_url }}" style="width: 48px; height: 48px; border-radius: 50%; object-fit: cover; border: 2px solid #fff; box-shadow: 0 2px 6px rgba(0,0,0,0.15);">
{% else %}
<div style="width: 48px; height: 48px; border-radius: 50%; background: #fff; display: flex; align-items: center; justify-content: center; font-size: 24px; box-shadow: 0 2px 6px rgba(0,0,0,0.1);">
{% if pet.species == 'dog' %}🐕{% elif pet.species == 'cat' %}🐈{% else %}🐾{% endif %}
</div>
{% endif %}
<div>
<div style="font-weight: 700; font-size: 15px; color: #92400e;">
{% if pet.species == 'dog' %}🐕{% elif pet.species == 'cat' %}🐈{% else %}🐾{% endif %} {{ pet.name }}
</div>
<div style="font-size: 12px; color: #a16207;">{{ pet.breed or '품종 미등록' }}</div>
<div style="font-size: 11px; color: #b45309; margin-top: 2px;">{{ pet.owner_name }} ({{ pet.owner_phone[:3] }}-****-{{ pet.owner_phone[-4:] }})</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
<!-- 최근 가입 사용자 -->
<div class="section">
<div class="section-title">최근 가입 사용자 (20명)</div>