let currentResults = null; let currentBatchResults = null; // 标签页切换 function switchTab(tabName) { // 隐藏所有标签内容 document.querySelectorAll('.tab-content').forEach(tab => { tab.classList.remove('active'); }); document.querySelectorAll('.tab-button').forEach(btn => { btn.classList.remove('active'); }); // 显示选中的标签 document.getElementById(tabName + '-tab').classList.add('active'); event.target.classList.add('active'); // 隐藏结果区域 document.getElementById('results').style.display = 'none'; document.getElementById('batchResults').style.display = 'none'; } // 单个基因设计 document.getElementById('primerForm').addEventListener('submit', async function(e) { e.preventDefault(); const geneSymbol = document.getElementById('geneSymbol').value.trim(); const species = document.getElementById('species').value; if (!geneSymbol) { alert('请输入基因名称'); return; } // 显示加载状态 document.getElementById('loading').style.display = 'block'; document.getElementById('results').style.display = 'none'; document.getElementById('batchResults').style.display = 'none'; document.getElementById('submitBtn').disabled = true; try { const response = await fetch('/design_primers', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ gene_symbol: geneSymbol, species: species }) }); const data = await response.json(); if (data.error) { showError(data.error); } else { currentResults = [{ gene: geneSymbol, status: 'success', data: data }]; showResults(data); } } catch (error) { showError('网络错误,请检查连接后重试'); } finally { document.getElementById('loading').style.display = 'none'; document.getElementById('submitBtn').disabled = false; } }); // 批量基因设计 document.getElementById('batchForm').addEventListener('submit', async function(e) { e.preventDefault(); const batchGenesText = document.getElementById('batchGenes').value.trim(); const species = document.getElementById('batchSpecies').value; if (!batchGenesText) { alert('请输入基因列表'); return; } // 解析基因列表 const geneList = parseGeneList(batchGenesText); if (geneList.length === 0) { alert('未找到有效的基因名称'); return; } // 显示进度条 document.getElementById('batchProgress').style.display = 'block'; document.getElementById('results').style.display = 'none'; document.getElementById('batchResults').style.display = 'none'; document.getElementById('batchSubmitBtn').disabled = true; try { const response = await fetch('/batch_design_primers', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ gene_list: geneList, species: species }) }); const data = await response.json(); currentBatchResults = data.results; showBatchResults(data.results); } catch (error) { showError('网络错误,请检查连接后重试'); } finally { document.getElementById('batchProgress').style.display = 'none'; document.getElementById('batchSubmitBtn').disabled = false; } }); function parseGeneList(text) { // 支持多种分隔符:换行、逗号、空格 return text .split(/[\n,\s]+/) .map(gene => gene.trim()) .filter(gene => gene.length > 0); } function showError(message) { document.getElementById('results').innerHTML = `
❌ ${message}
`; document.getElementById('results').style.display = 'block'; } function showResults(data) { const geneInfo = data.gene_info; const primers = data.primers; // 显示基因信息 document.getElementById('geneInfo').innerHTML = `

📋 基因信息

基因名称: ${geneInfo.symbol}

RefSeq ID: ${geneInfo.nm_id}

外显子交界点: ${geneInfo.junctions.join(', ')}

`; // 显示引物结果 let primerHtml = '

🎯 推荐引物序列

'; primers.forEach(primer => { primerHtml += `
引物对 ${primer.id} ${primer.product_size} bp
正向引物 (Forward)
${primer.forward}
反向引物 (Reverse)
${primer.reverse}
正向Tm: ${primer.f_tm}°C 反向Tm: ${primer.r_tm}°C ${primer.junction_info}
`; }); document.getElementById('primerResults').innerHTML = primerHtml; document.getElementById('exportSection').style.display = 'block'; document.getElementById('results').style.display = 'block'; } function showBatchResults(results) { const successCount = results.filter(r => r.status === 'success').length; const failedCount = results.filter(r => r.status === 'failed').length; const totalPrimers = results .filter(r => r.status === 'success') .reduce((sum, r) => sum + r.data.primers.length, 0); // 显示统计信息 document.getElementById('resultSummary').innerHTML = `
${results.length}
总基因数
${successCount}
成功设计
${failedCount}
设计失败
${totalPrimers}
引物对总数
`; // 显示失败的基因 const failedGenes = results.filter(r => r.status === 'failed'); if (failedGenes.length > 0) { let failedHtml = '

⚠️ 设计失败的基因

'; failedGenes.forEach(gene => { failedHtml += `
${gene.gene}: ${gene.error}
`; }); failedHtml += '
'; document.getElementById('failedGenes').innerHTML = failedHtml; } else { document.getElementById('failedGenes').innerHTML = ''; } // 显示成功的引物结果 let primerHtml = '

🎯 批量引物设计结果

'; results.filter(r => r.status === 'success').forEach(result => { const geneInfo = result.data.gene_info; const primers = result.data.primers; primerHtml += `
`; primerHtml += `

📋 ${geneInfo.symbol} (${geneInfo.nm_id})

`; primers.forEach(primer => { primerHtml += `
引物对 ${primer.id} ${primer.product_size} bp
正向引物 (Forward)
${primer.forward}
反向引物 (Reverse)
${primer.reverse}
正向Tm: ${primer.f_tm}°C 反向Tm: ${primer.r_tm}°C ${primer.junction_info}
`; }); primerHtml += '
'; }); document.getElementById('batchPrimerResults').innerHTML = primerHtml; document.getElementById('batchResults').style.display = 'block'; } // 导出单个结果 async function exportResults(format) { if (!currentResults) { alert('没有可导出的结果'); return; } try { const response = await fetch('/export_primers', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ format: format, data: currentResults }) }); if (response.ok) { const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = response.headers.get('Content-Disposition')?.split('filename=')[1] || `primers.${format}`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } else { alert('导出失败,请重试'); } } catch (error) { alert('导出失败:' + error.message); } } // 导出批量结果 async function exportBatchResults(format) { if (!currentBatchResults) { alert('没有可导出的结果'); return; } try { const response = await fetch('/export_primers', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ format: format, data: currentBatchResults }) }); if (response.ok) { const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = response.headers.get('Content-Disposition')?.split('filename=')[1] || `batch_primers.${format}`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); } else { alert('导出失败,请重试'); } } catch (error) { alert('导出失败:' + error.message); } }