feat: 관리자 대시보드 사용자 모달에 반려동물 탭 추가
- /admin/user/<id> API에 pets 데이터 추가
- 사용자 상세 모달에 🐾 반려동물 탭 추가
- 반려동물 사진, 이름, 종류, 품종, 성별, 등록일 표시
This commit is contained in:
parent
1cebb02ec6
commit
52a4f69abc
@ -1621,7 +1621,38 @@ def admin_user_detail(user_id):
|
||||
except Exception as interest_error:
|
||||
logging.warning(f"관심상품 조회 실패 (user {user_id}): {interest_error}")
|
||||
|
||||
# 8. 응답 생성
|
||||
# 8. 반려동물 조회
|
||||
pets = []
|
||||
try:
|
||||
cursor.execute("""
|
||||
SELECT id, name, species, breed, gender, birth_date, age_months,
|
||||
weight, photo_url, notes, created_at
|
||||
FROM pets
|
||||
WHERE user_id = ? AND is_active = TRUE
|
||||
ORDER BY created_at DESC
|
||||
""", (user_id,))
|
||||
for row in cursor.fetchall():
|
||||
species_label = '강아지 🐕' if row['species'] == 'dog' else ('고양이 🐈' if row['species'] == 'cat' else '기타')
|
||||
gender_label = '♂ 남아' if row['gender'] == 'male' else ('♀ 여아' if row['gender'] == 'female' else '')
|
||||
pets.append({
|
||||
'id': row['id'],
|
||||
'name': row['name'],
|
||||
'species': row['species'],
|
||||
'species_label': species_label,
|
||||
'breed': row['breed'],
|
||||
'gender': row['gender'],
|
||||
'gender_label': gender_label,
|
||||
'birth_date': row['birth_date'],
|
||||
'age_months': row['age_months'],
|
||||
'weight': float(row['weight']) if row['weight'] else None,
|
||||
'photo_url': row['photo_url'],
|
||||
'notes': row['notes'],
|
||||
'created_at': utc_to_kst_str(row['created_at'])
|
||||
})
|
||||
except Exception as pet_error:
|
||||
logging.warning(f"반려동물 조회 실패 (user {user_id}): {pet_error}")
|
||||
|
||||
# 9. 응답 생성
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'user': {
|
||||
@ -1647,7 +1678,8 @@ def admin_user_detail(user_id):
|
||||
'purchases': purchases,
|
||||
'prescriptions': prescriptions,
|
||||
'pos_customer': pos_customer,
|
||||
'interests': interests
|
||||
'interests': interests,
|
||||
'pets': pets
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
|
||||
BIN
backend/static/uploads/pets/pet_2_9919f990.jpg
Normal file
BIN
backend/static/uploads/pets/pet_2_9919f990.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
backend/static/uploads/pets/pet_3_53b73509.png
Normal file
BIN
backend/static/uploads/pets/pet_3_53b73509.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 MiB |
@ -913,6 +913,9 @@
|
||||
<button onclick="switchTab('interests')" id="tab-interests" class="tab-btn" style="padding: 12px 20px; border: none; background: none; font-size: 15px; font-weight: 600; cursor: pointer; border-bottom: 3px solid transparent; color: #868e96;">
|
||||
💝 관심 (${data.interests ? data.interests.length : 0})
|
||||
</button>
|
||||
<button onclick="switchTab('pets')" id="tab-pets" class="tab-btn" style="padding: 12px 20px; border: none; background: none; font-size: 15px; font-weight: 600; cursor: pointer; border-bottom: 3px solid transparent; color: #868e96;">
|
||||
🐾 반려동물 (${data.pets ? data.pets.length : 0})
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 정렬 버튼 (구매 이력용) -->
|
||||
@ -1070,6 +1073,53 @@
|
||||
html += '<p style="text-align: center; padding: 40px; color: #868e96;">💝 관심 상품이 없습니다<br><small>마일리지 적립 시 AI 추천에서 "관심있어요"를 누르면 여기에 표시됩니다</small></p>';
|
||||
}
|
||||
|
||||
html += `
|
||||
</div>
|
||||
|
||||
<!-- 반려동물 탭 -->
|
||||
<div id="tab-content-pets" class="tab-content" style="display: none;">
|
||||
`;
|
||||
|
||||
// 반려동물 렌더링
|
||||
const pets = data.pets || [];
|
||||
if (pets.length > 0) {
|
||||
html += '<div style="display: grid; gap: 16px;">';
|
||||
pets.forEach(pet => {
|
||||
const photoHtml = pet.photo_url
|
||||
? `<img src="${pet.photo_url}" alt="${pet.name}" style="width: 80px; height: 80px; border-radius: 50%; object-fit: cover;">`
|
||||
: `<div style="width: 80px; height: 80px; border-radius: 50%; background: linear-gradient(135deg, #fbbf24, #f59e0b); display: flex; align-items: center; justify-content: center; font-size: 36px;">${pet.species === 'dog' ? '🐕' : (pet.species === 'cat' ? '🐈' : '🐾')}</div>`;
|
||||
|
||||
html += `
|
||||
<div style="border: 1px solid #e9ecef; border-radius: 16px; padding: 20px; display: flex; gap: 20px; align-items: center; border-left: 4px solid #f59e0b;">
|
||||
<div style="flex-shrink: 0;">
|
||||
${photoHtml}
|
||||
</div>
|
||||
<div style="flex: 1;">
|
||||
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 8px;">
|
||||
<span style="font-size: 20px; font-weight: 700; color: #212529;">${pet.name}</span>
|
||||
<span style="background: ${pet.species === 'dog' ? '#dbeafe' : '#fce7f3'}; color: ${pet.species === 'dog' ? '#1e40af' : '#9d174d'}; font-size: 12px; font-weight: 600; padding: 4px 10px; border-radius: 20px;">
|
||||
${pet.species_label}
|
||||
</span>
|
||||
</div>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 12px; font-size: 14px; color: #6b7280;">
|
||||
${pet.breed ? `<span>🏷️ ${pet.breed}</span>` : ''}
|
||||
${pet.gender_label ? `<span>${pet.gender_label}</span>` : ''}
|
||||
${pet.weight ? `<span>⚖️ ${pet.weight}kg</span>` : ''}
|
||||
${pet.age_months ? `<span>🎂 ${pet.age_months}개월</span>` : ''}
|
||||
</div>
|
||||
${pet.notes ? `<div style="margin-top: 8px; font-size: 13px; color: #9ca3af; background: #f9fafb; padding: 8px 12px; border-radius: 8px;">📝 ${pet.notes}</div>` : ''}
|
||||
<div style="margin-top: 10px; font-size: 12px; color: #d1d5db;">
|
||||
등록일: ${pet.created_at}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
html += '</div>';
|
||||
} else {
|
||||
html += '<p style="text-align: center; padding: 40px; color: #868e96;">🐾 등록된 반려동물이 없습니다<br><small>고객이 마이페이지에서 반려동물을 등록하면 여기에 표시됩니다</small></p>';
|
||||
}
|
||||
|
||||
html += `
|
||||
</div>
|
||||
`;
|
||||
@ -1727,6 +1777,13 @@
|
||||
// KIMS 약물 상호작용 체크
|
||||
// ═══════════════════════════════════════════════════
|
||||
|
||||
function escapeHtml(text) {
|
||||
if (!text) return '';
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
async function checkDrugInteraction(drugCodes, preSerial) {
|
||||
// drugCodes가 문자열로 넘어올 수 있음
|
||||
if (typeof drugCodes === 'string') {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user