diff --git a/elastic/templates/elastic/manage.html b/elastic/templates/elastic/manage.html
index d8d9e52..d289d3e 100644
--- a/elastic/templates/elastic/manage.html
+++ b/elastic/templates/elastic/manage.html
@@ -35,7 +35,7 @@
.sidebar h3 {
margin-top: 0;
font-size: 18px;
- color: #ff79c6;
+ color: #add8e6;
text-align: center;
margin-bottom: 20px;
}
diff --git a/elastic/templates/elastic/upload.html b/elastic/templates/elastic/upload.html
index 273df65..231fff2 100644
--- a/elastic/templates/elastic/upload.html
+++ b/elastic/templates/elastic/upload.html
@@ -10,7 +10,7 @@
background: #fafafa;
}
- /* 导航栏样式 */
+ /* 导航栏样式 - 保持原有样式 */
.sidebar {
position: fixed;
top: 0;
@@ -35,7 +35,7 @@
.sidebar h3 {
margin-top: 0;
font-size: 18px;
- color: #ff79c6;
+ color: #add8e6;
text-align: center;
margin-bottom: 20px;
}
@@ -68,42 +68,207 @@
background-color: rgba(139, 233, 253, 0.2);
}
- /* 主内容区 */
+ /* 主内容区 - 改进后的样式 */
.main-content {
margin-left: 200px;
padding: 20px;
color: #333;
}
- /* 原有样式保持不变 */
.container {
- max-width: 900px;
- margin: 6vh auto;
+ max-width: 1200px;
+ margin: 0 auto;
background: #fff;
- border-radius: 10px;
- box-shadow: 0 6px 18px rgba(0,0,0,0.06);
+ border-radius: 14px;
+ box-shadow: 0 10px 24px rgba(31,35,40,0.08);
padding: 24px;
}
- .row { display: flex; gap: 16px; }
- .col { flex: 1; }
- textarea {
- width: 100%;
- min-height: 260px;
- font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
+
+ .header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 12px;
+ }
+
+ .header h2 {
+ margin: 0;
+ color: #1e293b;
+ }
+
+ .header p {
+ margin: 5px 0 0 0;
+ color: #64748b;
font-size: 14px;
}
- img { max-width: 100%; border: 1px solid #eee; border-radius: 6px; }
- .btn {
- padding: 8px 12px;
- border: none;
- border-radius: 6px;
- cursor: pointer;
+
+ .upload-section {
+ background: #f8fafc;
+ border: 2px dashed #cbd5e1;
+ border-radius: 12px;
+ 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; }
@@ -123,38 +288,46 @@
-
图片上传与识别
-
选择图片后上传,服务端调用大模型解析为可编辑的 JSON,再确认入库。
-
-
-
-
-
-
图片预览
-
![预览]()
-
-
-
识别结果(可编辑)
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
+
上传图片
+
点击下方按钮选择图片,或拖拽图片到此区域
+
+
+
+
+
+
+
图片预览
+
![预览]()
+
+
+
+
识别结果(可编辑)
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -177,15 +350,63 @@ const confirmMsg = document.getElementById('confirmMsg');
const kvForm = document.getElementById('kvForm');
const addFieldBtn = document.getElementById('addFieldBtn');
const syncFromTextBtn = document.getElementById('syncFromTextBtn');
+const dropArea = document.getElementById('dropArea');
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 = '') {
const row = document.createElement('div');
- row.style.display = 'grid';
- row.style.gridTemplateColumns = '1fr 1fr auto';
- row.style.gap = '8px';
- row.style.marginBottom = '6px';
+ row.className = 'form-row';
const keyInput = document.createElement('input');
keyInput.type = 'text';
keyInput.placeholder = '字段名';
@@ -196,9 +417,17 @@ function createRow(k = '', v = '') {
valInput.value = typeof v === 'object' ? JSON.stringify(v) : (v ?? '');
const delBtn = document.createElement('button');
delBtn.type = 'button';
- delBtn.className = 'btn btn-secondary';
+ delBtn.className = 'btn btn-danger';
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;
valInput.oninput = syncTextarea;
row.appendChild(keyInput);
@@ -246,9 +475,16 @@ syncFromTextBtn.addEventListener('click', () => {
try {
const obj = JSON.parse(resultBox.value || '{}');
renderFormFromObject(obj);
+ uploadMsg.textContent = '已从文本区刷新表单';
+ uploadMsg.className = 'status-message success';
+ uploadMsg.style.display = 'block';
+ setTimeout(() => {
+ uploadMsg.style.display = 'none';
+ }, 2000);
} catch (e) {
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];
if (!file) {
uploadMsg.textContent = '请选择图片文件';
- uploadMsg.className = 'error';
+ uploadMsg.className = 'status-message error';
+ uploadMsg.style.display = 'block';
return;
}
@@ -282,14 +519,16 @@ uploadForm.addEventListener('submit', async (e) => {
throw new Error(data.message || '上传识别失败');
}
uploadMsg.textContent = data.message || '识别成功';
- uploadMsg.className = 'success';
+ uploadMsg.className = 'status-message success';
+ uploadMsg.style.display = 'block';
preview.src = data.image_url;
renderFormFromObject(data.data || {});
currentImageRel = data.image;
confirmBtn.disabled = false;
} catch (e) {
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 || '录入失败');
}
confirmMsg.textContent = data.message || '录入成功';
- confirmMsg.className = 'success';
+ confirmMsg.style.color = '#179957';
} catch (e) {
confirmMsg.textContent = e.message || '发生错误';
- confirmMsg.className = 'error';
+ confirmMsg.style.color = '#d14343';
}
});
@@ -323,6 +562,7 @@ clearBtn.addEventListener('click', () => {
preview.src = '';
resultBox.value = '';
kvForm.innerHTML = '';
+ kvForm.appendChild(createRow()); // 保留一个空行
uploadMsg.textContent = '';
confirmMsg.textContent = '';
confirmBtn.disabled = true;
diff --git a/elastic/templates/elastic/users.html b/elastic/templates/elastic/users.html
index 406dc68..48d55cd 100644
--- a/elastic/templates/elastic/users.html
+++ b/elastic/templates/elastic/users.html
@@ -35,7 +35,7 @@
.sidebar h3 {
margin-top: 0;
font-size: 18px;
- color: #ff79c6;
+ color: #add8e6;
text-align: center;
margin-bottom: 20px;
}
diff --git a/main/templates/main/home.html b/main/templates/main/home.html
index 6bef3af..79d3a5c 100644
--- a/main/templates/main/home.html
+++ b/main/templates/main/home.html
@@ -35,7 +35,7 @@
.sidebar h3 {
margin-top: 0;
font-size: 18px;
- color: #ff79c6;
+ color: #add8e6;
text-align: center;
margin-bottom: 20px;
}