Merge branch 'test-gay'

This commit is contained in:
CAtlas0784 committed 2026-10-17 15:33:54 +07:00
commit 74c7a80bdb
4 files changed
+197 -118

No files matched your search

+9 -1
View File
@@ -2555,12 +2555,20 @@ input:checked + .slider:before {
max-width: 100%; max-width: 100%;
} }
.synergy-metrics-grid { .synergy-metrics-grid,
.mini-battle-metrics-grid {
display: grid; display: grid;
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
gap: 0.5rem; gap: 0.5rem;
} }
@media (max-width: 640px) {
.synergy-metrics-grid,
.mini-battle-metrics-grid {
grid-template-columns: repeat(2, 1fr);
}
}
.synergy-metric-box { .synergy-metric-box {
background: rgba(255, 255, 255, 0.03); background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.07); border: 1px solid rgba(255, 255, 255, 0.07);
+45 -28
View File
@@ -145,31 +145,60 @@
</div> </div>
</div> </div>
<!-- 2. Team Combat Synergy & Weakness Break Analysis --> <!-- 2. Mini Battle Summary & Team Stats -->
<div class="card" id="card-team-synergy"> <div class="card" id="card-battle-summary">
<div class="card-title" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem;"> <div class="card-title" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem;">
<span style="display: flex; align-items: center; gap: 0.5rem;"> <span style="display: flex; align-items: center; gap: 0.5rem;">
<span>⚔️</span> <span>💥</span>
<span data-i18n="synergyTitle">วิเคราะห์ Synergy ทีม & จุดอ่อน</span> <span data-i18n="miniBattleTitle">สรุปการต่อสู้ล่าสุด & ดาเมจทีม</span>
</span> </span>
<span class="badge-super-tag" id="badge-synergy-coverage" style="background: rgba(56, 189, 248, 0.15); color: var(--accent-cyan); font-weight: 800;">ครอบคลุม 0/7 ธาตุ</span> <div style="display: flex; align-items: center; gap: 0.4rem;">
</div> <span class="badge-super-tag" id="badge-mini-battle-status" style="background: rgba(156, 163, 175, 0.12); color: var(--text-muted); font-weight: 800; border: 1px solid rgba(156, 163, 175, 0.25);">
<p class="card-subtitle" style="margin-bottom: 0.85rem;" data-i18n="synergySubtitle">วิเคราะห์การครอบคลุม Weakness Break และความพร้อมของอุปกรณ์ในทีม</p> ยังไม่มีข้อมูลการต่อสู้
</span>
<!-- A. Weakness Break Coverage 7 Elements --> <button type="button" class="btn btn-sm btn-secondary" id="btn-mini-view-full-analyst" style="font-size: 0.725rem; padding: 0.2rem 0.55rem; color: var(--accent-cyan); border-color: rgba(56, 189, 248, 0.35); font-weight: 700;" title="เปิดหน้า Damage Analyst ตัวเต็ม" data-i18n="miniViewFullAnalyst">
<div style="margin-bottom: 1rem;"> Damage Analyst →
<div style="font-size: 0.775rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.4rem;" data-i18n="synergyBreakCoverage"> </button>
🎯 การทำลายจุดอ่อน (Weakness Break Coverage)
</div> </div>
<div class="synergy-elements-grid" id="synergy-elements-container"> </div>
<!-- Rendered dynamically by JS: Physical, Fire, Ice, Lightning, Wind, Quantum, Imaginary --> <p class="card-subtitle" style="margin-bottom: 0.75rem;" data-i18n="miniBattleSubtitle">
สถิติดาเมจ, DPS และสัดส่วนการทำดาเมจของตัวละครในทีมจากการต่อสู้จริงล่าสุด
</p>
<!-- A. Key Battle Metric Boxes (4 Boxes) -->
<div class="mini-battle-metrics-grid" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; margin-bottom: 0.85rem;">
<div class="mini-battle-box" style="background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.07); border-radius: var(--radius-sm); padding: 0.5rem 0.4rem; text-align: center;">
<div class="mini-battle-val" id="mini-total-dmg" style="font-size: 1.15rem; font-weight: 800; color: #f87171; font-family: monospace;">-</div>
<div class="mini-battle-lbl" style="font-size: 0.675rem; color: var(--text-muted); margin-top: 0.15rem;" data-i18n="miniTotalDmg">ดาเมจรวม</div>
</div>
<div class="mini-battle-box" style="background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.07); border-radius: var(--radius-sm); padding: 0.5rem 0.4rem; text-align: center;">
<div class="mini-battle-val" id="mini-team-dps" style="font-size: 1.15rem; font-weight: 800; color: var(--accent-gold); font-family: monospace;">-</div>
<div class="mini-battle-lbl" style="font-size: 0.675rem; color: var(--text-muted); margin-top: 0.15rem;" data-i18n="miniTeamDps">DPS รวม</div>
</div>
<div class="mini-battle-box" style="background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.07); border-radius: var(--radius-sm); padding: 0.5rem 0.4rem; text-align: center;">
<div class="mini-battle-val" id="mini-break-dmg" style="font-size: 1.15rem; font-weight: 800; color: var(--accent-cyan); font-family: monospace;">-</div>
<div class="mini-battle-lbl" style="font-size: 0.675rem; color: var(--text-muted); margin-top: 0.15rem;" data-i18n="miniBreakDmg">Break / Super Break</div>
</div>
<div class="mini-battle-box" style="background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.07); border-radius: var(--radius-sm); padding: 0.5rem 0.4rem; text-align: center;">
<div class="mini-battle-val" id="mini-battle-turns" style="font-size: 1.15rem; font-weight: 800; color: var(--accent-green); font-family: monospace;">-</div>
<div class="mini-battle-lbl" style="font-size: 0.675rem; color: var(--text-muted); margin-top: 0.15rem;" data-i18n="miniBattleTurns">เทิร์น / เวลา</div>
</div> </div>
</div> </div>
<!-- B. Equipment Readiness & Stats Overview --> <!-- B. Mini Avatar Damage Breakdown (4 Avatars) -->
<div style="margin-bottom: 0.85rem;">
<div style="font-size: 0.775rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.4rem;" data-i18n="miniBreakdownTitle">
📊 สัดส่วนดาเมจสมาชิกในทีม (Damage Share)
</div>
<div id="mini-battle-avatars-list" style="display: flex; flex-direction: column; gap: 0.45rem;">
<!-- Rendered dynamically by JS -->
</div>
</div>
<!-- C. Equipment Readiness & Stats Overview -->
<div> <div>
<div style="font-size: 0.775rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.4rem;" data-i18n="synergyEquipmentTitle"> <div style="font-size: 0.775rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.4rem;" data-i18n="synergyEquipmentTitle">
📊 ความพร้อมของอุปกรณ์และเลเวลเฉลี่ย 🛡️ ความพร้อมของอุปกรณ์และเลเวลเฉลี่ย
</div> </div>
<div class="synergy-metrics-grid"> <div class="synergy-metrics-grid">
<div class="synergy-metric-box"> <div class="synergy-metric-box">
@@ -190,18 +219,6 @@
</div> </div>
</div> </div>
</div> </div>
<!-- C. Quick Damage Analyst Banner -->
<div id="synergy-damage-banner" style="margin-top: 1rem; padding: 0.75rem 1rem; border-radius: 8px; background: linear-gradient(135deg, rgba(239, 68, 68, 0.08) 0%, rgba(245, 158, 11, 0.08) 100%); border: 1px solid rgba(239, 68, 68, 0.2); display: flex; justify-content: space-between; align-items: center; cursor: pointer; transition: all 0.2s ease;" title="คลิกเพื่อเปิดหน้า Damage Analyst">
<div style="display: flex; align-items: center; gap: 0.75rem;">
<span style="font-size: 1.4rem;">💥</span>
<div>
<div style="font-size: 0.85rem; font-weight: 700; color: #f87171;" id="dashboard-battle-title">Damage Analyst (จับดาเมจจากในเกม)</div>
<div style="font-size: 0.75rem; color: var(--text-muted);" id="dashboard-battle-summary">ยังไม่มีข้อมูลการต่อสู้ล่าสุด</div>
</div>
</div>
<button type="button" class="btn btn-sm btn-secondary" style="font-size: 0.75rem; padding: 0.25rem 0.6rem; pointer-events: none;">ดูบทวิเคราะห์ →</button>
</div>
</div> </div>
</div> </div>
+117 -87
View File
@@ -73,17 +73,19 @@ const el = {
lineupContainer: document.getElementById('lineup-container'), lineupContainer: document.getElementById('lineup-container'),
toggleCreativeMode: document.getElementById('toggle-creative-mode'), toggleCreativeMode: document.getElementById('toggle-creative-mode'),
badgeCreativeMode: document.getElementById('badge-creative-mode'), badgeCreativeMode: document.getElementById('badge-creative-mode'),
// Team Combat Synergy // Mini Battle Summary & Team Stats
cardTeamSynergy: document.getElementById('card-team-synergy'), cardBattleSummary: document.getElementById('card-battle-summary'),
badgeSynergyCoverage: document.getElementById('badge-synergy-coverage'), badgeMiniBattleStatus: document.getElementById('badge-mini-battle-status'),
synergyElementsContainer: document.getElementById('synergy-elements-container'), miniTotalDmg: document.getElementById('mini-total-dmg'),
miniTeamDps: document.getElementById('mini-team-dps'),
miniBreakDmg: document.getElementById('mini-break-dmg'),
miniBattleTurns: document.getElementById('mini-battle-turns'),
miniBattleAvatarsList: document.getElementById('mini-battle-avatars-list'),
btnMiniViewFullAnalyst: document.getElementById('btn-mini-view-full-analyst'),
synergyAvgLevel: document.getElementById('synergy-avg-level'), synergyAvgLevel: document.getElementById('synergy-avg-level'),
synergyAvgEidolon: document.getElementById('synergy-avg-eidolon'), synergyAvgEidolon: document.getElementById('synergy-avg-eidolon'),
synergyLcReady: document.getElementById('synergy-lc-ready'), synergyLcReady: document.getElementById('synergy-lc-ready'),
synergyRelicReady: document.getElementById('synergy-relic-ready'), synergyRelicReady: document.getElementById('synergy-relic-ready'),
synergyDamageBanner: document.getElementById('synergy-damage-banner'),
dashboardBattleTitle: document.getElementById('dashboard-battle-title'),
dashboardBattleSummary: document.getElementById('dashboard-battle-summary'),
// Damage Analyst // Damage Analyst
tabDamageAnalyst: document.getElementById('tab-damage-analyst'), tabDamageAnalyst: document.getElementById('tab-damage-analyst'),
@@ -1267,20 +1269,112 @@ function renderLineup(lineups) {
} }
// ========================================== // ==========================================
// Team Combat Synergy & Weakness Break Analysis // Mini Battle Summary & Team Stats
// ========================================== // ==========================================
const HSR_ELEMENTS = [ const ELEMENT_COLORS = {
{ key: 'Physical', name: 'Physical', nameTh: 'กายภาพ', color: '#cbd5e1' }, Physical: '#cbd5e1',
{ key: 'Fire', name: 'Fire', nameTh: 'ไฟ', color: '#ef4444' }, Fire: '#ef4444',
{ key: 'Ice', name: 'Ice', nameTh: 'น้ำแข็ง', color: '#38bdf8' }, Ice: '#38bdf8',
{ key: 'Lightning', name: 'Lightning', nameTh: 'สายฟ้า', color: '#c084fc' }, Lightning: '#c084fc',
{ key: 'Wind', name: 'Wind', nameTh: 'ลม', color: '#34d399' }, Thunder: '#c084fc',
{ key: 'Quantum', name: 'Quantum', nameTh: 'ควอนตัม', color: '#818cf8' }, Wind: '#34d399',
{ key: 'Imaginary', name: 'Imaginary', nameTh: 'จินตภาพ', color: '#fbbf24' } Quantum: '#818cf8',
]; Imaginary: '#fbbf24'
};
function renderMiniBattleSummary() {
if (!el.miniBattleAvatarsList) return;
const report = analystState.currentReport;
if (!report || !report.team_total_damage || !report.avatars || report.avatars.length === 0) {
if (el.badgeMiniBattleStatus) {
el.badgeMiniBattleStatus.textContent = t('miniNoBattleTitle');
el.badgeMiniBattleStatus.style.background = 'rgba(156, 163, 175, 0.12)';
el.badgeMiniBattleStatus.style.color = 'var(--text-muted)';
el.badgeMiniBattleStatus.style.borderColor = 'rgba(156, 163, 175, 0.25)';
}
if (el.miniTotalDmg) el.miniTotalDmg.textContent = '-';
if (el.miniTeamDps) el.miniTeamDps.textContent = '-';
if (el.miniBreakDmg) el.miniBreakDmg.textContent = '-';
if (el.miniBattleTurns) el.miniBattleTurns.textContent = '-';
el.miniBattleAvatarsList.innerHTML = `
<div style="background: rgba(0,0,0,0.25); border: 1px dashed rgba(255,255,255,0.1); border-radius: var(--radius-sm); padding: 0.85rem 1rem; text-align: center;">
<div style="font-size: 1.35rem; margin-bottom: 0.25rem;">⚔️</div>
<div style="font-size: 0.85rem; font-weight: 700; color: #fff;">${t('miniNoBattleTitle')}</div>
<div style="font-size: 0.75rem; color: var(--text-muted); margin-top: 0.2rem;">
${t('miniNoBattleDesc')}
</div>
<div style="margin-top: 0.6rem; display: flex; justify-content: center; gap: 0.5rem; flex-wrap: wrap;">
<button type="button" class="btn btn-sm btn-secondary" onclick="window.fetchLatestBattleReport(false)" style="font-size: 0.75rem; padding: 0.25rem 0.6rem;">
${t('miniBtnFetch')}
</button>
<button type="button" class="btn btn-sm btn-primary" onclick="window.loadDemoBattleReport()" style="font-size: 0.75rem; padding: 0.25rem 0.6rem; background: linear-gradient(135deg, #0284c7 0%, #0369a1 100%); border-color: #38bdf8;">
${t('miniBtnDemo')}
</button>
</div>
</div>
`;
return;
}
// Active Report
const isWin = (report.end_status || 'WIN').toUpperCase() === 'WIN';
if (el.badgeMiniBattleStatus) {
el.badgeMiniBattleStatus.textContent = isWin ? '✅ ชนะการต่อสู้' : `⚠️ สิ้นสุด (${report.end_status})`;
el.badgeMiniBattleStatus.style.background = isWin ? 'rgba(52, 211, 153, 0.15)' : 'rgba(239, 68, 68, 0.15)';
el.badgeMiniBattleStatus.style.color = isWin ? 'var(--accent-green)' : '#f87171';
el.badgeMiniBattleStatus.style.borderColor = isWin ? 'rgba(52, 211, 153, 0.4)' : 'rgba(239, 68, 68, 0.4)';
}
const durationSec = report.cost_time || 0;
const teamDps = durationSec > 0 ? (report.team_total_damage / durationSec) : 0;
let totalBreakDmg = 0;
(report.avatars || []).forEach(a => {
totalBreakDmg += (a.total_break_damage || 0);
});
if (el.miniTotalDmg) el.miniTotalDmg.textContent = formatNumber(report.team_total_damage);
if (el.miniTeamDps) el.miniTeamDps.textContent = `${formatNumber(Math.round(teamDps))}/s`;
if (el.miniBreakDmg) el.miniBreakDmg.textContent = formatNumber(totalBreakDmg);
if (el.miniBattleTurns) el.miniBattleTurns.textContent = `${report.total_battle_turns || 0} เทิร์น (${formatDuration(durationSec)})`;
// Sort avatars by total damage descending
const sortedAvatars = [...report.avatars].sort((a, b) => (b.total_damage || 0) - (a.total_damage || 0));
el.miniBattleAvatarsList.innerHTML = sortedAvatars.map(av => {
const meta = getAvatarInfo(av.avatar_id);
const elemColor = ELEMENT_COLORS[meta.element] || '#38bdf8';
const pct = Math.max(0, Math.min(100, av.damage_percent || 0));
const iconUrl = getAvatarIconUrl(av.avatar_id);
const rankStr = av.rank !== undefined ? `E${av.rank}` : '';
const lvlStr = av.level ? `Lv.${av.level}` : '';
const metaSub = [lvlStr, rankStr, translatePath(meta.path)].filter(Boolean).join(' • ');
return `
<div style="background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.06); border-radius: var(--radius-sm); padding: 0.45rem 0.65rem; transition: background 0.2s ease;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.35rem;">
<div style="display: flex; align-items: center; gap: 0.5rem; min-width: 0;">
<img src="${iconUrl}" onerror="window.handleAvatarImgError(this, ${av.avatar_id})" style="width: 28px; height: 28px; border-radius: 50%; border: 1.5px solid ${elemColor}; object-fit: cover; flex-shrink: 0;" alt="${meta.name}">
<div style="min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
<div style="font-size: 0.825rem; font-weight: 700; color: #fff; line-height: 1.1;">${meta.name}</div>
<div style="font-size: 0.675rem; color: var(--text-muted);">${metaSub}</div>
</div>
</div>
<div style="text-align: right; flex-shrink: 0;">
<span style="font-size: 0.875rem; font-weight: 800; color: ${elemColor}; font-family: monospace;">${formatNumber(av.total_damage)}</span>
<span style="font-size: 0.725rem; font-weight: 700; color: #fff; background: rgba(255,255,255,0.08); padding: 0.1rem 0.35rem; border-radius: 4px; margin-left: 0.35rem;">${pct.toFixed(1)}%</span>
</div>
</div>
<div style="height: 5px; width: 100%; background: rgba(0,0,0,0.4); border-radius: 3px; overflow: hidden;">
<div style="height: 100%; width: ${pct}%; background: ${elemColor}; border-radius: 3px; transition: width 0.4s ease;"></div>
</div>
</div>
`;
}).join('');
}
function renderTeamSynergy(lineups) { function renderTeamSynergy(lineups) {
if (!el.synergyElementsContainer) return;
const currentLineup = lineups || state.statusData?.lineups || DEFAULT_LINEUP; const currentLineup = lineups || state.statusData?.lineups || DEFAULT_LINEUP;
// Extract active character IDs // Extract active character IDs
@@ -1292,22 +1386,12 @@ function renderTeamSynergy(lineups) {
} }
} }
// 1. Weakness Break Coverage
const coveredElements = {};
const roles = {
dps: [], // Destruction, Hunt, Erudition
specialist: [], // Remembrance, Elation
support: [], // Harmony, Nihility
sustain: [] // Preservation, Abundance
};
let totalLevel = 0; let totalLevel = 0;
let totalEidolon = 0; let totalEidolon = 0;
let lcCount = 0; let lcCount = 0;
let fullRelicCount = 0; let fullRelicCount = 0;
activeIds.forEach(aid => { activeIds.forEach(aid => {
const meta = getAvatarInfo(aid);
const av = state.fullFreesrData?.avatars?.[aid]; const av = state.fullFreesrData?.avatars?.[aid];
const lvl = av?.level || 80; const lvl = av?.level || 80;
const rank = av?.data?.rank ?? (state.avatarsList.find(a => a.avatar_id === aid)?.rank ?? 0); const rank = av?.data?.rank ?? (state.avatarsList.find(a => a.avatar_id === aid)?.rank ?? 0);
@@ -1315,25 +1399,6 @@ function renderTeamSynergy(lineups) {
totalLevel += lvl; totalLevel += lvl;
totalEidolon += rank; totalEidolon += rank;
// Element coverage
const rawElem = normalizeElement(meta.rawElement || meta.element);
if (!coveredElements[rawElem]) {
coveredElements[rawElem] = [];
}
coveredElements[rawElem].push(meta.name);
// Path / Role
const rawPath = normalizePath(meta.rawPath || meta.path);
if (['Destruction', 'Hunt', 'Erudition'].includes(rawPath)) {
roles.dps.push(meta.name);
} else if (['Remembrance', 'Elation'].includes(rawPath)) {
roles.specialist.push(meta.name);
} else if (['Harmony', 'Nihility'].includes(rawPath)) {
roles.support.push(meta.name);
} else if (['Preservation', 'Abundance'].includes(rawPath)) {
roles.sustain.push(meta.name);
}
// LC check // LC check
const hasLc = (state.fullFreesrData?.lightcones || []).some(l => l.equip_avatar === aid); const hasLc = (state.fullFreesrData?.lightcones || []).some(l => l.equip_avatar === aid);
if (hasLc) lcCount++; if (hasLc) lcCount++;
@@ -1347,33 +1412,13 @@ function renderTeamSynergy(lineups) {
const avgLevel = activeIds.length ? (totalLevel / count).toFixed(1) : '-'; const avgLevel = activeIds.length ? (totalLevel / count).toFixed(1) : '-';
const avgEidolon = activeIds.length ? `E${(totalEidolon / count).toFixed(1)}` : '-'; const avgEidolon = activeIds.length ? `E${(totalEidolon / count).toFixed(1)}` : '-';
// Render Element Chips
const coveredCount = Object.keys(coveredElements).length;
if (el.badgeSynergyCoverage) {
el.badgeSynergyCoverage.textContent = t('synergyCoverageBadge', { count: coveredCount });
el.badgeSynergyCoverage.style.color = coveredCount >= 4 ? 'var(--accent-green)' : (coveredCount >= 2 ? 'var(--accent-cyan)' : 'var(--accent-gold)');
}
el.synergyElementsContainer.innerHTML = HSR_ELEMENTS.map(elem => {
const isCovered = !!coveredElements[elem.key];
const providers = coveredElements[elem.key] || [];
const providerText = isCovered ? providers.join(', ') : t('synergyNoInTeam');
return `
<div class="synergy-element-chip ${isCovered ? 'active' : 'inactive'}" style="${isCovered ? `border-color: ${elem.color}66; box-shadow: 0 0 8px ${elem.color}22;` : ''}">
${getElementIconHtml(elem.key, 22)}
<span class="synergy-element-name" style="${isCovered ? `color: ${elem.color};` : ''}">${translateElement(elem.key)}</span>
<span class="synergy-element-chars" title="${providerText}">${providerText}</span>
</div>
`;
}).join('');
// Metrics // Metrics
if (el.synergyAvgLevel) el.synergyAvgLevel.textContent = activeIds.length ? `Lv.${avgLevel}` : '-'; if (el.synergyAvgLevel) el.synergyAvgLevel.textContent = activeIds.length ? `Lv.${avgLevel}` : '-';
if (el.synergyAvgEidolon) el.synergyAvgEidolon.textContent = avgEidolon; if (el.synergyAvgEidolon) el.synergyAvgEidolon.textContent = avgEidolon;
if (el.synergyLcReady) el.synergyLcReady.textContent = activeIds.length ? `${lcCount}/${activeIds.length}` : '-'; if (el.synergyLcReady) el.synergyLcReady.textContent = activeIds.length ? `${lcCount}/${activeIds.length}` : '-';
if (el.synergyRelicReady) el.synergyRelicReady.textContent = activeIds.length ? `${fullRelicCount}/${activeIds.length}` : '-'; if (el.synergyRelicReady) el.synergyRelicReady.textContent = activeIds.length ? `${fullRelicCount}/${activeIds.length}` : '-';
updateDashboardBattleBanner(); renderMiniBattleSummary();
} }
// ========================================== // ==========================================
@@ -8070,23 +8115,7 @@ function renderDamageAnalyst() {
} }
function updateDashboardBattleBanner() { function updateDashboardBattleBanner() {
if (!el.dashboardBattleTitle || !el.dashboardBattleSummary) return; renderMiniBattleSummary();
const report = analystState.currentReport;
if (!report || !report.team_total_damage) {
el.dashboardBattleTitle.textContent = "Damage Analyst (จับดาเมจจากในเกม)";
el.dashboardBattleSummary.textContent = "ยังไม่มีข้อมูลการต่อสู้ล่าสุด — กดเพื่อเปิดหน้า Damage Analyst";
return;
}
const topAvatar = (report.avatars && report.avatars.length > 0)
? [...report.avatars].sort((a, b) => b.total_damage - a.total_damage)[0]
: null;
const topName = topAvatar ? getAvatarInfo(topAvatar.avatar_id).name : '';
const topDmgPct = topAvatar ? `${topAvatar.damage_percent.toFixed(0)}%` : '';
el.dashboardBattleTitle.textContent = `💥 ดาเมจรวม ${formatNumber(report.team_total_damage)} (${report.round_cnt} รอบ)`;
el.dashboardBattleSummary.textContent = topName
? `MVP: ${topName} (${topDmgPct} Share) • ${report.total_battle_turns} เทิร์น • เวลา ${formatDuration(report.cost_time)}`
: `สถานะ: ${report.end_status || 'WIN'} • ${report.total_battle_turns} เทิร์น`;
} }
function exportBattleReportJson() { function exportBattleReportJson() {
@@ -8289,8 +8318,8 @@ function setupDamageAnalystEvents() {
}); });
} }
if (el.synergyDamageBanner) { if (el.btnMiniViewFullAnalyst) {
el.synergyDamageBanner.addEventListener('click', () => { el.btnMiniViewFullAnalyst.addEventListener('click', () => {
const btn = document.querySelector('.tab-btn[data-tab="tab-damage-analyst"]'); const btn = document.querySelector('.tab-btn[data-tab="tab-damage-analyst"]');
if (btn) btn.click(); if (btn) btn.click();
}); });
@@ -8305,6 +8334,7 @@ function setupDamageAnalystEvents() {
} }
} }
window.renderMiniBattleSummary = renderMiniBattleSummary;
window.fetchLatestBattleReport = fetchLatestBattleReport; window.fetchLatestBattleReport = fetchLatestBattleReport;
window.loadDemoBattleReport = loadDemoBattleReport; window.loadDemoBattleReport = loadDemoBattleReport;
window.exportBattleReportJson = exportBattleReportJson; window.exportBattleReportJson = exportBattleReportJson;
+26 -2
View File
@@ -374,11 +374,23 @@ export const TRANSLATIONS = {
"btnAllE0S1": "⚡ ปรับ E0S1 ทุกตัว", "btnAllE0S1": "⚡ ปรับ E0S1 ทุกตัว",
"qaGachabaseTitle": "ดึงข้อมูล Gachabase", "qaGachabaseTitle": "ดึงข้อมูล Gachabase",
"qaGachabaseDesc": "นำเข้าตัวละคร/กรวยแสง เบต้าหรือใหม่ล่าสุด", "qaGachabaseDesc": "นำเข้าตัวละคร/กรวยแสง เบต้าหรือใหม่ล่าสุด",
"miniBattleTitle": "สรุปการต่อสู้ล่าสุด & ดาเมจทีม",
"miniBattleSubtitle": "สถิติดาเมจ, DPS และสัดส่วนการทำดาเมจของตัวละครในทีมจากการต่อสู้จริงล่าสุด",
"miniTotalDmg": "ดาเมจรวม",
"miniTeamDps": "DPS รวม",
"miniBreakDmg": "Break / Super Break",
"miniBattleTurns": "เทิร์น / เวลา",
"miniBreakdownTitle": "สัดส่วนดาเมจสมาชิกในทีม (Damage Share)",
"miniViewFullAnalyst": "Damage Analyst →",
"miniNoBattleTitle": "ยังไม่มีข้อมูลการต่อสู้ล่าสุด",
"miniNoBattleDesc": "เข้าสู้ในเกม (Calyx / Shadow / Boss) เพื่อเริ่มจับสถิติดาเมจแบบเรียลไทม์",
"miniBtnFetch": "🔄 ดึงข้อมูลสด",
"miniBtnDemo": "⚡ โหลดข้อมูลตัวอย่าง",
"synergyTitle": "วิเคราะห์ Synergy ทีม & จุดอ่อน", "synergyTitle": "วิเคราะห์ Synergy ทีม & จุดอ่อน",
"synergySubtitle": "วิเคราะห์การครอบคลุม Weakness Break, ความสมดุลของบทบาท และความพร้อมของทีม", "synergySubtitle": "วิเคราะห์การครอบคลุม Weakness Break, ความสมดุลของบทบาท และความพร้อมของทีม",
"synergyBreakCoverage": "🎯 การทำลายจุดอ่อน (Weakness Break Coverage)", "synergyBreakCoverage": "🎯 การทำลายจุดอ่อน (Weakness Break Coverage)",
"synergyRoleBalance": "🛡️ การกระจายบทบาทในทีม (Team Composition & Roles)", "synergyRoleBalance": "🛡️ การกระจายบทบาทในทีม (Team Composition & Roles)",
"synergyEquipmentTitle": "📊 ความพร้อมของอุปกรณ์และเลเวลเฉลี่ย", "synergyEquipmentTitle": "🛡️ ความพร้อมของอุปกรณ์และเลเวลเฉลี่ย",
"synergyAvgLevel": "เลเวลเฉลี่ย", "synergyAvgLevel": "เลเวลเฉลี่ย",
"synergyAvgEidolon": "Eidolon เฉลี่ย", "synergyAvgEidolon": "Eidolon เฉลี่ย",
"synergyLcEquipped": "สวมกรวยแสง", "synergyLcEquipped": "สวมกรวยแสง",
@@ -807,11 +819,23 @@ export const TRANSLATIONS = {
"btnGenAndEquip": "Generate & Equip", "btnGenAndEquip": "Generate & Equip",
"selectFromInventory": "Select from Inventory", "selectFromInventory": "Select from Inventory",
"btnAllE0S1": "⚡ All E0S1", "btnAllE0S1": "⚡ All E0S1",
"miniBattleTitle": "Recent Battle & Team Damage",
"miniBattleSubtitle": "Live damage stats, DPS, and damage share from the latest combat",
"miniTotalDmg": "Total DMG",
"miniTeamDps": "Team DPS",
"miniBreakDmg": "Break / Super Break",
"miniBattleTurns": "Turns / Time",
"miniBreakdownTitle": "Team Damage Share",
"miniViewFullAnalyst": "Damage Analyst →",
"miniNoBattleTitle": "No Recent Battle Recorded",
"miniNoBattleDesc": "Fight in-game (Calyx / Shadow / Boss) to track real-time combat stats",
"miniBtnFetch": "🔄 Fetch Live",
"miniBtnDemo": "⚡ Load Demo Data",
"synergyTitle": "Team Synergy & Weakness Analysis", "synergyTitle": "Team Synergy & Weakness Analysis",
"synergySubtitle": "Analyze Weakness Break coverage, role balance, and equipment readiness", "synergySubtitle": "Analyze Weakness Break coverage, role balance, and equipment readiness",
"synergyBreakCoverage": "🎯 Weakness Break Coverage", "synergyBreakCoverage": "🎯 Weakness Break Coverage",
"synergyRoleBalance": "🛡️ Team Composition & Role Distribution", "synergyRoleBalance": "🛡️ Team Composition & Role Distribution",
"synergyEquipmentTitle": "📊 Equipment Readiness & Average Level", "synergyEquipmentTitle": "🛡️ Equipment Readiness & Average Level",
"synergyAvgLevel": "Avg Level", "synergyAvgLevel": "Avg Level",
"synergyAvgEidolon": "Avg Eidolon", "synergyAvgEidolon": "Avg Eidolon",
"synergyLcEquipped": "Lightcones Equipped", "synergyLcEquipped": "Lightcones Equipped",