| {% extends "base.html" %} |
|
|
| {% block title %}管理面板 - Wisdom Hub{% endblock %} |
|
|
| {% block content %} |
| <div class="dashboard-container" style=" |
| max-width: 1200px; |
| margin: 0 auto; |
| background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.8)); |
| backdrop-filter: blur(10px); |
| border-radius: 24px; |
| box-shadow: 0 8px 32px rgba(99, 145, 197, 0.15); |
| border: 1px solid rgba(99, 145, 197, 0.2); |
| padding: 2rem; |
| "> |
| <div class="dashboard-header" style=" |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| margin-bottom: 2rem; |
| padding-bottom: 1.5rem; |
| border-bottom: 2px solid #B3CFEF; |
| "> |
| <div style="display: flex; align-items: center; gap: 1rem;"> |
| <i class="fas fa-chart-line" style=" |
| font-size: 2rem; |
| color: #6391C5; |
| "></i> |
| <h2 style=" |
| font-size: 1.75rem; |
| font-weight: 600; |
| color: #6391C5; |
| margin: 0; |
| ">文章管理</h2> |
| </div> |
|
|
| <div class="dashboard-actions" style=" |
| display: flex; |
| gap: 1rem; |
| "> |
| <button onclick="location.href='{{ url_for('admin.editor') }}'" style=" |
| padding: 0.75rem 1.5rem; |
| background: linear-gradient(135deg, #6391C5, #C5CDFD); |
| color: white; |
| border: none; |
| border-radius: 12px; |
| font-weight: 500; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| display: flex; |
| align-items: center; |
| gap: 0.5rem; |
| "> |
| <i class="fas fa-plus"></i> |
| 新建文章 |
| </button> |
|
|
| <button onclick="exportData()" style=" |
| padding: 0.75rem 1.5rem; |
| background: rgba(99, 145, 197, 0.1); |
| color: #6391C5; |
| border: 2px solid #B3CFEF; |
| border-radius: 12px; |
| font-weight: 500; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| display: flex; |
| align-items: center; |
| gap: 0.5rem; |
| "> |
| <i class="fas fa-download"></i> |
| 导出数据 |
| </button> |
|
|
| <button onclick="document.getElementById('importInput').click()" style=" |
| padding: 0.75rem 1.5rem; |
| background: rgba(99, 145, 197, 0.1); |
| color: #6391C5; |
| border: 2px solid #B3CFEF; |
| border-radius: 12px; |
| font-weight: 500; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| display: flex; |
| align-items: center; |
| gap: 0.5rem; |
| "> |
| <i class="fas fa-upload"></i> |
| 导入数据 |
| </button> |
| <input type="file" id="importInput" style="display: none" accept=".db"> |
| </div> |
| </div> |
| |
| <div class="articles-table" style=" |
| background: white; |
| border-radius: 16px; |
| box-shadow: 0 4px 16px rgba(99, 145, 197, 0.1); |
| overflow: hidden; |
| "> |
| <table style="width: 100%; border-collapse: collapse;"> |
| <thead> |
| <tr style="background: #FEEEDA;"> |
| <th style=" |
| text-align: left; |
| padding: 1rem 1.5rem; |
| color: #6391C5; |
| font-weight: 600; |
| border-bottom: 2px solid #B3CFEF; |
| ">标题</th> |
| <th style=" |
| text-align: left; |
| padding: 1rem 1.5rem; |
| color: #6391C5; |
| font-weight: 600; |
| border-bottom: 2px solid #B3CFEF; |
| ">创建时间</th> |
| <th style=" |
| text-align: left; |
| padding: 1rem 1.5rem; |
| color: #6391C5; |
| font-weight: 600; |
| border-bottom: 2px solid #B3CFEF; |
| ">更新时间</th> |
| <th style=" |
| text-align: left; |
| padding: 1rem 1.5rem; |
| color: #6391C5; |
| font-weight: 600; |
| border-bottom: 2px solid #B3CFEF; |
| ">操作</th> |
| </tr> |
| </thead> |
| <tbody> |
| {% for article in articles %} |
| <tr style="transition: all 0.3s ease;"> |
| <td style=" |
| padding: 1rem 1.5rem; |
| border-bottom: 1px solid #B3CFEF; |
| color: #6391C5; |
| ">{{ article.title }}</td> |
| <td style=" |
| padding: 1rem 1.5rem; |
| border-bottom: 1px solid #B3CFEF; |
| color: #6391C5; |
| ">{{ article.created_at.strftime('%Y-%m-%d') }}</td> |
| <td style=" |
| padding: 1rem 1.5rem; |
| border-bottom: 1px solid #B3CFEF; |
| color: #6391C5; |
| ">{{ article.updated_at.strftime('%Y-%m-%d') }}</td> |
| <td style=" |
| padding: 1rem 1.5rem; |
| border-bottom: 1px solid #B3CFEF; |
| "> |
| <div style="display: flex; gap: 0.5rem;"> |
| <a href="{{ url_for('admin.editor', slug=article.slug) }}" style=" |
| padding: 0.5rem 1rem; |
| background: linear-gradient(135deg, #6391C5, #C5CDFD); |
| color: white; |
| border-radius: 8px; |
| text-decoration: none; |
| font-size: 0.875rem; |
| transition: all 0.3s ease; |
| ">编辑</a> |
| <button onclick="deleteArticle('{{ article.slug }}')" style=" |
| padding: 0.5rem 1rem; |
| background: rgba(255, 71, 87, 0.1); |
| color: #ff4757; |
| border: 1px solid rgba(255, 71, 87, 0.2); |
| border-radius: 8px; |
| font-size: 0.875rem; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| ">删除</button> |
| </div> |
| </td> |
| </tr> |
| {% endfor %} |
| </tbody> |
| </table> |
| </div> |
| </div> |
|
|
| <script> |
| |
| document.querySelectorAll('tbody tr').forEach(row => { |
| row.addEventListener('mouseenter', () => { |
| row.style.background = 'rgba(99, 145, 197, 0.05)'; |
| }); |
| row.addEventListener('mouseleave', () => { |
| row.style.background = 'white'; |
| }); |
| }); |
| |
| |
| document.querySelectorAll('button').forEach(button => { |
| button.addEventListener('mouseenter', () => { |
| if (button.style.background.includes('linear-gradient')) { |
| button.style.transform = 'translateY(-2px)'; |
| button.style.boxShadow = '0 4px 12px rgba(99, 145, 197, 0.2)'; |
| } else if (button.style.background.includes('rgba(255, 71, 87')) { |
| button.style.background = 'rgba(255, 71, 87, 0.2)'; |
| } else { |
| button.style.borderColor = '#6391C5'; |
| button.style.background = 'rgba(99, 145, 197, 0.15)'; |
| } |
| }); |
| |
| button.addEventListener('mouseleave', () => { |
| if (button.style.background.includes('linear-gradient')) { |
| button.style.transform = 'none'; |
| button.style.boxShadow = 'none'; |
| } else if (button.style.background.includes('rgba(255, 71, 87')) { |
| button.style.background = 'rgba(255, 71, 87, 0.1)'; |
| } else { |
| button.style.borderColor = '#B3CFEF'; |
| button.style.background = 'rgba(99, 145, 197, 0.1)'; |
| } |
| }); |
| }); |
| |
| |
| document.querySelectorAll('a').forEach(link => { |
| if (link.style.background.includes('linear-gradient')) { |
| link.addEventListener('mouseenter', () => { |
| link.style.transform = 'translateY(-2px)'; |
| link.style.boxShadow = '0 4px 12px rgba(99, 145, 197, 0.2)'; |
| }); |
| |
| link.addEventListener('mouseleave', () => { |
| link.style.transform = 'none'; |
| link.style.boxShadow = 'none'; |
| }); |
| } |
| }); |
| |
| async function deleteArticle(slug) { |
| if (!confirm('确定要删除这篇文章吗?')) return; |
| |
| try { |
| const response = await fetch(`/api/articles/${slug}`, { |
| method: 'DELETE' |
| }); |
| |
| if (response.ok) { |
| location.reload(); |
| } |
| } catch (error) { |
| console.error('Error:', error); |
| alert('删除失败,请重试'); |
| } |
| } |
| |
| async function exportData() { |
| try { |
| window.location.href = '/api/export'; |
| } catch (error) { |
| console.error('Error:', error); |
| alert('导出失败,请重试'); |
| } |
| } |
| |
| document.getElementById('importInput').addEventListener('change', async (event) => { |
| const file = event.target.files[0]; |
| if (!file) return; |
| |
| try { |
| const formData = new FormData(); |
| formData.append('file', file); |
| |
| const response = await fetch('/api/import', { |
| method: 'POST', |
| body: formData |
| }); |
| |
| const data = await response.json(); |
| if (response.ok) { |
| alert('导入成功,页面将刷新'); |
| location.reload(); |
| } else { |
| throw new Error(data.error || '导入失败'); |
| } |
| } catch (error) { |
| console.error('Error:', error); |
| alert('导入失败:' + error.message); |
| } |
| }); |
| </script> |
| {% endblock %} |