Hugo-Jiang commited on
Commit
73f3779
·
1 Parent(s): 42a0809

update GUI

Browse files
Files changed (3) hide show
  1. static/css/style.css +139 -105
  2. static/js/app.js +29 -2
  3. templates/index.html +15 -15
static/css/style.css CHANGED
@@ -6,26 +6,29 @@
6
  }
7
 
8
  :root {
9
- --primary-color: #667eea;
10
- --primary-dark: #5a67d8;
11
- --secondary-color: #764ba2;
12
- --success-color: #48bb78;
13
- --error-color: #f56565;
14
- --warning-color: #ed8936;
15
- --text-color: #2d3748;
16
- --text-light: #718096;
17
- --bg-light: #f7fafc;
18
- --border-color: #e2e8f0;
19
- --card-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
20
- --card-shadow-hover: 0 8px 25px rgba(0, 0, 0, 0.15);
 
21
  }
22
 
23
  body {
24
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
25
- background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
26
  min-height: 100vh;
27
  padding: 20px;
28
  color: var(--text-color);
 
 
29
  }
30
 
31
  /* ==================== 容器 ==================== */
@@ -37,31 +40,34 @@ body {
37
  /* ==================== 头部 ==================== */
38
  header {
39
  text-align: center;
40
- color: white;
41
- margin-bottom: 30px;
42
- padding: 20px 0;
43
  }
44
 
45
  header h1 {
46
- font-size: 2.5rem;
47
- margin-bottom: 15px;
48
- text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
 
 
49
  }
50
 
51
  .header-info {
52
  display: flex;
53
  justify-content: center;
54
- gap: 30px;
55
  flex-wrap: wrap;
56
  }
57
 
58
  .header-info p {
59
- opacity: 0.9;
60
- font-size: 0.95rem;
 
61
  }
62
 
63
  .header-info .label {
64
- opacity: 0.7;
 
65
  }
66
 
67
  /* ==================== 工具栏 ==================== */
@@ -91,18 +97,21 @@ header h1 {
91
 
92
  .search-box input {
93
  width: 100%;
94
- padding: 15px 20px 15px 45px;
95
- border: none;
96
- border-radius: 12px;
97
  font-size: 1rem;
 
 
 
98
  box-shadow: var(--card-shadow);
99
- transition: box-shadow 0.3s, transform 0.2s;
100
  }
101
 
102
  .search-box input:focus {
103
  outline: none;
104
- box-shadow: var(--card-shadow-hover);
105
- transform: translateY(-1px);
106
  }
107
 
108
  /* 筛选按钮 */
@@ -112,36 +121,43 @@ header h1 {
112
  }
113
 
114
  .filter-btn {
115
- padding: 12px 24px;
116
- border: none;
117
- border-radius: 12px;
118
- background: white;
 
 
119
  color: var(--text-color);
120
- font-size: 0.95rem;
 
121
  cursor: pointer;
122
  box-shadow: var(--card-shadow);
123
- transition: all 0.3s;
124
  }
125
 
126
  .filter-btn:hover {
127
- transform: translateY(-2px);
128
- box-shadow: var(--card-shadow-hover);
129
  }
130
 
131
  .filter-btn.active {
132
  background: var(--primary-color);
133
  color: white;
 
134
  }
135
 
136
  /* ==================== 提示信息 ==================== */
137
  .tips {
138
  display: flex;
139
  align-items: center;
140
- gap: 10px;
141
- background: rgba(255, 255, 255, 0.9);
142
- padding: 15px 20px;
 
 
143
  border-radius: 12px;
144
- margin-bottom: 20px;
 
145
  box-shadow: var(--card-shadow);
146
  }
147
 
@@ -153,8 +169,9 @@ header h1 {
153
  }
154
 
155
  .tips span {
156
- color: var(--text-light);
157
- font-size: 0.9rem;
 
158
  }
159
 
160
  /* ==================== 加载状态 ==================== */
@@ -163,17 +180,16 @@ header h1 {
163
  flex-direction: column;
164
  align-items: center;
165
  justify-content: center;
166
- padding: 60px 20px;
167
- color: white;
168
  }
169
 
170
  .spinner {
171
- width: 50px;
172
- height: 50px;
173
- border: 4px solid rgba(255, 255, 255, 0.3);
174
- border-top-color: white;
175
  border-radius: 50%;
176
- animation: spin 1s linear infinite;
177
  margin-bottom: 20px;
178
  }
179
 
@@ -184,8 +200,9 @@ header h1 {
184
  }
185
 
186
  .loading p {
187
- font-size: 1.1rem;
188
- opacity: 0.9;
 
189
  }
190
 
191
  .loading.hidden {
@@ -196,17 +213,17 @@ header h1 {
196
  .error-message {
197
  display: flex;
198
  align-items: center;
199
- gap: 15px;
200
- background: #fff5f5;
201
- border: 1px solid #fed7d7;
202
- padding: 20px;
203
  border-radius: 12px;
204
- margin-bottom: 20px;
205
  }
206
 
207
  .error-message svg {
208
- width: 24px;
209
- height: 24px;
210
  color: var(--error-color);
211
  flex-shrink: 0;
212
  }
@@ -214,21 +231,25 @@ header h1 {
214
  .error-message span {
215
  flex: 1;
216
  color: var(--error-color);
 
 
217
  }
218
 
219
  .retry-btn {
220
- padding: 8px 20px;
221
  background: var(--error-color);
222
  color: white;
223
  border: none;
224
  border-radius: 8px;
225
  cursor: pointer;
226
- font-size: 0.9rem;
227
- transition: background 0.3s;
 
228
  }
229
 
230
  .retry-btn:hover {
231
- background: #e53e3e;
 
232
  }
233
 
234
  /* ==================== 货币网格 ==================== */
@@ -240,29 +261,33 @@ header h1 {
240
 
241
  /* ==================== 货币卡片 ==================== */
242
  .currency-card {
243
- background: white;
 
 
244
  border-radius: 16px;
245
- padding: 18px 20px;
246
  box-shadow: var(--card-shadow);
247
  display: flex;
248
  align-items: center;
249
- gap: 15px;
250
- transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s;
251
- border: 2px solid transparent;
252
  }
253
 
254
  .currency-card:hover {
255
- transform: translateY(-3px);
256
  box-shadow: var(--card-shadow-hover);
 
257
  }
258
 
259
  .currency-card.priority {
260
- border-left: 4px solid var(--primary-color);
261
  }
262
 
263
  .currency-card.active {
264
  border-color: var(--primary-color);
265
- background: linear-gradient(to right, #f8f9ff, white);
 
266
  }
267
 
268
  .currency-card.hidden {
@@ -271,17 +296,16 @@ header h1 {
271
 
272
  /* 货币图标/符号 */
273
  .currency-icon {
274
- width: 48px;
275
- height: 48px;
276
- background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
277
- border-radius: 12px;
278
  display: flex;
279
  align-items: center;
280
  justify-content: center;
281
- color: white;
282
- font-weight: bold;
283
- font-size: 1.1rem;
284
  flex-shrink: 0;
 
285
  }
286
 
287
  /* 货币信息 */
@@ -290,19 +314,20 @@ header h1 {
290
  }
291
 
292
  .currency-code {
293
- font-size: 1.25rem;
294
- font-weight: 700;
295
  color: var(--text-color);
296
- letter-spacing: 0.5px;
297
  }
298
 
299
  .currency-name {
300
- font-size: 0.85rem;
301
- color: var(--text-light);
302
  white-space: nowrap;
303
  overflow: hidden;
304
  text-overflow: ellipsis;
305
  max-width: 100px;
 
306
  }
307
 
308
  /* 输入区域 */
@@ -312,25 +337,28 @@ header h1 {
312
 
313
  .currency-input input {
314
  width: 100%;
315
- padding: 12px 15px;
316
- border: 2px solid var(--border-color);
317
  border-radius: 10px;
318
- font-size: 1.15rem;
319
  text-align: right;
320
  font-weight: 500;
321
- transition: border-color 0.3s, box-shadow 0.3s;
322
  color: var(--text-color);
 
323
  }
324
 
325
  .currency-input input:focus {
326
  outline: none;
327
  border-color: var(--primary-color);
328
- box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
 
329
  }
330
 
331
  .currency-input input::placeholder {
332
- color: #cbd5e0;
333
- font-weight: normal;
 
334
  }
335
 
336
  /* 禁用输入时去除 spinner */
@@ -346,44 +374,50 @@ header h1 {
346
 
347
  /* 汇率显示 */
348
  .currency-rate {
349
- font-size: 0.75rem;
350
- color: var(--text-light);
351
  text-align: right;
352
  margin-top: 6px;
 
353
  }
354
 
355
  /* ==================== 底部 ==================== */
356
  footer {
357
  text-align: center;
358
- padding: 30px 20px;
359
- color: rgba(255, 255, 255, 0.8);
360
- font-size: 0.9rem;
361
  }
362
 
363
  footer a {
364
- color: white;
365
  text-decoration: none;
366
  font-weight: 500;
 
367
  }
368
 
369
  footer a:hover {
370
- text-decoration: underline;
371
  }
372
 
373
  .footer-note {
374
  margin-top: 8px;
375
- opacity: 0.7;
376
- font-size: 0.85rem;
377
  }
378
 
379
  /* ==================== 响应式设计 ==================== */
380
  @media (max-width: 768px) {
381
  body {
382
- padding: 15px;
 
 
 
 
383
  }
384
 
385
  header h1 {
386
- font-size: 1.8rem;
387
  }
388
 
389
  .header-info {
@@ -412,9 +446,9 @@ footer a:hover {
412
  }
413
 
414
  .currency-icon {
415
- width: 42px;
416
- height: 42px;
417
- font-size: 1rem;
418
  }
419
 
420
  .currency-info {
 
6
  }
7
 
8
  :root {
9
+ --primary-color: #007AFF;
10
+ --primary-dark: #0051D5;
11
+ --secondary-color: #5856D6;
12
+ --success-color: #34C759;
13
+ --error-color: #FF3B30;
14
+ --warning-color: #FF9500;
15
+ --text-color: #1d1d1f;
16
+ --text-secondary: #86868b;
17
+ --bg-light: #f5f5f7;
18
+ --border-color: rgba(0, 0, 0, 0.08);
19
+ --card-bg: rgba(255, 255, 255, 0.72);
20
+ --card-shadow: 0 2px 16px rgba(0, 0, 0, 0.08);
21
+ --card-shadow-hover: 0 8px 32px rgba(0, 0, 0, 0.12);
22
  }
23
 
24
  body {
25
+ font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', Arial, sans-serif;
26
+ background: linear-gradient(180deg, #f5f5f7 0%, #e8e8ed 100%);
27
  min-height: 100vh;
28
  padding: 20px;
29
  color: var(--text-color);
30
+ -webkit-font-smoothing: antialiased;
31
+ -moz-osx-font-smoothing: grayscale;
32
  }
33
 
34
  /* ==================== 容器 ==================== */
 
40
  /* ==================== 头部 ==================== */
41
  header {
42
  text-align: center;
43
+ margin-bottom: 40px;
44
+ padding: 40px 0 20px;
 
45
  }
46
 
47
  header h1 {
48
+ font-size: 3rem;
49
+ font-weight: 600;
50
+ margin-bottom: 12px;
51
+ color: var(--text-color);
52
+ letter-spacing: -0.5px;
53
  }
54
 
55
  .header-info {
56
  display: flex;
57
  justify-content: center;
58
+ gap: 32px;
59
  flex-wrap: wrap;
60
  }
61
 
62
  .header-info p {
63
+ font-size: 0.9375rem;
64
+ color: var(--text-secondary);
65
+ font-weight: 400;
66
  }
67
 
68
  .header-info .label {
69
+ color: var(--text-secondary);
70
+ margin-right: 4px;
71
  }
72
 
73
  /* ==================== 工具栏 ==================== */
 
97
 
98
  .search-box input {
99
  width: 100%;
100
+ padding: 14px 20px 14px 45px;
101
+ border: 1px solid var(--border-color);
102
+ border-radius: 10px;
103
  font-size: 1rem;
104
+ background: var(--card-bg);
105
+ backdrop-filter: blur(20px);
106
+ -webkit-backdrop-filter: blur(20px);
107
  box-shadow: var(--card-shadow);
108
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
109
  }
110
 
111
  .search-box input:focus {
112
  outline: none;
113
+ border-color: var(--primary-color);
114
+ box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1), var(--card-shadow);
115
  }
116
 
117
  /* 筛选按钮 */
 
121
  }
122
 
123
  .filter-btn {
124
+ padding: 10px 20px;
125
+ border: 1px solid var(--border-color);
126
+ border-radius: 10px;
127
+ background: var(--card-bg);
128
+ backdrop-filter: blur(20px);
129
+ -webkit-backdrop-filter: blur(20px);
130
  color: var(--text-color);
131
+ font-size: 0.9375rem;
132
+ font-weight: 500;
133
  cursor: pointer;
134
  box-shadow: var(--card-shadow);
135
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
136
  }
137
 
138
  .filter-btn:hover {
139
+ background: rgba(255, 255, 255, 0.9);
140
+ transform: translateY(-1px);
141
  }
142
 
143
  .filter-btn.active {
144
  background: var(--primary-color);
145
  color: white;
146
+ border-color: var(--primary-color);
147
  }
148
 
149
  /* ==================== 提示信息 ==================== */
150
  .tips {
151
  display: flex;
152
  align-items: center;
153
+ gap: 12px;
154
+ background: var(--card-bg);
155
+ backdrop-filter: blur(20px);
156
+ -webkit-backdrop-filter: blur(20px);
157
+ padding: 16px 20px;
158
  border-radius: 12px;
159
+ margin-bottom: 24px;
160
+ border: 1px solid var(--border-color);
161
  box-shadow: var(--card-shadow);
162
  }
163
 
 
169
  }
170
 
171
  .tips span {
172
+ color: var(--text-secondary);
173
+ font-size: 0.875rem;
174
+ line-height: 1.5;
175
  }
176
 
177
  /* ==================== 加载状态 ==================== */
 
180
  flex-direction: column;
181
  align-items: center;
182
  justify-content: center;
183
+ padding: 80px 20px;
 
184
  }
185
 
186
  .spinner {
187
+ width: 44px;
188
+ height: 44px;
189
+ border: 3px solid rgba(0, 122, 255, 0.2);
190
+ border-top-color: var(--primary-color);
191
  border-radius: 50%;
192
+ animation: spin 0.8s linear infinite;
193
  margin-bottom: 20px;
194
  }
195
 
 
200
  }
201
 
202
  .loading p {
203
+ font-size: 1.0625rem;
204
+ color: var(--text-secondary);
205
+ font-weight: 500;
206
  }
207
 
208
  .loading.hidden {
 
213
  .error-message {
214
  display: flex;
215
  align-items: center;
216
+ gap: 16px;
217
+ background: rgba(255, 59, 48, 0.08);
218
+ border: 1px solid rgba(255, 59, 48, 0.2);
219
+ padding: 20px 24px;
220
  border-radius: 12px;
221
+ margin-bottom: 24px;
222
  }
223
 
224
  .error-message svg {
225
+ width: 22px;
226
+ height: 22px;
227
  color: var(--error-color);
228
  flex-shrink: 0;
229
  }
 
231
  .error-message span {
232
  flex: 1;
233
  color: var(--error-color);
234
+ font-size: 0.9375rem;
235
+ font-weight: 500;
236
  }
237
 
238
  .retry-btn {
239
+ padding: 8px 18px;
240
  background: var(--error-color);
241
  color: white;
242
  border: none;
243
  border-radius: 8px;
244
  cursor: pointer;
245
+ font-size: 0.875rem;
246
+ font-weight: 600;
247
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
248
  }
249
 
250
  .retry-btn:hover {
251
+ background: #d70015;
252
+ transform: scale(1.02);
253
  }
254
 
255
  /* ==================== 货币网格 ==================== */
 
261
 
262
  /* ==================== 货币卡片 ==================== */
263
  .currency-card {
264
+ background: var(--card-bg);
265
+ backdrop-filter: blur(20px);
266
+ -webkit-backdrop-filter: blur(20px);
267
  border-radius: 16px;
268
+ padding: 20px;
269
  box-shadow: var(--card-shadow);
270
  display: flex;
271
  align-items: center;
272
+ gap: 16px;
273
+ transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
274
+ border: 1px solid var(--border-color);
275
  }
276
 
277
  .currency-card:hover {
278
+ transform: translateY(-2px);
279
  box-shadow: var(--card-shadow-hover);
280
+ background: rgba(255, 255, 255, 0.85);
281
  }
282
 
283
  .currency-card.priority {
284
+ border-left: 3px solid var(--primary-color);
285
  }
286
 
287
  .currency-card.active {
288
  border-color: var(--primary-color);
289
+ background: rgba(255, 255, 255, 0.9);
290
+ box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1), var(--card-shadow-hover);
291
  }
292
 
293
  .currency-card.hidden {
 
296
 
297
  /* 货币图标/符号 */
298
  .currency-icon {
299
+ width: 52px;
300
+ height: 52px;
301
+ background: linear-gradient(135deg, rgba(0, 122, 255, 0.1), rgba(88, 86, 214, 0.1));
302
+ border-radius: 14px;
303
  display: flex;
304
  align-items: center;
305
  justify-content: center;
306
+ font-size: 1.5rem;
 
 
307
  flex-shrink: 0;
308
+ border: 1px solid rgba(0, 122, 255, 0.15);
309
  }
310
 
311
  /* 货币信息 */
 
314
  }
315
 
316
  .currency-code {
317
+ font-size: 1.125rem;
318
+ font-weight: 600;
319
  color: var(--text-color);
320
+ letter-spacing: -0.2px;
321
  }
322
 
323
  .currency-name {
324
+ font-size: 0.8125rem;
325
+ color: var(--text-secondary);
326
  white-space: nowrap;
327
  overflow: hidden;
328
  text-overflow: ellipsis;
329
  max-width: 100px;
330
+ font-weight: 400;
331
  }
332
 
333
  /* 输入区域 */
 
337
 
338
  .currency-input input {
339
  width: 100%;
340
+ padding: 12px 14px;
341
+ border: 1px solid var(--border-color);
342
  border-radius: 10px;
343
+ font-size: 1.0625rem;
344
  text-align: right;
345
  font-weight: 500;
346
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
347
  color: var(--text-color);
348
+ background: rgba(255, 255, 255, 0.6);
349
  }
350
 
351
  .currency-input input:focus {
352
  outline: none;
353
  border-color: var(--primary-color);
354
+ box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1);
355
+ background: rgba(255, 255, 255, 0.9);
356
  }
357
 
358
  .currency-input input::placeholder {
359
+ color: var(--text-secondary);
360
+ opacity: 0.5;
361
+ font-weight: 400;
362
  }
363
 
364
  /* 禁用输入时去除 spinner */
 
374
 
375
  /* 汇率显示 */
376
  .currency-rate {
377
+ font-size: 0.6875rem;
378
+ color: var(--text-secondary);
379
  text-align: right;
380
  margin-top: 6px;
381
+ font-weight: 400;
382
  }
383
 
384
  /* ==================== 底部 ==================== */
385
  footer {
386
  text-align: center;
387
+ padding: 40px 20px 30px;
388
+ color: var(--text-secondary);
389
+ font-size: 0.875rem;
390
  }
391
 
392
  footer a {
393
+ color: var(--primary-color);
394
  text-decoration: none;
395
  font-weight: 500;
396
+ transition: opacity 0.2s;
397
  }
398
 
399
  footer a:hover {
400
+ opacity: 0.7;
401
  }
402
 
403
  .footer-note {
404
  margin-top: 8px;
405
+ color: var(--text-secondary);
406
+ font-size: 0.8125rem;
407
  }
408
 
409
  /* ==================== 响应式设计 ==================== */
410
  @media (max-width: 768px) {
411
  body {
412
+ padding: 16px;
413
+ }
414
+
415
+ header {
416
+ padding: 24px 0 16px;
417
  }
418
 
419
  header h1 {
420
+ font-size: 2rem;
421
  }
422
 
423
  .header-info {
 
446
  }
447
 
448
  .currency-icon {
449
+ width: 44px;
450
+ height: 44px;
451
+ font-size: 1.25rem;
452
  }
453
 
454
  .currency-info {
static/js/app.js CHANGED
@@ -23,6 +23,17 @@ class CurrencyConverter {
23
  // 常用货币列表
24
  this.priorityCodes = ['CNY', 'USD', 'EUR', 'GBP', 'JPY', 'HKD', 'AUD', 'CAD', 'CHF', 'SGD', 'KRW', 'TWD', 'THB', 'MYR', 'INR', 'RUB'];
25
 
 
 
 
 
 
 
 
 
 
 
 
26
  // 初始化
27
  this.init();
28
  }
@@ -105,6 +116,22 @@ class CurrencyConverter {
105
  }
106
  }
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  /**
109
  * 渲染货币网格
110
  */
@@ -116,13 +143,13 @@ class CurrencyConverter {
116
  grid.innerHTML = this.currencies.map(currency => {
117
  const isPriority = this.priorityCodes.includes(currency.code);
118
  const rate = this.rates[currency.code] || 0;
119
- const symbol = currency.symbol || currency.code.substring(0, 2);
120
 
121
  return `
122
  <div class="currency-card ${isPriority ? 'priority' : ''}"
123
  data-code="${currency.code}"
124
  data-priority="${isPriority}">
125
- <div class="currency-icon">${symbol}</div>
126
  <div class="currency-info">
127
  <div class="currency-code">${currency.code}</div>
128
  <div class="currency-name" title="${currency.name}">${currency.name_cn}</div>
 
23
  // 常用货币列表
24
  this.priorityCodes = ['CNY', 'USD', 'EUR', 'GBP', 'JPY', 'HKD', 'AUD', 'CAD', 'CHF', 'SGD', 'KRW', 'TWD', 'THB', 'MYR', 'INR', 'RUB'];
25
 
26
+ // 货币国旗映射
27
+ this.currencyFlags = {
28
+ 'USD': '🇺🇸', 'EUR': '🇪🇺', 'GBP': '🇬🇧', 'JPY': '🇯🇵', 'CNY': '🇨🇳', 'AUD': '🇦🇺',
29
+ 'CAD': '🇨🇦', 'CHF': '🇨🇭', 'HKD': '🇭🇰', 'SGD': '🇸🇬', 'SEK': '🇸🇪', 'KRW': '🇰🇷',
30
+ 'NOK': '🇳🇴', 'NZD': '🇳🇿', 'INR': '🇮🇳', 'MXN': '🇲🇽', 'TWD': '🇹🇼', 'ZAR': '🇿🇦',
31
+ 'BRL': '🇧🇷', 'DKK': '🇩🇰', 'PLN': '🇵🇱', 'THB': '🇹🇭', 'MYR': '🇲🇾', 'HUF': '🇭🇺',
32
+ 'CZK': '🇨🇿', 'ILS': '🇮🇱', 'CLP': '🇨🇱', 'PHP': '🇵🇭', 'AED': '🇦🇪', 'SAR': '🇸🇦',
33
+ 'TRY': '🇹🇷', 'RUB': '🇷🇺', 'IDR': '🇮🇩', 'VND': '🇻🇳', 'ARS': '🇦🇷', 'EGP': '🇪🇬',
34
+ 'PKR': '🇵🇰', 'BGN': '🇧🇬', 'RON': '🇷🇴', 'ISK': '🇮🇸', 'HRK': '🇭🇷', 'UAH': '🇺🇦'
35
+ };
36
+
37
  // 初始化
38
  this.init();
39
  }
 
116
  }
117
  }
118
 
119
+ /**
120
+ * 获取货币图标(国旗或符号)
121
+ */
122
+ getCurrencyIcon(currency) {
123
+ // 优先使用国旗 emoji
124
+ if (this.currencyFlags[currency.code]) {
125
+ return this.currencyFlags[currency.code];
126
+ }
127
+ // 使用货币符号
128
+ if (currency.symbol && currency.symbol.length <= 3) {
129
+ return currency.symbol;
130
+ }
131
+ // 默认使用代码前两个字母
132
+ return currency.code.substring(0, 2);
133
+ }
134
+
135
  /**
136
  * 渲染货币网格
137
  */
 
143
  grid.innerHTML = this.currencies.map(currency => {
144
  const isPriority = this.priorityCodes.includes(currency.code);
145
  const rate = this.rates[currency.code] || 0;
146
+ const icon = this.getCurrencyIcon(currency);
147
 
148
  return `
149
  <div class="currency-card ${isPriority ? 'priority' : ''}"
150
  data-code="${currency.code}"
151
  data-priority="${isPriority}">
152
+ <div class="currency-icon">${icon}</div>
153
  <div class="currency-info">
154
  <div class="currency-code">${currency.code}</div>
155
  <div class="currency-name" title="${currency.name}">${currency.name_cn}</div>
templates/index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>汇率换算器</title>
7
  <link rel="stylesheet" href="/static/css/style.css">
8
  <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>💱</text></svg>">
9
  </head>
@@ -11,15 +11,15 @@
11
  <div class="container">
12
  <!-- 头部 -->
13
  <header>
14
- <h1>💱 汇率换算器</h1>
15
  <div class="header-info">
16
  <p class="update-time">
17
- <span class="label">数据更新时间:</span>
18
- <span id="lastUpdate">加载中...</span>
19
  </p>
20
  <p class="currency-count">
21
- <span class="label">支持货币:</span>
22
- <span id="currencyCount">-</span>
23
  </p>
24
  </div>
25
  </header>
@@ -33,11 +33,11 @@
33
  <circle cx="11" cy="11" r="8"/>
34
  <path d="M21 21l-4.35-4.35"/>
35
  </svg>
36
- <input type="text" id="searchInput" placeholder="搜索货币代码或名称...">
37
  </div>
38
  <div class="filter-buttons">
39
- <button class="filter-btn active" data-filter="all">全部</button>
40
- <button class="filter-btn" data-filter="priority">常用</button>
41
  </div>
42
  </div>
43
 
@@ -47,13 +47,13 @@
47
  <circle cx="12" cy="12" r="10"/>
48
  <path d="M12 16v-4M12 8h.01"/>
49
  </svg>
50
- <span>在任意货币输入框中输入金额,其他货币将自动换算</span>
51
  </div>
52
 
53
  <!-- 加载状态 -->
54
  <div class="loading" id="loading">
55
  <div class="spinner"></div>
56
- <p>正在加载汇率数据...</p>
57
  </div>
58
 
59
  <!-- 错误提示 -->
@@ -62,8 +62,8 @@
62
  <circle cx="12" cy="12" r="10"/>
63
  <path d="M15 9l-6 6M9 9l6 6"/>
64
  </svg>
65
- <span id="errorText">加载失败</span>
66
- <button id="retryBtn" class="retry-btn">重试</button>
67
  </div>
68
 
69
  <!-- 货币列表 -->
@@ -74,8 +74,8 @@
74
 
75
  <!-- 底部 -->
76
  <footer>
77
- <p>数据来源: <a href="https://www.exchangerate-api.com/" target="_blank">ExchangeRate-API</a></p>
78
- <p class="footer-note">汇率每日更新 | 基准货币: <span id="baseCurrency">CNY</span></p>
79
  </footer>
80
  </div>
81
 
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Currency Converter · 汇率换算</title>
7
  <link rel="stylesheet" href="/static/css/style.css">
8
  <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>💱</text></svg>">
9
  </head>
 
11
  <div class="container">
12
  <!-- 头部 -->
13
  <header>
14
+ <h1>💱 Currency Converter</h1>
15
  <div class="header-info">
16
  <p class="update-time">
17
+ <span class="label">Last Update</span>
18
+ <span id="lastUpdate">Loading...</span>
19
  </p>
20
  <p class="currency-count">
21
+ <span class="label">Currencies</span>
22
+ <span id="currencyCount">-</span>
23
  </p>
24
  </div>
25
  </header>
 
33
  <circle cx="11" cy="11" r="8"/>
34
  <path d="M21 21l-4.35-4.35"/>
35
  </svg>
36
+ <input type="text" id="searchInput" placeholder="Search currency code or name...">
37
  </div>
38
  <div class="filter-buttons">
39
+ <button class="filter-btn active" data-filter="all">All</button>
40
+ <button class="filter-btn" data-filter="priority">Popular</button>
41
  </div>
42
  </div>
43
 
 
47
  <circle cx="12" cy="12" r="10"/>
48
  <path d="M12 16v-4M12 8h.01"/>
49
  </svg>
50
+ <span>Enter amount in any currency field to convert automatically</span>
51
  </div>
52
 
53
  <!-- 加载状态 -->
54
  <div class="loading" id="loading">
55
  <div class="spinner"></div>
56
+ <p>Loading exchange rates...</p>
57
  </div>
58
 
59
  <!-- 错误提示 -->
 
62
  <circle cx="12" cy="12" r="10"/>
63
  <path d="M15 9l-6 6M9 9l6 6"/>
64
  </svg>
65
+ <span id="errorText">Failed to load</span>
66
+ <button id="retryBtn" class="retry-btn">Retry</button>
67
  </div>
68
 
69
  <!-- 货币列表 -->
 
74
 
75
  <!-- 底部 -->
76
  <footer>
77
+ <p>Data Source: <a href="https://www.exchangerate-api.com/" target="_blank" rel="noopener">ExchangeRate-API</a></p>
78
+ <p class="footer-note">Daily Updates · Base Currency: <span id="baseCurrency">CNY</span></p>
79
  </footer>
80
  </div>
81