122 lines
5.1 KiB
JavaScript
122 lines
5.1 KiB
JavaScript
(() => {
|
|
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 = `<div><span>PACKAGE</span><strong>${escapeHtml(query.pkg)}</strong></div><div><span>CATEGORY</span><strong>${escapeHtml(categoryLabel(query.category))}</strong></div><div><span>GEO</span><strong>${escapeHtml(countryLabel(query.country))}</strong></div>`;
|
|
list.innerHTML = results.map((item, index) => {
|
|
const [level, label, className] = priority(item.score, index);
|
|
return `<article class="result-card ${index === 0 ? 'top-result' : ''}">
|
|
<div class="rank">${String(index + 1).padStart(2, '0')}</div>
|
|
<div class="result-main"><div class="result-name"><h3>${escapeHtml(item.name)}</h3><span>${escapeHtml(item.type)}</span></div>
|
|
<div class="reason-tags">${item.reasons.slice(1, 4).map((reason) => `<span>${escapeHtml(reason)}</span>`).join('')}</div>
|
|
<p>${escapeHtml(item.strengths.join(' · '))}</p>
|
|
</div>
|
|
<div class="score-block"><div class="score-ring" style="--score:${item.score}"><strong>${item.score}</strong><small>/100</small></div><span class="priority ${className}">${level} · ${label}</span></div>
|
|
</article>`;
|
|
}).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();
|
|
});
|
|
})();
|