PharC commited on
Commit
47d60cb
·
verified ·
1 Parent(s): b636fe9

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +536 -0
templates/index.html CHANGED
@@ -0,0 +1,536 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>qPCR引物设计工具</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
+ min-height: 100vh;
18
+ padding: 20px;
19
+ }
20
+
21
+ .container {
22
+ max-width: 1200px;
23
+ margin: 0 auto;
24
+ background: white;
25
+ border-radius: 15px;
26
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
27
+ overflow: hidden;
28
+ }
29
+
30
+ .header {
31
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
32
+ color: white;
33
+ padding: 30px;
34
+ text-align: center;
35
+ }
36
+
37
+ .header h1 {
38
+ font-size: 2.5em;
39
+ margin-bottom: 10px;
40
+ }
41
+
42
+ .header p {
43
+ font-size: 1.1em;
44
+ opacity: 0.9;
45
+ }
46
+
47
+ .form-section {
48
+ padding: 40px;
49
+ }
50
+
51
+ .tab-container {
52
+ margin-bottom: 30px;
53
+ }
54
+
55
+ .tab-buttons {
56
+ display: flex;
57
+ border-bottom: 2px solid #e1e5e9;
58
+ margin-bottom: 20px;
59
+ }
60
+
61
+ .tab-button {
62
+ padding: 12px 24px;
63
+ background: none;
64
+ border: none;
65
+ cursor: pointer;
66
+ font-size: 16px;
67
+ font-weight: 600;
68
+ color: #666;
69
+ border-bottom: 3px solid transparent;
70
+ transition: all 0.3s;
71
+ }
72
+
73
+ .tab-button.active {
74
+ color: #4facfe;
75
+ border-bottom-color: #4facfe;
76
+ }
77
+
78
+ .tab-content {
79
+ display: none;
80
+ }
81
+
82
+ .tab-content.active {
83
+ display: block;
84
+ }
85
+
86
+ .batch-input {
87
+ margin-bottom: 20px;
88
+ }
89
+
90
+ .batch-textarea {
91
+ width: 100%;
92
+ min-height: 150px;
93
+ padding: 15px;
94
+ border: 2px solid #e1e5e9;
95
+ border-radius: 8px;
96
+ font-size: 14px;
97
+ font-family: 'Courier New', monospace;
98
+ resize: vertical;
99
+ }
100
+
101
+ .batch-help {
102
+ background: #f8f9fa;
103
+ padding: 15px;
104
+ border-radius: 8px;
105
+ margin-bottom: 20px;
106
+ font-size: 14px;
107
+ color: #666;
108
+ }
109
+
110
+ .export-section {
111
+ background: #f8f9fa;
112
+ padding: 20px;
113
+ border-radius: 8px;
114
+ margin-top: 20px;
115
+ }
116
+
117
+ .export-buttons {
118
+ display: flex;
119
+ gap: 10px;
120
+ flex-wrap: wrap;
121
+ }
122
+
123
+ .export-btn {
124
+ background: #28a745;
125
+ color: white;
126
+ padding: 10px 20px;
127
+ border: none;
128
+ border-radius: 6px;
129
+ cursor: pointer;
130
+ font-size: 14px;
131
+ font-weight: 600;
132
+ transition: background 0.3s;
133
+ }
134
+
135
+ .export-btn:hover {
136
+ background: #218838;
137
+ }
138
+
139
+ .export-btn:disabled {
140
+ background: #6c757d;
141
+ cursor: not-allowed;
142
+ }
143
+
144
+ .batch-progress {
145
+ display: none;
146
+ margin: 20px 0;
147
+ }
148
+
149
+ .progress-bar {
150
+ width: 100%;
151
+ height: 20px;
152
+ background: #e1e5e9;
153
+ border-radius: 10px;
154
+ overflow: hidden;
155
+ }
156
+
157
+ .progress-fill {
158
+ height: 100%;
159
+ background: linear-gradient(90deg, #4facfe, #00f2fe);
160
+ width: 0%;
161
+ transition: width 0.3s;
162
+ }
163
+
164
+ .progress-text {
165
+ text-align: center;
166
+ margin-top: 10px;
167
+ font-weight: 600;
168
+ }
169
+
170
+ .batch-results {
171
+ display: none;
172
+ }
173
+
174
+ .result-summary {
175
+ background: white;
176
+ padding: 20px;
177
+ border-radius: 8px;
178
+ margin-bottom: 20px;
179
+ display: flex;
180
+ justify-content: space-between;
181
+ align-items: center;
182
+ }
183
+
184
+ .summary-stats {
185
+ display: flex;
186
+ gap: 30px;
187
+ }
188
+
189
+ .stat-item {
190
+ text-align: center;
191
+ }
192
+
193
+ .stat-number {
194
+ font-size: 24px;
195
+ font-weight: bold;
196
+ color: #4facfe;
197
+ }
198
+
199
+ .stat-label {
200
+ font-size: 12px;
201
+ color: #666;
202
+ text-transform: uppercase;
203
+ }
204
+
205
+ .failed-genes {
206
+ background: #fff3cd;
207
+ border: 1px solid #ffeaa7;
208
+ padding: 15px;
209
+ border-radius: 8px;
210
+ margin-bottom: 20px;
211
+ }
212
+
213
+ .failed-gene {
214
+ margin-bottom: 10px;
215
+ padding: 8px;
216
+ background: white;
217
+ border-radius: 4px;
218
+ border-left: 3px solid #e17055;
219
+ }
220
+
221
+ .form-group {
222
+ margin-bottom: 25px;
223
+ }
224
+
225
+ label {
226
+ display: block;
227
+ margin-bottom: 8px;
228
+ font-weight: 600;
229
+ color: #333;
230
+ }
231
+
232
+ input, select {
233
+ width: 100%;
234
+ padding: 12px 15px;
235
+ border: 2px solid #e1e5e9;
236
+ border-radius: 8px;
237
+ font-size: 16px;
238
+ transition: border-color 0.3s;
239
+ }
240
+
241
+ input:focus, select:focus {
242
+ outline: none;
243
+ border-color: #4facfe;
244
+ }
245
+
246
+ .btn {
247
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
248
+ color: white;
249
+ padding: 15px 30px;
250
+ border: none;
251
+ border-radius: 8px;
252
+ font-size: 16px;
253
+ font-weight: 600;
254
+ cursor: pointer;
255
+ transition: transform 0.2s;
256
+ width: 100%;
257
+ }
258
+
259
+ .btn:hover {
260
+ transform: translateY(-2px);
261
+ }
262
+
263
+ .btn:disabled {
264
+ opacity: 0.6;
265
+ cursor: not-allowed;
266
+ transform: none;
267
+ }
268
+
269
+ .loading {
270
+ display: none;
271
+ text-align: center;
272
+ padding: 20px;
273
+ }
274
+
275
+ .spinner {
276
+ border: 4px solid #f3f3f3;
277
+ border-top: 4px solid #4facfe;
278
+ border-radius: 50%;
279
+ width: 40px;
280
+ height: 40px;
281
+ animation: spin 1s linear infinite;
282
+ margin: 0 auto 10px;
283
+ }
284
+
285
+ @keyframes spin {
286
+ 0% { transform: rotate(0deg); }
287
+ 100% { transform: rotate(360deg); }
288
+ }
289
+
290
+ .results {
291
+ display: none;
292
+ padding: 40px;
293
+ background: #f8f9fa;
294
+ }
295
+
296
+ .gene-info {
297
+ background: white;
298
+ padding: 20px;
299
+ border-radius: 8px;
300
+ margin-bottom: 30px;
301
+ border-left: 4px solid #4facfe;
302
+ }
303
+
304
+ .primer-card {
305
+ background: white;
306
+ border-radius: 8px;
307
+ padding: 20px;
308
+ margin-bottom: 20px;
309
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
310
+ }
311
+
312
+ .primer-header {
313
+ display: flex;
314
+ justify-content: space-between;
315
+ align-items: center;
316
+ margin-bottom: 15px;
317
+ }
318
+
319
+ .primer-id {
320
+ background: #4facfe;
321
+ color: white;
322
+ padding: 5px 15px;
323
+ border-radius: 20px;
324
+ font-weight: 600;
325
+ }
326
+
327
+ .product-size {
328
+ background: #e8f5e8;
329
+ color: #2d5a2d;
330
+ padding: 5px 15px;
331
+ border-radius: 20px;
332
+ font-weight: 600;
333
+ }
334
+
335
+ .primer-sequences {
336
+ display: grid;
337
+ grid-template-columns: 1fr 1fr;
338
+ gap: 20px;
339
+ margin-bottom: 15px;
340
+ }
341
+
342
+ .sequence-box {
343
+ background: #f8f9fa;
344
+ padding: 15px;
345
+ border-radius: 6px;
346
+ border-left: 3px solid #4facfe;
347
+ }
348
+
349
+ .sequence-label {
350
+ font-weight: 600;
351
+ color: #666;
352
+ margin-bottom: 5px;
353
+ }
354
+
355
+ .sequence {
356
+ font-family: 'Courier New', monospace;
357
+ font-size: 14px;
358
+ word-break: break-all;
359
+ background: white;
360
+ padding: 8px;
361
+ border-radius: 4px;
362
+ border: 1px solid #e1e5e9;
363
+ }
364
+
365
+ .tm-info {
366
+ display: flex;
367
+ justify-content: space-between;
368
+ font-size: 14px;
369
+ color: #666;
370
+ }
371
+
372
+ .error {
373
+ background: #fee;
374
+ color: #c33;
375
+ padding: 15px;
376
+ border-radius: 8px;
377
+ border-left: 4px solid #c33;
378
+ margin: 20px 0;
379
+ }
380
+
381
+ @media (max-width: 768px) {
382
+ .primer-sequences {
383
+ grid-template-columns: 1fr;
384
+ }
385
+
386
+ .primer-header {
387
+ flex-direction: column;
388
+ gap: 10px;
389
+ }
390
+ }
391
+ </style>
392
+ </head>
393
+ <body>
394
+ <div class="container">
395
+ <div class="header">
396
+ <h1>🧬 qPCR引物设计工具</h1>
397
+ <p>输入基因名称和物种,自动设计跨越外显子交界点的qPCR引物</p>
398
+ <p style="margin-top: 15px; font-size: 0.9em; opacity: 0.8;">Developed by PharC | Contact: pc794797023@163.com</p>
399
+ </div>
400
+
401
+ <div class="form-section">
402
+ <div class="tab-container">
403
+ <div class="tab-buttons">
404
+ <button type="button" class="tab-button active" onclick="switchTab('single')">
405
+ 🧬 单个基因
406
+ </button>
407
+ <button type="button" class="tab-button" onclick="switchTab('batch')">
408
+ 📋 批量处理
409
+ </button>
410
+ </div>
411
+
412
+ <!-- 单个基因设计 -->
413
+ <div id="single-tab" class="tab-content active">
414
+ <form id="primerForm">
415
+ <div class="form-group">
416
+ <label for="geneSymbol">基因名称 *</label>
417
+ <input type="text" id="geneSymbol" name="geneSymbol" placeholder="例如: GAPDH, Gpr34" required>
418
+ </div>
419
+
420
+ <div class="form-group">
421
+ <label for="species">物种</label>
422
+ <select id="species" name="species">
423
+ <option value="human">人类 (Human)</option>
424
+ <option value="Mus musculus">小鼠 (Mouse)</option>
425
+ <option value="Rattus norvegicus">大鼠 (Rat)</option>
426
+ <option value="Drosophila melanogaster">果蝇 (Drosophila)</option>
427
+ <option value="Caenorhabditis elegans">线虫 (C. elegans)</option>
428
+ <option value="Danio rerio">斑马鱼 (Zebrafish)</option>
429
+ </select>
430
+ </div>
431
+
432
+ <button type="submit" class="btn" id="submitBtn">
433
+ 🔬 设计引物
434
+ </button>
435
+ </form>
436
+ </div>
437
+
438
+ <!-- 批量基因设计 -->
439
+ <div id="batch-tab" class="tab-content">
440
+ <form id="batchForm">
441
+ <div class="batch-help">
442
+ 💡 <strong>使用说明:</strong>每行输入一个基因名称,支持多种格式:
443
+ <br>• 一行一个基因:GAPDH
444
+ <br>• 逗号分隔:GAPDH, ACTB, TUBB3
445
+ <br>• 空格分隔:GAPDH ACTB TUBB3
446
+ </div>
447
+
448
+ <div class="form-group">
449
+ <label for="batchGenes">基因列表 *</label>
450
+ <textarea
451
+ id="batchGenes"
452
+ class="batch-textarea"
453
+ placeholder="请输入基因名称,每行一个或用逗号/空格分隔:&#10;GAPDH&#10;ACTB&#10;TUBB3&#10;或者:GAPDH, ACTB, TUBB3"
454
+ required
455
+ ></textarea>
456
+ </div>
457
+
458
+ <div class="form-group">
459
+ <label for="batchSpecies">物种</label>
460
+ <select id="batchSpecies" name="batchSpecies">
461
+ <option value="human">人类 (Human)</option>
462
+ <option value="Mus musculus">小鼠 (Mouse)</option>
463
+ <option value="Rattus norvegicus">大鼠 (Rat)</option>
464
+ <option value="Drosophila melanogaster">果蝇 (Drosophila)</option>
465
+ <option value="Caenorhabditis elegans">线虫 (C. elegans)</option>
466
+ <option value="Danio rerio">斑马鱼 (Zebrafish)</option>
467
+ </select>
468
+ </div>
469
+
470
+ <button type="submit" class="btn" id="batchSubmitBtn">
471
+ 🚀 批量设计引物
472
+ </button>
473
+ </form>
474
+
475
+ <div class="batch-progress" id="batchProgress">
476
+ <div class="progress-bar">
477
+ <div class="progress-fill" id="progressFill"></div>
478
+ </div>
479
+ <div class="progress-text" id="progressText">正在处理: 0/0</div>
480
+ </div>
481
+ </div>
482
+ </div>
483
+ </div>
484
+
485
+ <div class="loading" id="loading">
486
+ <div class="spinner"></div>
487
+ <p>正在设计引物,请稍候...</p>
488
+ </div>
489
+
490
+ <div class="results" id="results">
491
+ <div class="gene-info" id="geneInfo"></div>
492
+ <div id="primerResults"></div>
493
+
494
+ <div class="export-section" id="exportSection" style="display: none;">
495
+ <h4>📥 导出结果</h4>
496
+ <p>选择导出格式:</p>
497
+ <div class="export-buttons">
498
+ <button class="export-btn" onclick="exportResults('excel')">
499
+ 📊 Excel格式
500
+ </button>
501
+ <button class="export-btn" onclick="exportResults('csv')">
502
+ 📄 CSV格式
503
+ </button>
504
+ <button class="export-btn" onclick="exportResults('json')">
505
+ 🔧 JSON格式
506
+ </button>
507
+ </div>
508
+ </div>
509
+ </div>
510
+
511
+ <div class="batch-results" id="batchResults">
512
+ <div class="result-summary" id="resultSummary"></div>
513
+ <div id="failedGenes"></div>
514
+ <div id="batchPrimerResults"></div>
515
+
516
+ <div class="export-section">
517
+ <h4>📥 导出批量结果</h4>
518
+ <p>选择导出格式:</p>
519
+ <div class="export-buttons">
520
+ <button class="export-btn" onclick="exportBatchResults('excel')">
521
+ 📊 Excel格式
522
+ </button>
523
+ <button class="export-btn" onclick="exportBatchResults('csv')">
524
+ 📄 CSV格式
525
+ </button>
526
+ <button class="export-btn" onclick="exportBatchResults('json')">
527
+ 🔧 JSON格式
528
+ </button>
529
+ </div>
530
+ </div>
531
+ </div>
532
+ </div>
533
+
534
+ <script src="{{ url_for('static', filename='app.js') }}"></script>
535
+ </body>
536
+ </html>