Compare commits
2 Commits
14788fd59d
...
c15c29850c
| Author | SHA1 | Date | |
|---|---|---|---|
| c15c29850c | |||
| 259246028e |
@@ -35,7 +35,7 @@
|
|||||||
.sidebar h3 {
|
.sidebar h3 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #ff79c6;
|
color: #add8e6;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 导航栏样式 */
|
/* 导航栏样式 - 保持原有样式 */
|
||||||
.sidebar {
|
.sidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
.sidebar h3 {
|
.sidebar h3 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #ff79c6;
|
color: #add8e6;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
@@ -68,42 +68,207 @@
|
|||||||
background-color: rgba(139, 233, 253, 0.2);
|
background-color: rgba(139, 233, 253, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 主内容区 */
|
/* 主内容区 - 改进后的样式 */
|
||||||
.main-content {
|
.main-content {
|
||||||
margin-left: 200px;
|
margin-left: 200px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 原有样式保持不变 */
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 900px;
|
max-width: 1200px;
|
||||||
margin: 6vh auto;
|
margin: 0 auto;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 10px;
|
border-radius: 14px;
|
||||||
box-shadow: 0 6px 18px rgba(0,0,0,0.06);
|
box-shadow: 0 10px 24px rgba(31,35,40,0.08);
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
.row { display: flex; gap: 16px; }
|
|
||||||
.col { flex: 1; }
|
.header {
|
||||||
textarea {
|
display: flex;
|
||||||
width: 100%;
|
align-items: center;
|
||||||
min-height: 260px;
|
justify-content: space-between;
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h2 {
|
||||||
|
margin: 0;
|
||||||
|
color: #1e293b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header p {
|
||||||
|
margin: 5px 0 0 0;
|
||||||
|
color: #64748b;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
img { max-width: 100%; border: 1px solid #eee; border-radius: 6px; }
|
|
||||||
.btn {
|
.upload-section {
|
||||||
padding: 8px 12px;
|
background: #f8fafc;
|
||||||
border: none;
|
border: 2px dashed #cbd5e1;
|
||||||
border-radius: 6px;
|
border-radius: 12px;
|
||||||
cursor: pointer;
|
padding: 32px;
|
||||||
|
text-align: center;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-section:hover {
|
||||||
|
border-color: #4f46e5;
|
||||||
|
background: #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-section.drag-over {
|
||||||
|
border-color: #4f46e5;
|
||||||
|
background: #e0e7ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-section input[type="file"] {
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 10px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: #4f46e5;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background: #4338ca;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background: #e2e8f0;
|
||||||
|
color: #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary:hover {
|
||||||
|
background: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger {
|
||||||
|
background: #ef4444;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger:hover {
|
||||||
|
background: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
margin: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.preview-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-box {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-box h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-box img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 300px;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-box {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-box h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-controls {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kvForm {
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr auto;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row input {
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid #cbd5e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resultBox {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 200px;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
resize: vertical;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-message {
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-message.success {
|
||||||
|
background-color: #d4edda;
|
||||||
|
color: #155724;
|
||||||
|
border: 1px solid #c3e6cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-message.error {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
color: #721c24;
|
||||||
|
border: 1px solid #f5c6cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.btn-primary { background: #1677ff; color: #fff; }
|
|
||||||
.btn-secondary { background: #f0f0f0; }
|
|
||||||
.muted { color: #666; font-size: 12px; }
|
|
||||||
.error { color: #d14343; }
|
|
||||||
.success { color: #179957; }
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -123,38 +288,46 @@
|
|||||||
<!-- 主内容区域 -->
|
<!-- 主内容区域 -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2>图片上传与识别</h2>
|
<div class="header">
|
||||||
<p class="muted">选择图片后上传,服务端调用大模型解析为可编辑的 JSON,再确认入库。</p>
|
<div>
|
||||||
|
<h2>图片上传与识别</h2>
|
||||||
<form id="uploadForm" enctype="multipart/form-data">
|
<p>选择图片后上传,服务端调用大模型解析为可编辑的 JSON,再确认入库。</p>
|
||||||
{% csrf_token %}
|
</div>
|
||||||
<input type="file" id="fileInput" name="file" accept="image/*" />
|
|
||||||
<button type="submit" class="btn btn-primary">上传并识别</button>
|
|
||||||
<span id="uploadMsg" class="muted"></span>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="row" style="margin-top:16px;">
|
|
||||||
<div class="col">
|
|
||||||
<h4>图片预览</h4>
|
|
||||||
<img id="preview" alt="预览" />
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<h4>识别结果(可编辑)</h4>
|
|
||||||
<div style="display:flex; gap:8px; align-items:center; margin-bottom:8px;">
|
|
||||||
<button id="addFieldBtn" class="btn btn-secondary" type="button">添加字段</button>
|
|
||||||
<button id="syncFromTextBtn" class="btn btn-secondary" type="button">从文本区刷新表单</button>
|
|
||||||
</div>
|
|
||||||
<div id="kvForm" style="border:1px solid #eee; border-radius:6px; padding:8px; max-height:300px; overflow:auto;"></div>
|
|
||||||
<div style="margin-top:8px;">
|
|
||||||
<textarea id="resultBox" placeholder="识别结果JSON将显示在这里"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-top:16px;">
|
<div class="upload-section" id="dropArea">
|
||||||
<button id="confirmBtn" class="btn btn-primary" disabled>确认并入库</button>
|
<h3>上传图片</h3>
|
||||||
<button id="clearBtn" class="btn btn-secondary" type="button">清空</button>
|
<p>点击下方按钮选择图片,或拖拽图片到此区域</p>
|
||||||
<span id="confirmMsg" class="muted"></span>
|
<form id="uploadForm" enctype="multipart/form-data">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="file" id="fileInput" name="file" accept="image/*" required />
|
||||||
|
<br>
|
||||||
|
<button type="submit" class="btn btn-primary">上传并识别</button>
|
||||||
|
</form>
|
||||||
|
<div class="status-message" id="uploadMsg"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="preview-container">
|
||||||
|
<div class="preview-box">
|
||||||
|
<h3>图片预览</h3>
|
||||||
|
<img id="preview" alt="预览" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="result-box">
|
||||||
|
<h3>识别结果(可编辑)</h3>
|
||||||
|
<div class="form-controls">
|
||||||
|
<button id="addFieldBtn" class="btn btn-secondary" type="button">添加字段</button>
|
||||||
|
<button id="syncFromTextBtn" class="btn btn-secondary" type="button">从文本区刷新表单</button>
|
||||||
|
</div>
|
||||||
|
<div id="kvForm"></div>
|
||||||
|
<textarea id="resultBox" placeholder="识别结果JSON将显示在这里"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button id="confirmBtn" class="btn btn-primary" disabled>确认并入库</button>
|
||||||
|
<button id="clearBtn" class="btn btn-secondary" type="button">清空</button>
|
||||||
|
<span id="confirmMsg" class="muted"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -177,15 +350,63 @@ const confirmMsg = document.getElementById('confirmMsg');
|
|||||||
const kvForm = document.getElementById('kvForm');
|
const kvForm = document.getElementById('kvForm');
|
||||||
const addFieldBtn = document.getElementById('addFieldBtn');
|
const addFieldBtn = document.getElementById('addFieldBtn');
|
||||||
const syncFromTextBtn = document.getElementById('syncFromTextBtn');
|
const syncFromTextBtn = document.getElementById('syncFromTextBtn');
|
||||||
|
const dropArea = document.getElementById('dropArea');
|
||||||
|
|
||||||
let currentImageRel = '';
|
let currentImageRel = '';
|
||||||
|
|
||||||
|
// 拖拽上传功能
|
||||||
|
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||||
|
dropArea.addEventListener(eventName, preventDefaults, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
function preventDefaults(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
['dragenter', 'dragover'].forEach(eventName => {
|
||||||
|
dropArea.addEventListener(eventName, highlight, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
['dragleave', 'drop'].forEach(eventName => {
|
||||||
|
dropArea.addEventListener(eventName, unhighlight, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
function highlight() {
|
||||||
|
dropArea.classList.add('drag-over');
|
||||||
|
}
|
||||||
|
|
||||||
|
function unhighlight() {
|
||||||
|
dropArea.classList.remove('drag-over');
|
||||||
|
}
|
||||||
|
|
||||||
|
dropArea.addEventListener('drop', handleDrop, false);
|
||||||
|
|
||||||
|
function handleDrop(e) {
|
||||||
|
const dt = e.dataTransfer;
|
||||||
|
const files = dt.files;
|
||||||
|
if (files.length) {
|
||||||
|
fileInput.files = files;
|
||||||
|
const event = new Event('change', { bubbles: true });
|
||||||
|
fileInput.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件选择后预览
|
||||||
|
fileInput.addEventListener('change', function(e) {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (file && file.type.startsWith('image/')) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
preview.src = e.target.result;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function createRow(k = '', v = '') {
|
function createRow(k = '', v = '') {
|
||||||
const row = document.createElement('div');
|
const row = document.createElement('div');
|
||||||
row.style.display = 'grid';
|
row.className = 'form-row';
|
||||||
row.style.gridTemplateColumns = '1fr 1fr auto';
|
|
||||||
row.style.gap = '8px';
|
|
||||||
row.style.marginBottom = '6px';
|
|
||||||
const keyInput = document.createElement('input');
|
const keyInput = document.createElement('input');
|
||||||
keyInput.type = 'text';
|
keyInput.type = 'text';
|
||||||
keyInput.placeholder = '字段名';
|
keyInput.placeholder = '字段名';
|
||||||
@@ -196,9 +417,17 @@ function createRow(k = '', v = '') {
|
|||||||
valInput.value = typeof v === 'object' ? JSON.stringify(v) : (v ?? '');
|
valInput.value = typeof v === 'object' ? JSON.stringify(v) : (v ?? '');
|
||||||
const delBtn = document.createElement('button');
|
const delBtn = document.createElement('button');
|
||||||
delBtn.type = 'button';
|
delBtn.type = 'button';
|
||||||
delBtn.className = 'btn btn-secondary';
|
delBtn.className = 'btn btn-danger';
|
||||||
delBtn.textContent = '删除';
|
delBtn.textContent = '删除';
|
||||||
delBtn.onclick = () => { kvForm.removeChild(row); syncTextarea(); };
|
delBtn.onclick = () => {
|
||||||
|
if (kvForm.children.length > 1) {
|
||||||
|
kvForm.removeChild(row);
|
||||||
|
} else {
|
||||||
|
keyInput.value = '';
|
||||||
|
valInput.value = '';
|
||||||
|
}
|
||||||
|
syncTextarea();
|
||||||
|
};
|
||||||
keyInput.oninput = syncTextarea;
|
keyInput.oninput = syncTextarea;
|
||||||
valInput.oninput = syncTextarea;
|
valInput.oninput = syncTextarea;
|
||||||
row.appendChild(keyInput);
|
row.appendChild(keyInput);
|
||||||
@@ -246,9 +475,16 @@ syncFromTextBtn.addEventListener('click', () => {
|
|||||||
try {
|
try {
|
||||||
const obj = JSON.parse(resultBox.value || '{}');
|
const obj = JSON.parse(resultBox.value || '{}');
|
||||||
renderFormFromObject(obj);
|
renderFormFromObject(obj);
|
||||||
|
uploadMsg.textContent = '已从文本区刷新表单';
|
||||||
|
uploadMsg.className = 'status-message success';
|
||||||
|
uploadMsg.style.display = 'block';
|
||||||
|
setTimeout(() => {
|
||||||
|
uploadMsg.style.display = 'none';
|
||||||
|
}, 2000);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
uploadMsg.textContent = '文本区不是有效JSON';
|
uploadMsg.textContent = '文本区不是有效JSON';
|
||||||
uploadMsg.className = 'error';
|
uploadMsg.className = 'status-message error';
|
||||||
|
uploadMsg.style.display = 'block';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -263,7 +499,8 @@ uploadForm.addEventListener('submit', async (e) => {
|
|||||||
const file = fileInput.files[0];
|
const file = fileInput.files[0];
|
||||||
if (!file) {
|
if (!file) {
|
||||||
uploadMsg.textContent = '请选择图片文件';
|
uploadMsg.textContent = '请选择图片文件';
|
||||||
uploadMsg.className = 'error';
|
uploadMsg.className = 'status-message error';
|
||||||
|
uploadMsg.style.display = 'block';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,14 +519,16 @@ uploadForm.addEventListener('submit', async (e) => {
|
|||||||
throw new Error(data.message || '上传识别失败');
|
throw new Error(data.message || '上传识别失败');
|
||||||
}
|
}
|
||||||
uploadMsg.textContent = data.message || '识别成功';
|
uploadMsg.textContent = data.message || '识别成功';
|
||||||
uploadMsg.className = 'success';
|
uploadMsg.className = 'status-message success';
|
||||||
|
uploadMsg.style.display = 'block';
|
||||||
preview.src = data.image_url;
|
preview.src = data.image_url;
|
||||||
renderFormFromObject(data.data || {});
|
renderFormFromObject(data.data || {});
|
||||||
currentImageRel = data.image;
|
currentImageRel = data.image;
|
||||||
confirmBtn.disabled = false;
|
confirmBtn.disabled = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
uploadMsg.textContent = e.message || '发生错误';
|
uploadMsg.textContent = e.message || '发生错误';
|
||||||
uploadMsg.className = 'error';
|
uploadMsg.className = 'status-message error';
|
||||||
|
uploadMsg.style.display = 'block';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -311,10 +550,10 @@ confirmBtn.addEventListener('click', async () => {
|
|||||||
throw new Error(data.message || '录入失败');
|
throw new Error(data.message || '录入失败');
|
||||||
}
|
}
|
||||||
confirmMsg.textContent = data.message || '录入成功';
|
confirmMsg.textContent = data.message || '录入成功';
|
||||||
confirmMsg.className = 'success';
|
confirmMsg.style.color = '#179957';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
confirmMsg.textContent = e.message || '发生错误';
|
confirmMsg.textContent = e.message || '发生错误';
|
||||||
confirmMsg.className = 'error';
|
confirmMsg.style.color = '#d14343';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -323,6 +562,7 @@ clearBtn.addEventListener('click', () => {
|
|||||||
preview.src = '';
|
preview.src = '';
|
||||||
resultBox.value = '';
|
resultBox.value = '';
|
||||||
kvForm.innerHTML = '';
|
kvForm.innerHTML = '';
|
||||||
|
kvForm.appendChild(createRow()); // 保留一个空行
|
||||||
uploadMsg.textContent = '';
|
uploadMsg.textContent = '';
|
||||||
confirmMsg.textContent = '';
|
confirmMsg.textContent = '';
|
||||||
confirmBtn.disabled = true;
|
confirmBtn.disabled = true;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
.sidebar h3 {
|
.sidebar h3 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #ff79c6;
|
color: #add8e6;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
.sidebar h3 {
|
.sidebar h3 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #ff79c6;
|
color: #add8e6;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user