feat: add traffic intelligence toolkit

This commit is contained in:
王源
2026-10-19 19:50:06 +08:00
commit f34e0e085a
10 changed files with 609 additions and 0 deletions
+121
View File
@@ -0,0 +1,121 @@
(() => {
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) => ({ '&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#39;' })[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();
});
})();