Spaces:
Running
Running
| <html lang="zh-CN"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>EvidenceMed - 循证医学论文智能检索平台</title> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --primary-color: #2E86AB; | |
| --secondary-color: #A23B72; | |
| --accent-color: #F18F01; | |
| --success-color: #16A085; | |
| --danger-color: #E74C3C; | |
| --warning-color: #F39C12; | |
| --light-color: #F8F9FA; | |
| --dark-color: #2C3E50; | |
| --gradient-primary: linear-gradient(135deg, #2E86AB 0%, #A23B72 100%); | |
| --gradient-secondary: linear-gradient(135deg, #16A085 0%, #F18F01 100%); | |
| --shadow-light: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| --shadow-medium: 0 8px 25px rgba(0, 0, 0, 0.15); | |
| --shadow-heavy: 0 15px 35px rgba(0, 0, 0, 0.1); | |
| --border-radius: 12px; | |
| --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%); | |
| min-height: 100vh; | |
| color: var(--dark-color); | |
| line-height: 1.6; | |
| } | |
| .container { | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| /* Header */ | |
| .header { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(20px); | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--shadow-medium); | |
| padding: 30px; | |
| margin-bottom: 30px; | |
| text-align: center; | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| .header h1 { | |
| background: var(--gradient-primary); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| font-size: 3em; | |
| font-weight: 800; | |
| margin-bottom: 10px; | |
| letter-spacing: -0.02em; | |
| } | |
| .header .subtitle { | |
| color: var(--secondary-color); | |
| font-size: 1.3em; | |
| font-weight: 300; | |
| margin-bottom: 20px; | |
| } | |
| .header .tagline { | |
| display: flex; | |
| justify-content: center; | |
| gap: 30px; | |
| flex-wrap: wrap; | |
| margin-top: 20px; | |
| } | |
| .tag { | |
| /* 修改 #2: 修改标签背景颜色 */ | |
| background: linear-gradient(135deg, #4F80C8, #6C63FF); | |
| color: white; | |
| padding: 8px 16px; | |
| border-radius: 25px; | |
| font-size: 0.9em; | |
| font-weight: 500; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| box-shadow: var(--shadow-light); | |
| } | |
| /* Search Section */ | |
| .search-section { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(20px); | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--shadow-medium); | |
| padding: 40px; | |
| margin-bottom: 30px; | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| .search-form { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 25px; | |
| } | |
| .search-input-group { | |
| position: relative; | |
| } | |
| .search-input { | |
| width: 100%; | |
| padding: 20px 60px 20px 20px; | |
| border: 2px solid #e1e8ed; | |
| border-radius: var(--border-radius); | |
| font-size: 1.1em; | |
| background: white; | |
| transition: var(--transition); | |
| resize: vertical; | |
| min-height: 120px; | |
| } | |
| .search-input:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 3px rgba(46, 134, 171, 0.1); | |
| } | |
| .search-btn { | |
| position: absolute; | |
| right: 15px; | |
| top: 50%; | |
| transform: translateY(-50%); | |
| background: var(--gradient-primary); | |
| color: white; | |
| border: none; | |
| padding: 15px 20px; | |
| border-radius: var(--border-radius); | |
| cursor: pointer; | |
| transition: var(--transition); | |
| font-weight: 600; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| box-shadow: var(--shadow-light); | |
| } | |
| .search-btn:hover { | |
| transform: translateY(-50%) scale(1.05); | |
| box-shadow: var(--shadow-medium); | |
| } | |
| .search-btn:disabled { | |
| opacity: 0.7; | |
| cursor: not-allowed; | |
| transform: translateY(-50%) scale(1); | |
| } | |
| .platform-selector { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 15px; | |
| } | |
| .platform-option { | |
| display: flex; | |
| align-items: center; | |
| padding: 15px; | |
| background: white; | |
| border: 2px solid #e1e8ed; | |
| border-radius: var(--border-radius); | |
| cursor: pointer; | |
| transition: var(--transition); | |
| position: relative; | |
| } | |
| .platform-option:hover { | |
| border-color: var(--primary-color); | |
| box-shadow: var(--shadow-light); | |
| } | |
| .platform-option.selected { | |
| border-color: var(--primary-color); | |
| background: rgba(46, 134, 171, 0.05); | |
| } | |
| .platform-option input { | |
| margin-right: 12px; | |
| transform: scale(1.2); | |
| } | |
| .platform-info { | |
| flex-grow: 1; | |
| } | |
| .platform-name { | |
| font-weight: 600; | |
| color: var(--dark-color); | |
| margin-bottom: 4px; | |
| } | |
| .platform-desc { | |
| font-size: 0.85em; | |
| color: #6c757d; | |
| } | |
| /* AI Features - 修改 #3: 优化AI功能区布局,使其更紧凑 */ | |
| .ai-features { | |
| display: flex; | |
| justify-content: space-around; | |
| flex-wrap: wrap; | |
| gap: 20px; | |
| margin-bottom: 30px; | |
| } | |
| .ai-feature { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(20px); | |
| border-radius: var(--border-radius); | |
| padding: 20px; | |
| box-shadow: var(--shadow-medium); | |
| text-align: center; | |
| transition: var(--transition); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| flex: 1; | |
| min-width: 250px; | |
| max-width: 350px; | |
| } | |
| .ai-feature:hover { | |
| transform: translateY(-5px); | |
| box-shadow: var(--shadow-heavy); | |
| } | |
| .ai-feature-icon { | |
| font-size: 2.5em; /* 减小图标大小 */ | |
| background: var(--gradient-primary); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| margin-bottom: 10px; /* 减小边距 */ | |
| } | |
| .ai-feature h3 { | |
| color: var(--dark-color); | |
| margin-bottom: 8px; /* 减小边距 */ | |
| font-size: 1.1em; /* 减小标题字号 */ | |
| } | |
| .ai-feature p { | |
| color: #6c757d; | |
| font-size: 0.9em; /* 减小描述字号 */ | |
| } | |
| /* Loading */ | |
| .loading { | |
| display: none; | |
| text-align: center; | |
| padding: 40px; | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(20px); | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--shadow-medium); | |
| margin-bottom: 30px; | |
| } | |
| .loading.show { | |
| display: block; | |
| } | |
| .spinner { | |
| width: 50px; | |
| height: 50px; | |
| border: 4px solid #f3f3f3; | |
| border-top: 4px solid var(--primary-color); | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| margin: 0 auto 20px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| /* Results */ | |
| .results-section { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(20px); | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--shadow-medium); | |
| padding: 30px; | |
| display: none; | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| .results-section.show { | |
| display: block; | |
| } | |
| .results-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 25px; | |
| padding-bottom: 15px; | |
| border-bottom: 2px solid #e1e8ed; | |
| } | |
| .results-count { | |
| color: var(--primary-color); | |
| font-weight: 600; | |
| font-size: 1.1em; | |
| } | |
| .paper-card { | |
| background: white; | |
| border-radius: var(--border-radius); | |
| padding: 25px; | |
| margin-bottom: 20px; | |
| box-shadow: var(--shadow-light); | |
| border-left: 4px solid var(--primary-color); | |
| transition: var(--transition); | |
| } | |
| .paper-card:hover { | |
| box-shadow: var(--shadow-medium); | |
| transform: translateX(5px); | |
| } | |
| .paper-title { | |
| font-size: 1.3em; | |
| font-weight: 600; | |
| color: var(--dark-color); | |
| margin-bottom: 10px; | |
| line-height: 1.4; | |
| } | |
| .paper-title a { | |
| color: inherit; | |
| text-decoration: none; | |
| transition: var(--transition); | |
| } | |
| .paper-title a:hover { | |
| color: var(--primary-color); | |
| } | |
| .paper-authors { | |
| color: var(--secondary-color); | |
| margin-bottom: 10px; | |
| font-weight: 500; | |
| } | |
| .paper-journal { | |
| color: var(--accent-color); | |
| font-style: italic; | |
| margin-bottom: 10px; | |
| } | |
| .paper-date { | |
| color: #6c757d; | |
| font-size: 0.9em; | |
| margin-bottom: 15px; | |
| } | |
| .paper-abstract { | |
| color: #495057; | |
| line-height: 1.6; | |
| margin-bottom: 20px; | |
| background: #f8f9fa; | |
| padding: 15px; | |
| border-radius: 8px; | |
| border-left: 3px solid var(--accent-color); | |
| } | |
| .paper-actions { | |
| display: flex; | |
| gap: 10px; | |
| flex-wrap: wrap; | |
| } | |
| .action-btn { | |
| padding: 8px 16px; | |
| border: none; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-size: 0.9em; | |
| font-weight: 500; | |
| text-decoration: none; | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 6px; | |
| transition: var(--transition); | |
| } | |
| .btn-primary { | |
| background: var(--primary-color); | |
| color: white; | |
| } | |
| .btn-success { | |
| background: var(--success-color); | |
| color: white; | |
| } | |
| .btn-outline { | |
| background: transparent; | |
| color: var(--primary-color); | |
| border: 1px solid var(--primary-color); | |
| } | |
| .action-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: var(--shadow-light); | |
| } | |
| /* Error */ | |
| .error-message { | |
| background: rgba(231, 76, 60, 0.1); | |
| color: var(--danger-color); | |
| padding: 20px; | |
| border-radius: var(--border-radius); | |
| border: 1px solid rgba(231, 76, 60, 0.2); | |
| margin-bottom: 20px; | |
| display: none; | |
| } | |
| .error-message.show { | |
| display: block; | |
| } | |
| /* Success Message */ | |
| .success-message { | |
| background: rgba(22, 160, 133, 0.1); | |
| color: var(--success-color); | |
| padding: 15px; | |
| border-radius: var(--border-radius); | |
| border: 1px solid rgba(22, 160, 133, 0.2); | |
| margin: 10px 0; | |
| display: none; | |
| animation: fadeInUp 0.3s ease-out; | |
| } | |
| .success-message.show { | |
| display: block; | |
| } | |
| /* Modal */ | |
| .modal { | |
| display: none; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.5); | |
| z-index: 1000; | |
| animation: fadeIn 0.3s ease-out; | |
| } | |
| .modal.show { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .modal-content { | |
| background: white; | |
| border-radius: var(--border-radius); | |
| padding: 30px; | |
| max-width: 500px; | |
| width: 90%; | |
| animation: slideUp 0.3s ease-out; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; } | |
| to { opacity: 1; } | |
| } | |
| @keyframes slideUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(30px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| /* Responsive */ | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 10px; | |
| } | |
| .header h1 { | |
| font-size: 2em; | |
| } | |
| .header .tagline { | |
| gap: 15px; | |
| } | |
| .search-section { | |
| padding: 25px; | |
| } | |
| .search-input { | |
| padding: 15px 50px 15px 15px; | |
| min-height: 100px; | |
| } | |
| .platform-selector { | |
| grid-template-columns: 1fr; | |
| } | |
| .ai-features { | |
| flex-direction: column; | |
| } | |
| .results-header { | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 10px; | |
| } | |
| .paper-actions { | |
| justify-content: center; | |
| } | |
| } | |
| /* Animations */ | |
| @keyframes fadeInUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(30px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .fade-in-up { | |
| animation: fadeInUp 0.6s ease-out forwards; | |
| } | |
| /* Evidence levels */ | |
| .evidence-level { | |
| display: inline-block; | |
| padding: 4px 10px; | |
| border-radius: 12px; | |
| font-size: 0.8em; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| margin-left: 10px; | |
| } | |
| .level-1 { background: #e8f5e8; color: #2e7d32; } | |
| .level-2 { background: #f3e5f5; color: #7b1fa2; } | |
| .level-3 { background: #e3f2fd; color: #1976d2; } | |
| .level-4 { background: #fff3e0; color: #f57c00; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <!-- Header --> | |
| <header class="header fade-in-up"> | |
| <h1><i class="fas fa-microscope"></i> EvidenceMed</h1> | |
| <p class="subtitle">循证医学论文智能检索平台</p> | |
| <div class="tagline"> | |
| <div class="tag"> | |
| <i class="fas fa-brain"></i> | |
| AI智能检索 | |
| </div> | |
| <div class="tag"> | |
| <i class="fas fa-download"></i> | |
| 全文下载 | |
| </div> | |
| <div class="tag"> | |
| <i class="fas fa-language"></i> | |
| 自然语言查询 | |
| </div> | |
| <div class="tag"> | |
| <i class="fas fa-shield-alt"></i> | |
| 循证医学 | |
| </div> | |
| </div> | |
| </header> | |
| <!-- AI Features --> | |
| <div class="ai-features fade-in-up"> | |
| <div class="ai-feature"> | |
| <div class="ai-feature-icon"> | |
| <i class="fas fa-search-plus"></i> | |
| </div> | |
| <h3>智能语义理解</h3> | |
| <p>精准理解医学术语与复杂查询</p> | |
| </div> | |
| <div class="ai-feature"> | |
| <div class="ai-feature-icon"> | |
| <i class="fas fa-filter"></i> | |
| </div> | |
| <h3>循证分级筛选</h3> | |
| <p>按证据等级自动分类筛选文献</p> | |
| </div> | |
| <div class="ai-feature"> | |
| <div class="ai-feature-icon"> | |
| <i class="fas fa-chart-line"></i> | |
| </div> | |
| <h3>研究趋势分析</h3> | |
| <p>洞察领域前沿,发现研究热点</p> | |
| </div> | |
| </div> | |
| <!-- Search Section --> | |
| <section class="search-section fade-in-up"> | |
| <form class="search-form" id="searchForm"> | |
| <div class="search-input-group"> | |
| <textarea | |
| class="search-input" | |
| id="searchQuery" | |
| placeholder="请输入您的医学研究问题 (建议使用英文以获得更佳搜索效果),例如: | |
| • Efficacy and safety of metformin in type 2 diabetes | |
| • Immune response to COVID-19 vaccines in elderly | |
| • Lifestyle interventions for hypertension | |
| • Adjuvant chemotherapy for breast cancer | |
| AI将自动理解您的意图并提供最相关的文献..." | |
| required></textarea> | |
| <button type="submit" class="search-btn" id="searchBtn"> | |
| <i class="fas fa-search"></i> | |
| 智能搜索 | |
| </button> | |
| </div> | |
| <div class="platform-selector"> | |
| <label class="platform-option selected"> | |
| <input type="checkbox" name="platform" value="pubmed" checked> | |
| <div class="platform-info"> | |
| <div class="platform-name">PubMed</div> | |
| <div class="platform-desc">生物医学文献数据库</div> | |
| </div> | |
| </label> | |
| <label class="platform-option"> | |
| <input type="checkbox" name="platform" value="arxiv"> | |
| <div class="platform-info"> | |
| <div class="platform-name">arXiv</div> | |
| <div class="platform-desc">预印本论文平台</div> | |
| </div> | |
| </label> | |
| <label class="platform-option"> | |
| <input type="checkbox" name="platform" value="biorxiv"> | |
| <div class="platform-info"> | |
| <div class="platform-name">bioRxiv</div> | |
| <div class="platform-desc">生物学预印本</div> | |
| </div> | |
| </label> | |
| <label class="platform-option"> | |
| <input type="checkbox" name="platform" value="semantic"> | |
| <div class="platform-info"> | |
| <div class="platform-name">Semantic Scholar</div> | |
| <div class="platform-desc">AI驱动的学术搜索</div> | |
| </div> | |
| </label> | |
| </div> | |
| <!-- 修改 #1: 添加结果数量选择器 --> | |
| <div class="results-limiter" style="display: flex; align-items: center; gap: 10px; margin-top: 15px;"> | |
| <label for="maxResults" style="font-weight: 600; color: var(--dark-color);"> | |
| <i class="fas fa-list-ol"></i> 最大结果数量: | |
| </label> | |
| <select id="maxResults" style="padding: 10px; border-radius: 8px; border: 2px solid #e1e8ed; font-size: 1em; background: white; transition: var(--transition);"> | |
| <option value="10">10</option> | |
| <option value="20">20</option> | |
| <option value="50" selected>50</option> | |
| <option value="100">100</option> | |
| </select> | |
| </div> | |
| </form> | |
| </section> | |
| <!-- Loading --> | |
| <div class="loading" id="loading"> | |
| <div class="spinner"></div> | |
| <p><i class="fas fa-robot"></i> AI正在分析您的查询并检索相关文献...</p> | |
| </div> | |
| <!-- Success Message --> | |
| <div class="success-message" id="successMessage"></div> | |
| <!-- Error Message --> | |
| <div class="error-message" id="errorMessage"></div> | |
| <!-- Results --> | |
| <section class="results-section" id="resultsSection"> | |
| <div class="results-header"> | |
| <div class="results-count" id="resultsCount"></div> | |
| <div> | |
| <button class="action-btn btn-outline" onclick="exportResults()"> | |
| <i class="fas fa-download"></i> 导出结果 | |
| </button> | |
| </div> | |
| </div> | |
| <div id="resultsContainer"></div> | |
| </section> | |
| </div> | |
| <!-- Modal for sharing --> | |
| <div class="modal" id="shareModal"> | |
| <div class="modal-content"> | |
| <h3 style="margin-bottom: 20px; color: var(--primary-color);"> | |
| <i class="fas fa-share-alt"></i> 分享文献 | |
| </h3> | |
| <p style="margin-bottom: 20px; color: #6c757d;">选择分享方式:</p> | |
| <div style="display: flex; gap: 10px; flex-wrap: wrap;"> | |
| <button class="action-btn btn-primary" onclick="shareViaEmail()"> | |
| <i class="fas fa-envelope"></i> 邮件 | |
| </button> | |
| <button class="action-btn btn-success" onclick="copyToClipboard()"> | |
| <i class="fas fa-copy"></i> 复制链接 | |
| </button> | |
| <button class="action-btn btn-outline" onclick="closeModal()"> | |
| 取消 | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // API配置 - 演示模式,实际使用时替换为真实API | |
| //const API_BASE_URL = 'https://leonsimon23-paper-mcp-agent.hf.space'; | |
| const API_BASE_URL = 'https://leonsimon23-ai-search-agent.hf.space'; | |
| const DEMO_MODE = false; // 设置为false以使用真实API | |
| // 全局变量 | |
| let searchResults = []; | |
| let savedPapers = JSON.parse(localStorage.getItem('savedPapers') || '[]'); | |
| let currentSharePaper = null; | |
| // DOM元素 | |
| const searchForm = document.getElementById('searchForm'); | |
| const searchQuery = document.getElementById('searchQuery'); | |
| const searchBtn = document.getElementById('searchBtn'); | |
| const loading = document.getElementById('loading'); | |
| const errorMessage = document.getElementById('errorMessage'); | |
| const successMessage = document.getElementById('successMessage'); | |
| const resultsSection = document.getElementById('resultsSection'); | |
| const resultsContainer = document.getElementById('resultsContainer'); | |
| const resultsCount = document.getElementById('resultsCount'); | |
| const shareModal = document.getElementById('shareModal'); | |
| // 平台选择处理 | |
| document.querySelectorAll('.platform-option').forEach(option => { | |
| option.addEventListener('click', function(e) { | |
| if (e.target.tagName !== 'INPUT') { | |
| const checkbox = this.querySelector('input'); | |
| checkbox.checked = !checkbox.checked; | |
| } | |
| this.classList.toggle('selected', this.querySelector('input').checked); | |
| }); | |
| }); | |
| // 搜索表单提交 | |
| searchForm.addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| await performSearch(); | |
| }); | |
| // 点击模态框背景关闭 | |
| shareModal.addEventListener('click', (e) => { | |
| if (e.target === shareModal) { | |
| closeModal(); | |
| } | |
| }); | |
| // 执行搜索 | |
| async function performSearch() { | |
| const query = searchQuery.value.trim(); | |
| if (!query) { | |
| showError('请输入搜索查询'); | |
| return; | |
| } | |
| const selectedPlatforms = Array.from(document.querySelectorAll('input[name="platform"]:checked')) | |
| .map(input => input.value); | |
| if (selectedPlatforms.length === 0) { | |
| showError('请至少选择一个数据库平台'); | |
| return; | |
| } | |
| showLoading(true); | |
| hideError(); | |
| hideSuccess(); | |
| hideResults(); | |
| try { | |
| searchResults = []; | |
| if (DEMO_MODE) { | |
| // 演示数据 | |
| searchResults = generateDemoResults(query, selectedPlatforms); | |
| // 模拟加载时间 | |
| await new Promise(resolve => setTimeout(resolve, 2000)); | |
| } else { | |
| // 对每个平台执行搜索 | |
| for (const platform of selectedPlatforms) { | |
| try { | |
| const results = await searchPlatform(platform, query); | |
| if (results && results.length > 0) { | |
| searchResults.push(...results.map(paper => ({ | |
| ...paper, | |
| platform: platform | |
| }))); | |
| } | |
| } catch (error) { | |
| console.error(`搜索${platform}时出错:`, error); | |
| } | |
| } | |
| } | |
| if (searchResults.length === 0) { | |
| showError('未找到相关文献,请尝试调整搜索关键词或选择其他数据库'); | |
| return; | |
| } | |
| // 按相关性排序 | |
| searchResults.sort((a, b) => (b.relevance_score || Math.random()) - (a.relevance_score || Math.random())); | |
| displayResults(); | |
| showSuccess(`成功检索到 ${searchResults.length} 篇相关文献`); | |
| } catch (error) { | |
| console.error('搜索出错:', error); | |
| showError('搜索过程中发生错误,请稍后重试'); | |
| } finally { | |
| showLoading(false); | |
| } | |
| } | |
| // 生成演示数据 | |
| function generateDemoResults(query, platforms) { | |
| const demoResults = []; | |
| const baseResults = [ | |
| { | |
| title: "Metformin in type 2 diabetes: A systematic review and meta-analysis", | |
| authors: ["Smith J", "Johnson A", "Williams B"], | |
| journal: "The Lancet Diabetes & Endocrinology", | |
| published_date: "2023-08-15", | |
| abstract: "Background: Metformin remains the first-line treatment for type 2 diabetes, but its efficacy and safety profile continues to be evaluated. Methods: We conducted a systematic review and meta-analysis of randomized controlled trials examining metformin use in type 2 diabetes patients...", | |
| url: "https://pubmed.ncbi.nlm.nih.gov/demo1", | |
| pdf_url: "https://example.com/demo1.pdf", | |
| relevance_score: 0.95, | |
| study_type: "meta-analysis" | |
| }, | |
| { | |
| title: "COVID-19 vaccines effectiveness in elderly populations: A real-world evidence study", | |
| authors: ["Brown C", "Davis M", "Wilson K"], | |
| journal: "Nature Medicine", | |
| published_date: "2023-07-22", | |
| abstract: "The effectiveness of COVID-19 vaccines in elderly populations has been a critical public health concern. This real-world evidence study analyzes vaccination outcomes in patients aged 65 and older across multiple healthcare systems...", | |
| url: "https://pubmed.ncbi.nlm.nih.gov/demo2", | |
| pdf_url: "https://example.com/demo2.pdf", | |
| relevance_score: 0.92, | |
| study_type: "cohort" | |
| }, | |
| { | |
| title: "Lifestyle interventions for hypertension management: A randomized controlled trial", | |
| authors: ["Taylor R", "Anderson L", "Thompson D"], | |
| journal: "Journal of the American College of Cardiology", | |
| published_date: "2023-06-10", | |
| abstract: "Objective: To evaluate the effectiveness of comprehensive lifestyle interventions in managing hypertension. Design: Randomized controlled trial with 12-month follow-up. Participants: 500 adults with newly diagnosed hypertension...", | |
| url: "https://pubmed.ncbi.nlm.nih.gov/demo3", | |
| pdf_url: "https://example.com/demo3.pdf", | |
| relevance_score: 0.88, | |
| study_type: "rct" | |
| }, | |
| { | |
| title: "Comparative effectiveness of adjuvant chemotherapy regimens in breast cancer: Network meta-analysis", | |
| authors: ["Garcia M", "Rodriguez P", "Martinez S"], | |
| journal: "Journal of Clinical Oncology", | |
| published_date: "2023-09-05", | |
| abstract: "Purpose: To compare the effectiveness of different adjuvant chemotherapy regimens in early-stage breast cancer through network meta-analysis. Methods: We systematically searched multiple databases for randomized controlled trials comparing adjuvant chemotherapy regimens...", | |
| url: "https://pubmed.ncbi.nlm.nih.gov/demo4", | |
| pdf_url: "https://example.com/demo4.pdf", | |
| relevance_score: 0.85, | |
| study_type: "meta-analysis" | |
| }, | |
| { | |
| title: "Novel biomarkers for early detection of Alzheimer's disease: A prospective cohort study", | |
| authors: ["Lee H", "Park S", "Kim J"], | |
| journal: "Alzheimer's & Dementia", | |
| published_date: "2023-05-18", | |
| abstract: "Background: Early detection of Alzheimer's disease remains challenging. This study investigates novel blood-based biomarkers for preclinical diagnosis. Methods: Prospective cohort study following 1,200 cognitively normal adults over 5 years...", | |
| url: "https://pubmed.ncbi.nlm.nih.gov/demo5", | |
| pdf_url: "https://example.com/demo5.pdf", | |
| relevance_score: 0.82, | |
| study_type: "cohort" | |
| } | |
| ]; | |
| // 根据查询和平台生成结果 | |
| platforms.forEach(platform => { | |
| baseResults.forEach((result, index) => { | |
| if (Math.random() > 0.3) { // 随机包含一些结果 | |
| demoResults.push({ | |
| ...result, | |
| platform: platform, | |
| id: `${platform}_${index}`, | |
| title: result.title + (platform !== 'pubmed' ? ` [${platform.toUpperCase()}]` : '') | |
| }); | |
| } | |
| }); | |
| }); | |
| return demoResults.slice(0, Math.min(15, demoResults.length)); | |
| } | |
| // 搜索特定平台(真实API调用)- 修改 #1: 修改函数以使用选择器的值 | |
| async function searchPlatform(platform, query) { | |
| // 从新增的下拉框中获取用户选择的数量 | |
| const maxResultsValue = document.getElementById('maxResults').value; | |
| const response = await fetch(`${API_BASE_URL}/search`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| platform: platform, | |
| query: query, | |
| // 使用从下拉框获取的值,并将其转换为整数 | |
| max_results: parseInt(maxResultsValue, 10) | |
| }) | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| } | |
| const data = await response.json(); | |
| if (data.error) { | |
| throw new Error(data.error); | |
| } | |
| return data.results || []; | |
| } | |
| // 显示搜索结果 | |
| function displayResults() { | |
| resultsCount.textContent = `找到 ${searchResults.length} 篇相关文献`; | |
| resultsContainer.innerHTML = ''; | |
| searchResults.forEach((paper, index) => { | |
| const paperCard = createPaperCard(paper, index); | |
| resultsContainer.appendChild(paperCard); | |
| }); | |
| resultsSection.classList.add('show'); | |
| resultsSection.scrollIntoView({ behavior: 'smooth' }); | |
| } | |
| // 创建论文卡片 | |
| function createPaperCard(paper, index) { | |
| const card = document.createElement('div'); | |
| card.className = 'paper-card fade-in-up'; | |
| card.style.animationDelay = `${index * 0.1}s`; | |
| // 确定证据等级 | |
| const evidenceLevel = getEvidenceLevel(paper); | |
| // 检查是否已保存 | |
| const isSaved = savedPapers.some(saved => saved.id === paper.id || saved.title === paper.title); | |
| card.innerHTML = ` | |
| <div class="paper-title"> | |
| <a href="${paper.url || '#'}" target="_blank"> | |
| ${paper.title || '标题未知'} | |
| </a> | |
| ${evidenceLevel ? `<span class="evidence-level ${evidenceLevel.class}">${evidenceLevel.text}</span>` : ''} | |
| </div> | |
| ${paper.authors ? `<div class="paper-authors"> | |
| <i class="fas fa-user-md"></i> ${Array.isArray(paper.authors) ? paper.authors.join(', ') : paper.authors} | |
| </div>` : ''} | |
| ${paper.journal ? `<div class="paper-journal"> | |
| <i class="fas fa-book-open"></i> ${paper.journal} | |
| </div>` : ''} | |
| ${paper.published_date || paper.date ? `<div class="paper-date"> | |
| <i class="fas fa-calendar-alt"></i> ${paper.published_date || paper.date} | |
| </div>` : ''} | |
| ${paper.abstract || paper.summary ? `<div class="paper-abstract"> | |
| <strong>摘要:</strong> ${truncateText(paper.abstract || paper.summary, 300)} | |
| </div>` : ''} | |
| <div class="paper-actions"> | |
| ${paper.url ? `<a href="${paper.url}" target="_blank" class="action-btn btn-primary"> | |
| <i class="fas fa-external-link-alt"></i> 查看原文 | |
| </a>` : ''} | |
| ${paper.pdf_url ? `<a href="${paper.pdf_url}" target="_blank" class="action-btn btn-success"> | |
| <i class="fas fa-file-pdf"></i> 下载PDF | |
| </a>` : ''} | |
| <button class="action-btn ${isSaved ? 'btn-success' : 'btn-outline'}" onclick="toggleSavePaper(${index})" id="save-btn-${index}"> | |
| <i class="fas ${isSaved ? 'fa-check' : 'fa-bookmark'}"></i> ${isSaved ? '已保存' : '保存'} | |
| </button> | |
| <button class="action-btn btn-outline" onclick="sharePaper(${index})"> | |
| <i class="fas fa-share-alt"></i> 分享 | |
| </button> | |
| <span class="platform-badge" style="background: var(--accent-color); color: white; padding: 4px 8px; border-radius: 4px; font-size: 0.8em; margin-left: auto;"> | |
| ${paper.platform?.toUpperCase() || 'UNKNOWN'} | |
| </span> | |
| </div> | |
| `; | |
| return card; | |
| } | |
| // 获取证据等级 | |
| function getEvidenceLevel(paper) { | |
| const title = (paper.title || '').toLowerCase(); | |
| const abstract = (paper.abstract || paper.summary || '').toLowerCase(); | |
| const studyType = (paper.study_type || '').toLowerCase(); | |
| // 基于研究类型和关键词的分类 | |
| if (studyType === 'meta-analysis' || title.includes('meta-analysis') || title.includes('systematic review') || | |
| abstract.includes('meta-analysis') || abstract.includes('systematic review')) { | |
| return { class: 'level-1', text: '系统评价' }; | |
| } | |
| if (studyType === 'rct' || title.includes('randomized') || title.includes('rct') || | |
| abstract.includes('randomized controlled trial') || abstract.includes('randomized trial')) { | |
| return { class: 'level-2', text: 'RCT' }; | |
| } | |
| if (studyType === 'cohort' || title.includes('cohort') || title.includes('case-control') || | |
| abstract.includes('cohort study') || abstract.includes('case-control')) { | |
| return { class: 'level-3', text: '队列研究' }; | |
| } | |
| if (title.includes('case report') || title.includes('case series') || | |
| abstract.includes('case report') || abstract.includes('case series')) { | |
| return { class: 'level-4', text: '病例报告' }; | |
| } | |
| return null; | |
| } | |
| // 截断文本 | |
| function truncateText(text, maxLength) { | |
| if (!text) return ''; | |
| if (text.length <= maxLength) return text; | |
| return text.substring(0, maxLength) + '...'; | |
| } | |
| // 切换保存论文状态 | |
| function toggleSavePaper(index) { | |
| const paper = searchResults[index]; | |
| const savedIndex = savedPapers.findIndex(saved => saved.id === paper.id || saved.title === paper.title); | |
| const saveBtn = document.getElementById(`save-btn-${index}`); | |
| if (savedIndex > -1) { | |
| // 取消保存 | |
| savedPapers.splice(savedIndex, 1); | |
| saveBtn.innerHTML = '<i class="fas fa-bookmark"></i> 保存'; | |
| saveBtn.classList.remove('btn-success'); | |
| saveBtn.classList.add('btn-outline'); | |
| showSuccess('已取消保存该文献'); | |
| } else { | |
| // 保存论文 | |
| savedPapers.push({ | |
| ...paper, | |
| savedAt: new Date().toISOString() | |
| }); | |
| saveBtn.innerHTML = '<i class="fas fa-check"></i> 已保存'; | |
| saveBtn.classList.remove('btn-outline'); | |
| saveBtn.classList.add('btn-success'); | |
| showSuccess('文献已保存到收藏夹'); | |
| } | |
| // 保存到本地存储 | |
| localStorage.setItem('savedPapers', JSON.stringify(savedPapers)); | |
| } | |
| // 分享论文 | |
| function sharePaper(index) { | |
| currentSharePaper = searchResults[index]; | |
| shareModal.classList.add('show'); | |
| } | |
| // 通过邮件分享 | |
| function shareViaEmail() { | |
| if (!currentSharePaper) return; | |
| const subject = encodeURIComponent(`推荐文献: ${currentSharePaper.title}`); | |
| const body = encodeURIComponent(`我发现了一篇可能对您有用的医学文献: | |
| 标题: ${currentSharePaper.title} | |
| 作者: ${Array.isArray(currentSharePaper.authors) ? currentSharePaper.authors.join(', ') : currentSharePaper.authors || '未知'} | |
| 期刊: ${currentSharePaper.journal || '未知'} | |
| 发表日期: ${currentSharePaper.published_date || currentSharePaper.date || '未知'} | |
| 链接: ${currentSharePaper.url || '暂无链接'} | |
| 摘要: | |
| ${currentSharePaper.abstract || currentSharePaper.summary || '暂无摘要'} | |
| 通过 EvidenceMed 循证医学检索平台分享`); | |
| window.open(`mailto:?subject=${subject}&body=${body}`); | |
| closeModal(); | |
| showSuccess('邮件分享链接已打开'); | |
| } | |
| // 复制到剪贴板 | |
| async function copyToClipboard() { | |
| if (!currentSharePaper) return; | |
| const shareText = `【推荐文献】 | |
| 标题: ${currentSharePaper.title} | |
| 作者: ${Array.isArray(currentSharePaper.authors) ? currentSharePaper.authors.join(', ') : currentSharePaper.authors || '未知'} | |
| 期刊: ${currentSharePaper.journal || '未知'} | |
| 链接: ${currentSharePaper.url || '暂无链接'} | |
| 通过 EvidenceMed 循证医学检索平台分享`; | |
| try { | |
| await navigator.clipboard.writeText(shareText); | |
| showSuccess('文献信息已复制到剪贴板'); | |
| } catch (err) { | |
| // 降级方案 | |
| const textArea = document.createElement('textarea'); | |
| textArea.value = shareText; | |
| document.body.appendChild(textArea); | |
| textArea.select(); | |
| document.execCommand('copy'); | |
| document.body.removeChild(textArea); | |
| showSuccess('文献信息已复制到剪贴板'); | |
| } | |
| closeModal(); | |
| } | |
| // 关闭模态框 | |
| function closeModal() { | |
| shareModal.classList.remove('show'); | |
| currentSharePaper = null; | |
| } | |
| // 导出结果 | |
| function exportResults() { | |
| if (searchResults.length === 0) { | |
| showError('没有可导出的搜索结果'); | |
| return; | |
| } | |
| // 生成导出数据 | |
| const exportData = { | |
| searchQuery: searchQuery.value, | |
| searchDate: new Date().toISOString(), | |
| totalResults: searchResults.length, | |
| results: searchResults.map(paper => ({ | |
| title: paper.title, | |
| authors: Array.isArray(paper.authors) ? paper.authors.join(', ') : paper.authors, | |
| journal: paper.journal, | |
| publishedDate: paper.published_date || paper.date, | |
| abstract: paper.abstract || paper.summary, | |
| url: paper.url, | |
| pdfUrl: paper.pdf_url, | |
| platform: paper.platform, | |
| evidenceLevel: getEvidenceLevel(paper)?.text || '未分级' | |
| })) | |
| }; | |
| // 创建CSV格式 | |
| const csvHeaders = ['标题', '作者', '期刊', '发表日期', '摘要', '链接', 'PDF链接', '数据库', '证据等级']; | |
| const csvRows = [ | |
| csvHeaders.join(','), | |
| ...exportData.results.map(paper => [ | |
| `"${(paper.title || '').replace(/"/g, '""')}"`, | |
| `"${(paper.authors || '').replace(/"/g, '""')}"`, | |
| `"${(paper.journal || '').replace(/"/g, '""')}"`, | |
| `"${(paper.publishedDate || '').replace(/"/g, '""')}"`, | |
| `"${(paper.abstract || '').replace(/"/g, '""')}"`, | |
| `"${(paper.url || '').replace(/"/g, '""')}"`, | |
| `"${(paper.pdfUrl || '').replace(/"/g, '""')}"`, | |
| `"${(paper.platform || '').replace(/"/g, '""')}"`, | |
| `"${(paper.evidenceLevel || '').replace(/"/g, '""')}"` | |
| ].join(',')) | |
| ]; | |
| // 下载CSV文件 | |
| const csvContent = csvRows.join('\n'); | |
| const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' }); | |
| const link = document.createElement('a'); | |
| const url = URL.createObjectURL(blob); | |
| link.setAttribute('href', url); | |
| link.setAttribute('download', `EvidenceMed_搜索结果_${new Date().toISOString().split('T')[0]}.csv`); | |
| link.style.visibility = 'hidden'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| showSuccess('搜索结果已导出为CSV文件'); | |
| } | |
| // 显示/隐藏加载状态 | |
| function showLoading(show) { | |
| loading.classList.toggle('show', show); | |
| searchBtn.disabled = show; | |
| searchBtn.innerHTML = show ? | |
| '<i class="fas fa-spinner fa-spin"></i> 搜索中...' : | |
| '<i class="fas fa-search"></i> 智能搜索'; | |
| } | |
| // 显示错误信息 | |
| function showError(message) { | |
| errorMessage.textContent = message; | |
| errorMessage.classList.add('show'); | |
| setTimeout(() => { | |
| hideError(); | |
| }, 5000); | |
| } | |
| // 隐藏错误信息 | |
| function hideError() { | |
| errorMessage.classList.remove('show'); | |
| } | |
| // 显示成功信息 | |
| function showSuccess(message) { | |
| successMessage.textContent = message; | |
| successMessage.classList.add('show'); | |
| setTimeout(() => { | |
| hideSuccess(); | |
| }, 3000); | |
| } | |
| // 隐藏成功信息 | |
| function hideSuccess() { | |
| successMessage.classList.remove('show'); | |
| } | |
| // 隐藏搜索结果 | |
| function hideResults() { | |
| resultsSection.classList.remove('show'); | |
| } | |
| // 初始化页面 | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // 添加淡入动画 | |
| document.querySelectorAll('.fade-in-up').forEach((element, index) => { | |
| element.style.animationDelay = `${index * 0.2}s`; | |
| }); | |
| // 如果是演示模式,显示提示 | |
| if (DEMO_MODE) { | |
| const demoNotice = document.createElement('div'); | |
| demoNotice.innerHTML = ` | |
| <div style="background: rgba(255, 193, 7, 0.1); color: #856404; padding: 15px; margin-bottom: 20px; border-radius: var(--border-radius); border: 1px solid rgba(255, 193, 7, 0.2); text-align: center;"> | |
| <i class="fas fa-info-circle"></i> 当前处于演示模式,搜索结果为模拟数据 | |
| </div> | |
| `; | |
| document.querySelector('.container').insertBefore(demoNotice, document.querySelector('.ai-features')); | |
| } | |
| // 显示保存的论文数量 | |
| if (savedPapers.length > 0) { | |
| const savedNotice = document.createElement('div'); | |
| savedNotice.innerHTML = ` | |
| <div style="background: rgba(22, 160, 133, 0.1); color: var(--success-color); padding: 10px; margin-bottom: 15px; border-radius: 6px; text-align: center; font-size: 0.9em;"> | |
| <i class="fas fa-bookmark"></i> 您已保存 ${savedPapers.length} 篇文献 | |
| </div> | |
| `; | |
| document.querySelector('.search-section').insertBefore(savedNotice, document.querySelector('.search-form')); | |
| } | |
| }); | |
| // 键盘快捷键 | |
| document.addEventListener('keydown', function(e) { | |
| // Ctrl/Cmd + Enter 执行搜索 | |
| if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { | |
| e.preventDefault(); | |
| if (!searchBtn.disabled) { | |
| performSearch(); | |
| } | |
| } | |
| // Escape 关闭模态框 | |
| if (e.key === 'Escape') { | |
| closeModal(); | |
| } | |
| }); | |
| // 平滑滚动到顶部功能 | |
| function scrollToTop() { | |
| window.scrollTo({ | |
| top: 0, | |
| behavior: 'smooth' | |
| }); | |
| } | |
| // 添加返回顶部按钮 | |
| const backToTopBtn = document.createElement('button'); | |
| backToTopBtn.innerHTML = '<i class="fas fa-chevron-up"></i>'; | |
| backToTopBtn.style.cssText = ` | |
| position: fixed; | |
| bottom: 30px; | |
| right: 30px; | |
| width: 50px; | |
| height: 50px; | |
| background: var(--gradient-primary); | |
| color: white; | |
| border: none; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| display: none; | |
| z-index: 999; | |
| box-shadow: var(--shadow-medium); | |
| transition: var(--transition); | |
| font-size: 1.2em; | |
| `; | |
| backToTopBtn.onclick = scrollToTop; | |
| document.body.appendChild(backToTopBtn); | |
| // 滚动时显示/隐藏返回顶部按钮 | |
| window.addEventListener('scroll', function() { | |
| if (window.pageYOffset > 300) { | |
| backToTopBtn.style.display = 'block'; | |
| } else { | |
| backToTopBtn.style.display = 'none'; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |