mistpe commited on
Commit
406a65a
·
verified ·
1 Parent(s): 6259b7a

Update app/templates/admin/dashboard.html

Browse files
Files changed (1) hide show
  1. app/templates/admin/dashboard.html +289 -289
app/templates/admin/dashboard.html CHANGED
@@ -1,290 +1,290 @@
1
- {% extends "base.html" %}
2
-
3
- {% block title %}管理面板 - 个人博客{% endblock %}
4
-
5
- {% block content %}
6
- <div class="dashboard-container" style="
7
- max-width: 1200px;
8
- margin: 0 auto;
9
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.8));
10
- backdrop-filter: blur(10px);
11
- border-radius: 24px;
12
- box-shadow: 0 8px 32px rgba(99, 145, 197, 0.15);
13
- border: 1px solid rgba(99, 145, 197, 0.2);
14
- padding: 2rem;
15
- ">
16
- <div class="dashboard-header" style="
17
- display: flex;
18
- justify-content: space-between;
19
- align-items: center;
20
- margin-bottom: 2rem;
21
- padding-bottom: 1.5rem;
22
- border-bottom: 2px solid #B3CFEF;
23
- ">
24
- <div style="display: flex; align-items: center; gap: 1rem;">
25
- <i class="fas fa-chart-line" style="
26
- font-size: 2rem;
27
- color: #6391C5;
28
- "></i>
29
- <h2 style="
30
- font-size: 1.75rem;
31
- font-weight: 600;
32
- color: #6391C5;
33
- margin: 0;
34
- ">文章管理</h2>
35
- </div>
36
-
37
- <div class="dashboard-actions" style="
38
- display: flex;
39
- gap: 1rem;
40
- ">
41
- <button onclick="location.href='{{ url_for('admin.editor') }}'" style="
42
- padding: 0.75rem 1.5rem;
43
- background: linear-gradient(135deg, #6391C5, #C5CDFD);
44
- color: white;
45
- border: none;
46
- border-radius: 12px;
47
- font-weight: 500;
48
- cursor: pointer;
49
- transition: all 0.3s ease;
50
- display: flex;
51
- align-items: center;
52
- gap: 0.5rem;
53
- ">
54
- <i class="fas fa-plus"></i>
55
- 新建文章
56
- </button>
57
-
58
- <button onclick="exportData()" style="
59
- padding: 0.75rem 1.5rem;
60
- background: rgba(99, 145, 197, 0.1);
61
- color: #6391C5;
62
- border: 2px solid #B3CFEF;
63
- border-radius: 12px;
64
- font-weight: 500;
65
- cursor: pointer;
66
- transition: all 0.3s ease;
67
- display: flex;
68
- align-items: center;
69
- gap: 0.5rem;
70
- ">
71
- <i class="fas fa-download"></i>
72
- 导出数据
73
- </button>
74
-
75
- <button onclick="document.getElementById('importInput').click()" style="
76
- padding: 0.75rem 1.5rem;
77
- background: rgba(99, 145, 197, 0.1);
78
- color: #6391C5;
79
- border: 2px solid #B3CFEF;
80
- border-radius: 12px;
81
- font-weight: 500;
82
- cursor: pointer;
83
- transition: all 0.3s ease;
84
- display: flex;
85
- align-items: center;
86
- gap: 0.5rem;
87
- ">
88
- <i class="fas fa-upload"></i>
89
- 导入数据
90
- </button>
91
- <input type="file" id="importInput" style="display: none" accept=".db">
92
- </div>
93
- </div>
94
-
95
- <div class="articles-table" style="
96
- background: white;
97
- border-radius: 16px;
98
- box-shadow: 0 4px 16px rgba(99, 145, 197, 0.1);
99
- overflow: hidden;
100
- ">
101
- <table style="width: 100%; border-collapse: collapse;">
102
- <thead>
103
- <tr style="background: #FEEEDA;">
104
- <th style="
105
- text-align: left;
106
- padding: 1rem 1.5rem;
107
- color: #6391C5;
108
- font-weight: 600;
109
- border-bottom: 2px solid #B3CFEF;
110
- ">标题</th>
111
- <th style="
112
- text-align: left;
113
- padding: 1rem 1.5rem;
114
- color: #6391C5;
115
- font-weight: 600;
116
- border-bottom: 2px solid #B3CFEF;
117
- ">创建时间</th>
118
- <th style="
119
- text-align: left;
120
- padding: 1rem 1.5rem;
121
- color: #6391C5;
122
- font-weight: 600;
123
- border-bottom: 2px solid #B3CFEF;
124
- ">更新时间</th>
125
- <th style="
126
- text-align: left;
127
- padding: 1rem 1.5rem;
128
- color: #6391C5;
129
- font-weight: 600;
130
- border-bottom: 2px solid #B3CFEF;
131
- ">操作</th>
132
- </tr>
133
- </thead>
134
- <tbody>
135
- {% for article in articles %}
136
- <tr style="transition: all 0.3s ease;">
137
- <td style="
138
- padding: 1rem 1.5rem;
139
- border-bottom: 1px solid #B3CFEF;
140
- color: #6391C5;
141
- ">{{ article.title }}</td>
142
- <td style="
143
- padding: 1rem 1.5rem;
144
- border-bottom: 1px solid #B3CFEF;
145
- color: #6391C5;
146
- ">{{ article.created_at.strftime('%Y-%m-%d') }}</td>
147
- <td style="
148
- padding: 1rem 1.5rem;
149
- border-bottom: 1px solid #B3CFEF;
150
- color: #6391C5;
151
- ">{{ article.updated_at.strftime('%Y-%m-%d') }}</td>
152
- <td style="
153
- padding: 1rem 1.5rem;
154
- border-bottom: 1px solid #B3CFEF;
155
- ">
156
- <div style="display: flex; gap: 0.5rem;">
157
- <a href="{{ url_for('admin.editor', slug=article.slug) }}" style="
158
- padding: 0.5rem 1rem;
159
- background: linear-gradient(135deg, #6391C5, #C5CDFD);
160
- color: white;
161
- border-radius: 8px;
162
- text-decoration: none;
163
- font-size: 0.875rem;
164
- transition: all 0.3s ease;
165
- ">编辑</a>
166
- <button onclick="deleteArticle('{{ article.slug }}')" style="
167
- padding: 0.5rem 1rem;
168
- background: rgba(255, 71, 87, 0.1);
169
- color: #ff4757;
170
- border: 1px solid rgba(255, 71, 87, 0.2);
171
- border-radius: 8px;
172
- font-size: 0.875rem;
173
- cursor: pointer;
174
- transition: all 0.3s ease;
175
- ">删除</button>
176
- </div>
177
- </td>
178
- </tr>
179
- {% endfor %}
180
- </tbody>
181
- </table>
182
- </div>
183
- </div>
184
-
185
- <script>
186
- // 表格行悬停效果
187
- document.querySelectorAll('tbody tr').forEach(row => {
188
- row.addEventListener('mouseenter', () => {
189
- row.style.background = 'rgba(99, 145, 197, 0.05)';
190
- });
191
- row.addEventListener('mouseleave', () => {
192
- row.style.background = 'white';
193
- });
194
- });
195
-
196
- // 按钮悬停效果
197
- document.querySelectorAll('button').forEach(button => {
198
- button.addEventListener('mouseenter', () => {
199
- if (button.style.background.includes('linear-gradient')) {
200
- button.style.transform = 'translateY(-2px)';
201
- button.style.boxShadow = '0 4px 12px rgba(99, 145, 197, 0.2)';
202
- } else if (button.style.background.includes('rgba(255, 71, 87')) {
203
- button.style.background = 'rgba(255, 71, 87, 0.2)';
204
- } else {
205
- button.style.borderColor = '#6391C5';
206
- button.style.background = 'rgba(99, 145, 197, 0.15)';
207
- }
208
- });
209
-
210
- button.addEventListener('mouseleave', () => {
211
- if (button.style.background.includes('linear-gradient')) {
212
- button.style.transform = 'none';
213
- button.style.boxShadow = 'none';
214
- } else if (button.style.background.includes('rgba(255, 71, 87')) {
215
- button.style.background = 'rgba(255, 71, 87, 0.1)';
216
- } else {
217
- button.style.borderColor = '#B3CFEF';
218
- button.style.background = 'rgba(99, 145, 197, 0.1)';
219
- }
220
- });
221
- });
222
-
223
- // 编辑链接悬停效果
224
- document.querySelectorAll('a').forEach(link => {
225
- if (link.style.background.includes('linear-gradient')) {
226
- link.addEventListener('mouseenter', () => {
227
- link.style.transform = 'translateY(-2px)';
228
- link.style.boxShadow = '0 4px 12px rgba(99, 145, 197, 0.2)';
229
- });
230
-
231
- link.addEventListener('mouseleave', () => {
232
- link.style.transform = 'none';
233
- link.style.boxShadow = 'none';
234
- });
235
- }
236
- });
237
-
238
- async function deleteArticle(slug) {
239
- if (!confirm('确定要删除这篇文章吗?')) return;
240
-
241
- try {
242
- const response = await fetch(`/api/articles/${slug}`, {
243
- method: 'DELETE'
244
- });
245
-
246
- if (response.ok) {
247
- location.reload();
248
- }
249
- } catch (error) {
250
- console.error('Error:', error);
251
- alert('删除失败,请重试');
252
- }
253
- }
254
-
255
- async function exportData() {
256
- try {
257
- window.location.href = '/api/export';
258
- } catch (error) {
259
- console.error('Error:', error);
260
- alert('导出失败,请重试');
261
- }
262
- }
263
-
264
- document.getElementById('importInput').addEventListener('change', async (event) => {
265
- const file = event.target.files[0];
266
- if (!file) return;
267
-
268
- try {
269
- const formData = new FormData();
270
- formData.append('file', file);
271
-
272
- const response = await fetch('/api/import', {
273
- method: 'POST',
274
- body: formData
275
- });
276
-
277
- const data = await response.json();
278
- if (response.ok) {
279
- alert('导入成功,页面将刷新');
280
- location.reload();
281
- } else {
282
- throw new Error(data.error || '导入失败');
283
- }
284
- } catch (error) {
285
- console.error('Error:', error);
286
- alert('导入失败:' + error.message);
287
- }
288
- });
289
- </script>
290
  {% endblock %}
 
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}管理面板 - Wisdom Hub{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="dashboard-container" style="
7
+ max-width: 1200px;
8
+ margin: 0 auto;
9
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.8));
10
+ backdrop-filter: blur(10px);
11
+ border-radius: 24px;
12
+ box-shadow: 0 8px 32px rgba(99, 145, 197, 0.15);
13
+ border: 1px solid rgba(99, 145, 197, 0.2);
14
+ padding: 2rem;
15
+ ">
16
+ <div class="dashboard-header" style="
17
+ display: flex;
18
+ justify-content: space-between;
19
+ align-items: center;
20
+ margin-bottom: 2rem;
21
+ padding-bottom: 1.5rem;
22
+ border-bottom: 2px solid #B3CFEF;
23
+ ">
24
+ <div style="display: flex; align-items: center; gap: 1rem;">
25
+ <i class="fas fa-chart-line" style="
26
+ font-size: 2rem;
27
+ color: #6391C5;
28
+ "></i>
29
+ <h2 style="
30
+ font-size: 1.75rem;
31
+ font-weight: 600;
32
+ color: #6391C5;
33
+ margin: 0;
34
+ ">文章管理</h2>
35
+ </div>
36
+
37
+ <div class="dashboard-actions" style="
38
+ display: flex;
39
+ gap: 1rem;
40
+ ">
41
+ <button onclick="location.href='{{ url_for('admin.editor') }}'" style="
42
+ padding: 0.75rem 1.5rem;
43
+ background: linear-gradient(135deg, #6391C5, #C5CDFD);
44
+ color: white;
45
+ border: none;
46
+ border-radius: 12px;
47
+ font-weight: 500;
48
+ cursor: pointer;
49
+ transition: all 0.3s ease;
50
+ display: flex;
51
+ align-items: center;
52
+ gap: 0.5rem;
53
+ ">
54
+ <i class="fas fa-plus"></i>
55
+ 新建文章
56
+ </button>
57
+
58
+ <button onclick="exportData()" style="
59
+ padding: 0.75rem 1.5rem;
60
+ background: rgba(99, 145, 197, 0.1);
61
+ color: #6391C5;
62
+ border: 2px solid #B3CFEF;
63
+ border-radius: 12px;
64
+ font-weight: 500;
65
+ cursor: pointer;
66
+ transition: all 0.3s ease;
67
+ display: flex;
68
+ align-items: center;
69
+ gap: 0.5rem;
70
+ ">
71
+ <i class="fas fa-download"></i>
72
+ 导出数据
73
+ </button>
74
+
75
+ <button onclick="document.getElementById('importInput').click()" style="
76
+ padding: 0.75rem 1.5rem;
77
+ background: rgba(99, 145, 197, 0.1);
78
+ color: #6391C5;
79
+ border: 2px solid #B3CFEF;
80
+ border-radius: 12px;
81
+ font-weight: 500;
82
+ cursor: pointer;
83
+ transition: all 0.3s ease;
84
+ display: flex;
85
+ align-items: center;
86
+ gap: 0.5rem;
87
+ ">
88
+ <i class="fas fa-upload"></i>
89
+ 导入数据
90
+ </button>
91
+ <input type="file" id="importInput" style="display: none" accept=".db">
92
+ </div>
93
+ </div>
94
+
95
+ <div class="articles-table" style="
96
+ background: white;
97
+ border-radius: 16px;
98
+ box-shadow: 0 4px 16px rgba(99, 145, 197, 0.1);
99
+ overflow: hidden;
100
+ ">
101
+ <table style="width: 100%; border-collapse: collapse;">
102
+ <thead>
103
+ <tr style="background: #FEEEDA;">
104
+ <th style="
105
+ text-align: left;
106
+ padding: 1rem 1.5rem;
107
+ color: #6391C5;
108
+ font-weight: 600;
109
+ border-bottom: 2px solid #B3CFEF;
110
+ ">标题</th>
111
+ <th style="
112
+ text-align: left;
113
+ padding: 1rem 1.5rem;
114
+ color: #6391C5;
115
+ font-weight: 600;
116
+ border-bottom: 2px solid #B3CFEF;
117
+ ">创建时间</th>
118
+ <th style="
119
+ text-align: left;
120
+ padding: 1rem 1.5rem;
121
+ color: #6391C5;
122
+ font-weight: 600;
123
+ border-bottom: 2px solid #B3CFEF;
124
+ ">更新时间</th>
125
+ <th style="
126
+ text-align: left;
127
+ padding: 1rem 1.5rem;
128
+ color: #6391C5;
129
+ font-weight: 600;
130
+ border-bottom: 2px solid #B3CFEF;
131
+ ">操作</th>
132
+ </tr>
133
+ </thead>
134
+ <tbody>
135
+ {% for article in articles %}
136
+ <tr style="transition: all 0.3s ease;">
137
+ <td style="
138
+ padding: 1rem 1.5rem;
139
+ border-bottom: 1px solid #B3CFEF;
140
+ color: #6391C5;
141
+ ">{{ article.title }}</td>
142
+ <td style="
143
+ padding: 1rem 1.5rem;
144
+ border-bottom: 1px solid #B3CFEF;
145
+ color: #6391C5;
146
+ ">{{ article.created_at.strftime('%Y-%m-%d') }}</td>
147
+ <td style="
148
+ padding: 1rem 1.5rem;
149
+ border-bottom: 1px solid #B3CFEF;
150
+ color: #6391C5;
151
+ ">{{ article.updated_at.strftime('%Y-%m-%d') }}</td>
152
+ <td style="
153
+ padding: 1rem 1.5rem;
154
+ border-bottom: 1px solid #B3CFEF;
155
+ ">
156
+ <div style="display: flex; gap: 0.5rem;">
157
+ <a href="{{ url_for('admin.editor', slug=article.slug) }}" style="
158
+ padding: 0.5rem 1rem;
159
+ background: linear-gradient(135deg, #6391C5, #C5CDFD);
160
+ color: white;
161
+ border-radius: 8px;
162
+ text-decoration: none;
163
+ font-size: 0.875rem;
164
+ transition: all 0.3s ease;
165
+ ">编辑</a>
166
+ <button onclick="deleteArticle('{{ article.slug }}')" style="
167
+ padding: 0.5rem 1rem;
168
+ background: rgba(255, 71, 87, 0.1);
169
+ color: #ff4757;
170
+ border: 1px solid rgba(255, 71, 87, 0.2);
171
+ border-radius: 8px;
172
+ font-size: 0.875rem;
173
+ cursor: pointer;
174
+ transition: all 0.3s ease;
175
+ ">删除</button>
176
+ </div>
177
+ </td>
178
+ </tr>
179
+ {% endfor %}
180
+ </tbody>
181
+ </table>
182
+ </div>
183
+ </div>
184
+
185
+ <script>
186
+ // 表格行悬停效果
187
+ document.querySelectorAll('tbody tr').forEach(row => {
188
+ row.addEventListener('mouseenter', () => {
189
+ row.style.background = 'rgba(99, 145, 197, 0.05)';
190
+ });
191
+ row.addEventListener('mouseleave', () => {
192
+ row.style.background = 'white';
193
+ });
194
+ });
195
+
196
+ // 按钮悬停效果
197
+ document.querySelectorAll('button').forEach(button => {
198
+ button.addEventListener('mouseenter', () => {
199
+ if (button.style.background.includes('linear-gradient')) {
200
+ button.style.transform = 'translateY(-2px)';
201
+ button.style.boxShadow = '0 4px 12px rgba(99, 145, 197, 0.2)';
202
+ } else if (button.style.background.includes('rgba(255, 71, 87')) {
203
+ button.style.background = 'rgba(255, 71, 87, 0.2)';
204
+ } else {
205
+ button.style.borderColor = '#6391C5';
206
+ button.style.background = 'rgba(99, 145, 197, 0.15)';
207
+ }
208
+ });
209
+
210
+ button.addEventListener('mouseleave', () => {
211
+ if (button.style.background.includes('linear-gradient')) {
212
+ button.style.transform = 'none';
213
+ button.style.boxShadow = 'none';
214
+ } else if (button.style.background.includes('rgba(255, 71, 87')) {
215
+ button.style.background = 'rgba(255, 71, 87, 0.1)';
216
+ } else {
217
+ button.style.borderColor = '#B3CFEF';
218
+ button.style.background = 'rgba(99, 145, 197, 0.1)';
219
+ }
220
+ });
221
+ });
222
+
223
+ // 编辑链接悬停效果
224
+ document.querySelectorAll('a').forEach(link => {
225
+ if (link.style.background.includes('linear-gradient')) {
226
+ link.addEventListener('mouseenter', () => {
227
+ link.style.transform = 'translateY(-2px)';
228
+ link.style.boxShadow = '0 4px 12px rgba(99, 145, 197, 0.2)';
229
+ });
230
+
231
+ link.addEventListener('mouseleave', () => {
232
+ link.style.transform = 'none';
233
+ link.style.boxShadow = 'none';
234
+ });
235
+ }
236
+ });
237
+
238
+ async function deleteArticle(slug) {
239
+ if (!confirm('确定要删除这篇文章吗?')) return;
240
+
241
+ try {
242
+ const response = await fetch(`/api/articles/${slug}`, {
243
+ method: 'DELETE'
244
+ });
245
+
246
+ if (response.ok) {
247
+ location.reload();
248
+ }
249
+ } catch (error) {
250
+ console.error('Error:', error);
251
+ alert('删除失败,请重试');
252
+ }
253
+ }
254
+
255
+ async function exportData() {
256
+ try {
257
+ window.location.href = '/api/export';
258
+ } catch (error) {
259
+ console.error('Error:', error);
260
+ alert('导出失败,请重试');
261
+ }
262
+ }
263
+
264
+ document.getElementById('importInput').addEventListener('change', async (event) => {
265
+ const file = event.target.files[0];
266
+ if (!file) return;
267
+
268
+ try {
269
+ const formData = new FormData();
270
+ formData.append('file', file);
271
+
272
+ const response = await fetch('/api/import', {
273
+ method: 'POST',
274
+ body: formData
275
+ });
276
+
277
+ const data = await response.json();
278
+ if (response.ok) {
279
+ alert('导入成功,页面将刷新');
280
+ location.reload();
281
+ } else {
282
+ throw new Error(data.error || '导入失败');
283
+ }
284
+ } catch (error) {
285
+ console.error('Error:', error);
286
+ alert('导入失败:' + error.message);
287
+ }
288
+ });
289
+ </script>
290
  {% endblock %}