(() => {
const auth = window.TrafficAuth;
const current = auth.requireUser();
if (!current) return;
const templates = window.LINK_TEMPLATES;
const historyStore = window.LinkHistoryStore;
if (!templates?.length) return;
const { convertTrackingLink } = window.TrackingLinkConverter;
const $ = (id) => document.getElementById(id);
const platformSelect = $('platformSelect');
const macroBody = $('macroTableBody');
const output = $('urlOutput');
let activeResult = null;
let inputTimer;
$('currentUser').textContent = current.username;
$('templateCount').textContent = `${templates.length} 个平台模板`;
templates.forEach((template, index) => platformSelect.add(new Option(template.name, index)));
const activeTemplate = () => templates[Number(platformSelect.value || 0)];
function ensureSession() {
const active = auth.currentUser();
if (active?.username === current.username) return true;
location.replace('login.html?next=link-generator.html');
return false;
}
auth.watchSession(() => location.replace('login.html?next=link-generator.html'));
function scopedHistoryCount() {
const records = historyStore.list();
return current.role === 'admin' ? records.length : records.filter((item) => item.username === current.username).length;
}
function updateHistoryCount() {
$('historyCountBadge').textContent = scopedHistoryCount();
}
function renderPlatform() {
const template = activeTemplate();
const review = template.status.includes('待');
$('platformStatus').innerHTML = `${escapeHtml(template.status)}`;
$('macroReferenceTitle').textContent = `${template.name} 平台宏参考`;
renderMacros();
if ($('originalLink').value.trim()) convertFromInput(false);
}
function renderMacros() {
const query = $('macroSearch').value.trim().toLowerCase();
const allMacros = activeTemplate().macros;
const rows = allMacros.filter(([macro, desc]) => `${macro} ${desc}`.toLowerCase().includes(query));
$('macroCount').textContent = `${allMacros.length} 个可用宏 · 点击展开`;
macroBody.innerHTML = rows.length ? rows.map(([macro, desc]) => `
${escapeHtml(macro)} | ${escapeHtml(desc)} |
`).join('') : '| 没有匹配的媒体宏 |
';
}
function renderChanges(changes) {
const rows = changes.length ? changes : [{ key:'—', from:'原链接参数无需变化', to:'—' }];
$('mappingTableBody').innerHTML = rows.map((change) => `${escapeHtml(change.key)} | ${escapeHtml(change.from || '(空值)')} | ${change.to ? `${escapeHtml(change.to)}` : '留空'} |
`).join('');
}
function showEmpty() {
activeResult = null;
$('conversionEmpty').classList.remove('hidden');
$('conversionResult').classList.add('hidden');
$('detectedType').textContent = '等待链接';
$('generatorMessage').textContent = '';
$('copyStatus').textContent = '';
$('copyLink').disabled = true;
}
function showError(message) {
activeResult = null;
$('generatorMessage').textContent = message;
$('conversionEmpty').classList.remove('hidden');
$('conversionResult').classList.add('hidden');
$('detectedType').textContent = '无法识别';
$('copyLink').disabled = true;
}
function convertFromInput(showRequiredMessage = true) {
const original = $('originalLink').value.trim();
$('copyStatus').textContent = '';
if (!original) {
showEmpty();
if (showRequiredMessage) $('generatorMessage').textContent = '请先粘贴一条完整的 Tracking Link';
return null;
}
try {
const result = convertTrackingLink(original, activeTemplate());
activeResult = result;
const typeLabel = result.type === 'imp' ? 'Impression' : 'Click';
$('detectedType').innerHTML = `${typeLabel}`;
$('summaryType').textContent = typeLabel;
$('replacementCount').textContent = result.changes.length;
$('preservedCount').textContent = result.preservedCount;
$('urlLength').textContent = `${result.url.length} chars`;
output.textContent = result.url;
renderChanges(result.changes);
$('generatorMessage').textContent = result.changes.length ? '' : '链接有效,但没有发现需要替换的参数';
$('conversionEmpty').classList.add('hidden');
$('conversionResult').classList.remove('hidden');
$('copyLink').disabled = false;
return result;
} catch (error) {
showError(error.message === 'Invalid URL' ? '链接格式不正确,请粘贴包含 http:// 或 https:// 的完整链接' : error.message);
return null;
}
}
function extractPkg(url) {
try { return new URL(url).searchParams.get('pkg') || '—'; }
catch (_) { return '—'; }
}
function convertAndSave() {
if (!ensureSession()) return;
const result = convertFromInput(true);
if (!result) return;
const saved = historyStore.add({ username:current.username, userRole:current.role, platform:activeTemplate().name, pkg:extractPkg(result.url), type:result.type, url:result.url });
if (!saved.ok) return showToast('转换成功,但浏览器无法保存记录');
updateHistoryCount();
$('generatorMessage').textContent = '转换完成,已记录操作用户';
showToast('转换完成并已保存记录');
}
function loadSample() {
$('originalLink').value = activeTemplate().sample || '';
convertFromInput(false);
}
async function copyText(text) {
try { await navigator.clipboard.writeText(text); }
catch (_) {
const area = document.createElement('textarea'); area.value = text;
area.style.position = 'fixed'; area.style.opacity = '0';
document.body.appendChild(area); area.select(); document.execCommand('copy'); area.remove();
}
}
async function copyUrl() {
if (!activeResult || !ensureSession()) return;
await copyText(activeResult.url);
$('copyStatus').textContent = '已复制'; showToast('转换后的平台链接已复制');
}
function showToast(message) {
const toast = $('toast'); toast.textContent = message; toast.classList.add('show');
clearTimeout(showToast.timer); showToast.timer = setTimeout(() => toast.classList.remove('show'), 1800);
}
function escapeHtml(value) {
return String(value).replace(/[&<>"']/g, (char) => ({ '&':'&', '<':'<', '>':'>', '"':'"', "'":''' })[char]);
}
$('logoutBtn').addEventListener('click', () => { auth.logout(); location.href = 'login.html'; });
platformSelect.addEventListener('change', renderPlatform);
$('macroSearch').addEventListener('input', renderMacros);
$('convertLink').addEventListener('click', convertAndSave);
$('sampleLink').addEventListener('click', loadSample);
$('copyLink').addEventListener('click', copyUrl);
$('clearConverter').addEventListener('click', () => { $('originalLink').value = ''; showEmpty(); $('originalLink').focus(); });
$('originalLink').addEventListener('input', () => { clearTimeout(inputTimer); inputTimer = setTimeout(() => convertFromInput(false), 220); });
window.addEventListener('storage', (event) => { if (event.key === historyStore.STORAGE_KEY) updateHistoryCount(); });
renderPlatform(); showEmpty(); updateHistoryCount();
})();