(() => { const data = window.CHANNEL_RULES; if (!data) return; const form = document.getElementById('recommendationForm'); const category = document.getElementById('category'); const country = document.getElementById('country'); const packageName = document.getElementById('packageName'); const message = document.getElementById('formMessage'); const empty = document.getElementById('resultEmpty'); const content = document.getElementById('resultContent'); const list = document.getElementById('resultList'); const summary = document.getElementById('querySummary'); const resetBtn = document.getElementById('resetBtn'); data.categories.forEach((item) => category.add(new Option(item.label, item.value))); data.countries.forEach(([code, name]) => country.add(new Option(`${name} · ${code}`, code))); const categoryLabel = (value) => data.categories.find((item) => item.value === value)?.label || value; const countryLabel = (value) => { const item = data.countries.find(([code]) => code === value); return item ? `${item[1]} · ${item[0]}` : value; }; function scoreChannel(channel, query) { let score = channel.base; const reasons = [`基础能力 ${channel.base} 分`]; const region = data.regionMap[query.country]; if (channel.categories.includes(query.category)) { score += 35; reasons.push(`适配「${categoryLabel(query.category)}」品类`); } else if (channel.categories.includes('other')) { score += 10; reasons.push('支持通用品类测试'); } if (channel.countries.includes(query.country)) { score += 30; reasons.push(`明确覆盖 ${query.country}`); } else if (region && channel.regions.includes(region)) { score += 24; reasons.push(`覆盖 ${region} 区域`); } else if (channel.countries.includes('GLOBAL')) { score += 18; reasons.push('具备全球流量覆盖'); } if (query.os === 'ALL' || channel.os.includes(query.os)) { score += 10; reasons.push(query.os === 'ALL' ? '同时支持 Android / iOS' : `支持 ${query.os === 'AOS' ? 'Android' : 'iOS'}`); } const lowerPkg = query.pkg.toLowerCase(); const hint = channel.pkgHints.find((word) => lowerPkg.includes(word)); if (hint) { score += 5; reasons.push(`包名特征命中「${hint}」`); } return { ...channel, score: Math.min(score, 100), reasons }; } function priority(score, index) { if (index === 0 || score >= 80) return ['P1', '优先测试', 'priority-high']; if (score >= 65) return ['P2', '建议测试', 'priority-mid']; return ['P3', '补充候选', 'priority-low']; } function render(query) { const results = data.channels.map((channel) => scoreChannel(channel, query)).sort((a, b) => b.score - a.score).slice(0, 6); summary.innerHTML = `
PACKAGE${escapeHtml(query.pkg)}
CATEGORY${escapeHtml(categoryLabel(query.category))}
GEO${escapeHtml(countryLabel(query.country))}
`; list.innerHTML = results.map((item, index) => { const [level, label, className] = priority(item.score, index); return `
${String(index + 1).padStart(2, '0')}

${escapeHtml(item.name)}

${escapeHtml(item.type)}
${item.reasons.slice(1, 4).map((reason) => `${escapeHtml(reason)}`).join('')}

${escapeHtml(item.strengths.join(' · '))}

${item.score}/100
${level} · ${label}
`; }).join(''); empty.classList.add('hidden'); content.classList.remove('hidden'); resetBtn.classList.remove('hidden'); } function escapeHtml(value) { return String(value).replace(/[&<>"']/g, (char) => ({ '&':'&', '<':'<', '>':'>', '"':'"', "'":''' })[char]); } form.addEventListener('submit', (event) => { event.preventDefault(); const pkg = packageName.value.trim(); if (!pkg || !category.value || !country.value) { message.textContent = '请完整填写包名、产品品类和投放国家。'; return; } message.textContent = ''; const os = form.querySelector('input[name="os"]:checked').value; render({ pkg, category: category.value, country: country.value, os }); }); document.getElementById('sampleBtn').addEventListener('click', () => { packageName.value = 'com.example.finance'; category.value = 'finance'; country.value = 'ID'; form.querySelector('input[name="os"][value="AOS"]').checked = true; message.textContent = ''; }); resetBtn.addEventListener('click', () => { form.reset(); message.textContent = ''; content.classList.add('hidden'); resetBtn.classList.add('hidden'); empty.classList.remove('hidden'); packageName.focus(); }); })();