feat: 판매내역 페이지에서 제품 이미지 등록/교체 기능 추가
- 이미지/플레이스홀더 클릭시 이미지 등록 모달 열림 - URL 입력 탭: 이미지 URL로 등록 - 촬영 탭: 카메라로 직접 촬영 (1:1 크롭 가이드) - 기존 /api/admin/product-images API 재활용 - 저장 후 자동 새로고침
This commit is contained in:
parent
b660f324ac
commit
5dd3489385
@ -380,6 +380,12 @@
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.15s, box-shadow 0.15s;
|
||||||
|
}
|
||||||
|
.product-thumb:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
box-shadow: 0 4px 12px rgba(139,92,246,0.3);
|
||||||
}
|
}
|
||||||
.product-thumb-placeholder {
|
.product-thumb-placeholder {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
@ -391,6 +397,12 @@
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border: 1px solid rgba(255,255,255,0.05);
|
border: 1px solid rgba(255,255,255,0.05);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.15s, border-color 0.15s;
|
||||||
|
}
|
||||||
|
.product-thumb-placeholder:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
border-color: var(--accent-purple);
|
||||||
}
|
}
|
||||||
.product-thumb-placeholder svg {
|
.product-thumb-placeholder svg {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
@ -398,6 +410,117 @@
|
|||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
fill: #888;
|
fill: #888;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 이미지 교체 모달 */
|
||||||
|
.image-modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0; left: 0; right: 0; bottom: 0;
|
||||||
|
background: rgba(0,0,0,0.8);
|
||||||
|
z-index: 1000;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
.image-modal.show { display: flex; }
|
||||||
|
|
||||||
|
.image-modal-content {
|
||||||
|
background: #1a1a3e;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 24px;
|
||||||
|
max-width: 450px;
|
||||||
|
width: 90%;
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid rgba(139,92,246,0.3);
|
||||||
|
}
|
||||||
|
.image-modal-content h3 {
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
color: var(--accent-purple);
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.image-modal-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.tab-btn {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid rgba(255,255,255,0.1);
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.tab-btn.active {
|
||||||
|
background: var(--accent-purple);
|
||||||
|
color: white;
|
||||||
|
border-color: var(--accent-purple);
|
||||||
|
}
|
||||||
|
.tab-content { display: none; }
|
||||||
|
.tab-content.active { display: block; }
|
||||||
|
|
||||||
|
.image-input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid rgba(255,255,255,0.1);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.image-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--accent-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.camera-container {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
background: #000;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.camera-container video,
|
||||||
|
.camera-container canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
.camera-guide {
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0; right: 0; bottom: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-btns {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.btn-modal {
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.btn-modal.secondary {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
.btn-modal.primary {
|
||||||
|
background: var(--accent-purple);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.btn-modal:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
.product-info {
|
.product-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -831,8 +954,8 @@
|
|||||||
<td>
|
<td>
|
||||||
<div class="product-cell">
|
<div class="product-cell">
|
||||||
${item.thumbnail
|
${item.thumbnail
|
||||||
? `<img src="data:image/jpeg;base64,${item.thumbnail}" class="product-thumb" alt="">`
|
? `<img src="data:image/jpeg;base64,${item.thumbnail}" class="product-thumb" onclick="openImageModal('${item.barcode || ''}', '${item.drug_code || ''}', '${escapeHtml(item.product_name)}')" alt="">`
|
||||||
: `<div class="product-thumb-placeholder"><svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zm-5-7l-3 3.72L9 13l-3 4h12l-4-5z"/></svg></div>`
|
: `<div class="product-thumb-placeholder" onclick="openImageModal('${item.barcode || ''}', '${item.drug_code || ''}', '${escapeHtml(item.product_name)}')"><svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zm-5-7l-3 3.72L9 13l-3 4h12l-4-5z"/></svg></div>`
|
||||||
}
|
}
|
||||||
<div class="product-info">
|
<div class="product-info">
|
||||||
<span class="product-name">${escapeHtml(item.product_name)}</span>
|
<span class="product-name">${escapeHtml(item.product_name)}</span>
|
||||||
@ -867,8 +990,8 @@
|
|||||||
<td>
|
<td>
|
||||||
<div class="product-cell">
|
<div class="product-cell">
|
||||||
${item.thumbnail
|
${item.thumbnail
|
||||||
? `<img src="data:image/jpeg;base64,${item.thumbnail}" class="product-thumb" alt="">`
|
? `<img src="data:image/jpeg;base64,${item.thumbnail}" class="product-thumb" onclick="openImageModal('${item.barcode || ''}', '${item.drug_code || ''}', '${escapeHtml(item.product_name)}')" alt="">`
|
||||||
: `<div class="product-thumb-placeholder"><svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zm-5-7l-3 3.72L9 13l-3 4h12l-4-5z"/></svg></div>`
|
: `<div class="product-thumb-placeholder" onclick="openImageModal('${item.barcode || ''}', '${item.drug_code || ''}', '${escapeHtml(item.product_name)}')"><svg viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V5h14v14zm-5-7l-3 3.72L9 13l-3 4h12l-4-5z"/></svg></div>`
|
||||||
}
|
}
|
||||||
<div class="product-info">
|
<div class="product-info">
|
||||||
<span class="product-name">${escapeHtml(item.product_name)}</span>
|
<span class="product-name">${escapeHtml(item.product_name)}</span>
|
||||||
@ -943,6 +1066,288 @@
|
|||||||
|
|
||||||
// 초기 로드
|
// 초기 로드
|
||||||
loadSalesData();
|
loadSalesData();
|
||||||
|
|
||||||
|
// ──────────────── 이미지 교체 모달 ────────────────
|
||||||
|
let imgModalBarcode = null;
|
||||||
|
let imgModalDrugCode = null;
|
||||||
|
let imgModalName = null;
|
||||||
|
let cameraStream = null;
|
||||||
|
let capturedImageData = null;
|
||||||
|
|
||||||
|
function openImageModal(barcode, drugCode, productName) {
|
||||||
|
// 바코드나 drug_code 중 하나는 있어야 함
|
||||||
|
if (!barcode && !drugCode) {
|
||||||
|
showToast('제품 코드 정보가 없습니다', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
imgModalBarcode = barcode || null;
|
||||||
|
imgModalDrugCode = drugCode || null;
|
||||||
|
imgModalName = productName || (barcode || drugCode);
|
||||||
|
|
||||||
|
document.getElementById('imgModalProductName').textContent = imgModalName;
|
||||||
|
document.getElementById('imgModalCode').textContent = barcode || drugCode;
|
||||||
|
document.getElementById('imgUrlInput').value = '';
|
||||||
|
|
||||||
|
// URL 탭으로 초기화
|
||||||
|
switchImageTab('url');
|
||||||
|
|
||||||
|
document.getElementById('imageModal').classList.add('show');
|
||||||
|
document.getElementById('imgUrlInput').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeImageModal() {
|
||||||
|
stopCamera();
|
||||||
|
document.getElementById('imageModal').classList.remove('show');
|
||||||
|
imgModalBarcode = null;
|
||||||
|
imgModalDrugCode = null;
|
||||||
|
imgModalName = null;
|
||||||
|
capturedImageData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchImageTab(tab) {
|
||||||
|
document.querySelectorAll('.image-modal .tab-btn').forEach(btn => {
|
||||||
|
btn.classList.toggle('active', btn.dataset.tab === tab);
|
||||||
|
});
|
||||||
|
document.querySelectorAll('.image-modal .tab-content').forEach(content => {
|
||||||
|
content.classList.toggle('active', content.id === 'tab' + tab.charAt(0).toUpperCase() + tab.slice(1));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (tab === 'camera') {
|
||||||
|
startCamera();
|
||||||
|
} else {
|
||||||
|
stopCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startCamera() {
|
||||||
|
try {
|
||||||
|
stopCamera();
|
||||||
|
|
||||||
|
const constraints = {
|
||||||
|
video: {
|
||||||
|
facingMode: { ideal: 'environment' },
|
||||||
|
width: { ideal: 1920 },
|
||||||
|
height: { ideal: 1920 }
|
||||||
|
},
|
||||||
|
audio: false
|
||||||
|
};
|
||||||
|
|
||||||
|
cameraStream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||||
|
const video = document.getElementById('cameraVideo');
|
||||||
|
video.srcObject = cameraStream;
|
||||||
|
video.style.display = 'block';
|
||||||
|
|
||||||
|
document.getElementById('captureCanvas').style.display = 'none';
|
||||||
|
document.getElementById('cameraGuide').style.display = 'block';
|
||||||
|
document.getElementById('captureBtn').style.display = 'block';
|
||||||
|
document.getElementById('previewBtns').style.display = 'none';
|
||||||
|
capturedImageData = null;
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('카메라 오류:', err);
|
||||||
|
showToast('카메라에 접근할 수 없습니다', 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopCamera() {
|
||||||
|
if (cameraStream) {
|
||||||
|
cameraStream.getTracks().forEach(track => track.stop());
|
||||||
|
cameraStream = null;
|
||||||
|
}
|
||||||
|
const video = document.getElementById('cameraVideo');
|
||||||
|
if (video) video.srcObject = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function capturePhoto() {
|
||||||
|
const video = document.getElementById('cameraVideo');
|
||||||
|
const canvas = document.getElementById('captureCanvas');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
const vw = video.videoWidth;
|
||||||
|
const vh = video.videoHeight;
|
||||||
|
const minDim = Math.min(vw, vh);
|
||||||
|
const cropSize = minDim * 0.8;
|
||||||
|
const sx = (vw - cropSize) / 2;
|
||||||
|
const sy = (vh - cropSize) / 2;
|
||||||
|
|
||||||
|
canvas.width = 800;
|
||||||
|
canvas.height = 800;
|
||||||
|
ctx.drawImage(video, sx, sy, cropSize, cropSize, 0, 0, 800, 800);
|
||||||
|
|
||||||
|
capturedImageData = canvas.toDataURL('image/jpeg', 0.92);
|
||||||
|
|
||||||
|
video.style.display = 'none';
|
||||||
|
canvas.style.display = 'block';
|
||||||
|
document.getElementById('cameraGuide').style.display = 'none';
|
||||||
|
document.getElementById('captureBtn').style.display = 'none';
|
||||||
|
document.getElementById('previewBtns').style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
function retakePhoto() {
|
||||||
|
const video = document.getElementById('cameraVideo');
|
||||||
|
const canvas = document.getElementById('captureCanvas');
|
||||||
|
|
||||||
|
video.style.display = 'block';
|
||||||
|
canvas.style.display = 'none';
|
||||||
|
document.getElementById('cameraGuide').style.display = 'block';
|
||||||
|
document.getElementById('captureBtn').style.display = 'block';
|
||||||
|
document.getElementById('previewBtns').style.display = 'none';
|
||||||
|
capturedImageData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitCapturedImage() {
|
||||||
|
if (!capturedImageData) {
|
||||||
|
showToast('촬영된 이미지가 없습니다', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = imgModalBarcode || imgModalDrugCode;
|
||||||
|
const name = imgModalName;
|
||||||
|
const imageData = capturedImageData;
|
||||||
|
|
||||||
|
closeImageModal();
|
||||||
|
showToast(`"${name}" 이미지 저장 중...`, 'info');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/admin/product-images/${code}/upload`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
image_data: imageData,
|
||||||
|
product_name: name,
|
||||||
|
drug_code: imgModalDrugCode
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
showToast('✅ 이미지 저장 완료!', 'success');
|
||||||
|
loadSalesData(); // 새로고침
|
||||||
|
} else {
|
||||||
|
showToast(data.error || '저장 실패', 'error');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
showToast('오류: ' + err.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitImageUrl() {
|
||||||
|
const imageUrl = document.getElementById('imgUrlInput').value.trim();
|
||||||
|
|
||||||
|
if (!imageUrl) {
|
||||||
|
showToast('이미지 URL을 입력하세요', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!imageUrl.startsWith('http')) {
|
||||||
|
showToast('올바른 URL을 입력하세요', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = imgModalBarcode || imgModalDrugCode;
|
||||||
|
const name = imgModalName;
|
||||||
|
|
||||||
|
closeImageModal();
|
||||||
|
showToast(`"${name}" 이미지 다운로드 중...`, 'info');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/admin/product-images/${code}/replace`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
image_url: imageUrl,
|
||||||
|
product_name: name,
|
||||||
|
drug_code: imgModalDrugCode
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
showToast('✅ 이미지 등록 완료!', 'success');
|
||||||
|
loadSalesData(); // 새로고침
|
||||||
|
} else {
|
||||||
|
showToast(data.error || '등록 실패', 'error');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
showToast('오류: ' + err.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showToast(message, type = 'info') {
|
||||||
|
const toast = document.createElement('div');
|
||||||
|
toast.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
bottom: 24px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
padding: 12px 24px;
|
||||||
|
background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#6366f1'};
|
||||||
|
color: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
z-index: 2000;
|
||||||
|
animation: fadeIn 0.3s;
|
||||||
|
`;
|
||||||
|
toast.textContent = message;
|
||||||
|
document.body.appendChild(toast);
|
||||||
|
setTimeout(() => toast.remove(), 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 모달 외부 클릭시 닫기
|
||||||
|
document.getElementById('imageModal').addEventListener('click', e => {
|
||||||
|
if (e.target.id === 'imageModal') closeImageModal();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- 이미지 교체 모달 -->
|
||||||
|
<div class="image-modal" id="imageModal">
|
||||||
|
<div class="image-modal-content">
|
||||||
|
<h3>📷 제품 이미지 등록</h3>
|
||||||
|
<div style="background: rgba(139,92,246,0.1); border-radius: 8px; padding: 12px; margin-bottom: 16px;">
|
||||||
|
<div style="font-weight: 600;" id="imgModalProductName">제품명</div>
|
||||||
|
<div style="font-size: 12px; color: var(--text-muted); font-family: monospace;" id="imgModalCode">코드</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="image-modal-tabs">
|
||||||
|
<button class="tab-btn active" data-tab="url" onclick="switchImageTab('url')">🔗 URL 입력</button>
|
||||||
|
<button class="tab-btn" data-tab="camera" onclick="switchImageTab('camera')">📸 촬영</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- URL 탭 -->
|
||||||
|
<div class="tab-content active" id="tabUrl">
|
||||||
|
<input type="text" class="image-input" id="imgUrlInput" placeholder="이미지 URL을 입력하세요...">
|
||||||
|
<div class="modal-btns">
|
||||||
|
<button class="btn-modal secondary" onclick="closeImageModal()">취소</button>
|
||||||
|
<button class="btn-modal primary" onclick="submitImageUrl()">등록하기</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 카메라 탭 -->
|
||||||
|
<div class="tab-content" id="tabCamera">
|
||||||
|
<div class="camera-container">
|
||||||
|
<video id="cameraVideo" autoplay playsinline></video>
|
||||||
|
<canvas id="captureCanvas" style="display:none;"></canvas>
|
||||||
|
<div class="camera-guide" id="cameraGuide">
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
|
||||||
|
<rect x="10" y="10" width="80" height="80" fill="none" stroke="rgba(139,92,246,0.5)" stroke-width="0.5" stroke-dasharray="2,2"/>
|
||||||
|
<path d="M10,10 L20,10 M10,10 L10,20" fill="none" stroke="#a855f7" stroke-width="1"/>
|
||||||
|
<path d="M90,10 L80,10 M90,10 L90,20" fill="none" stroke="#a855f7" stroke-width="1"/>
|
||||||
|
<path d="M10,90 L20,90 M10,90 L10,80" fill="none" stroke="#a855f7" stroke-width="1"/>
|
||||||
|
<path d="M90,90 L80,90 M90,90 L90,80" fill="none" stroke="#a855f7" stroke-width="1"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-btns" id="captureBtn">
|
||||||
|
<button class="btn-modal secondary" onclick="closeImageModal()">취소</button>
|
||||||
|
<button class="btn-modal primary" onclick="capturePhoto()">📸 촬영</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-btns" id="previewBtns" style="display:none;">
|
||||||
|
<button class="btn-modal secondary" onclick="retakePhoto()">다시 촬영</button>
|
||||||
|
<button class="btn-modal primary" onclick="submitCapturedImage()">저장하기</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user