에러코드 누적 순위 차트 축 수정 — 에러코드 Y축, 충전기별 스택
- 기존: 충전기 Y축 + 에러코드별 스택 (충전기 중심) - 변경: 에러코드 Y축 + 충전기별 스택 (에러코드 순위 중심) - 어떤 에러코드가 가장 많이 발생했는지 + 어떤 충전기에서 발생했는지 한눈에 확인 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -230,8 +230,8 @@
|
||||
<!-- 충전기별 에러코드 누적 순위 -->
|
||||
<div class="card" style="margin-bottom:20px">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;flex-wrap:wrap;gap:8px">
|
||||
<div class="card-title" style="margin:0">⚡ 충전기별 에러코드 누적 순위 Top 10</div>
|
||||
<span style="font-size:11px;color:var(--gray4)">에러코드 입력된 신고 기준</span>
|
||||
<div class="card-title" style="margin:0">⚠️ 에러코드 누적 순위 Top 10</div>
|
||||
<span style="font-size:11px;color:var(--gray4)">에러코드 입력된 신고 기준 · 색상 = 충전기</span>
|
||||
</div>
|
||||
<div id="errorCodesChartWrap" style="position:relative">
|
||||
<canvas id="errorCodesChart"></canvas>
|
||||
@@ -636,29 +636,29 @@ async function loadTopChargersChart() {
|
||||
});
|
||||
}
|
||||
|
||||
/* ── 충전기별 에러코드 차트 ── */
|
||||
/* ── 에러코드별 누적 순위 차트 ── */
|
||||
let _errorCodesChart = null;
|
||||
async function loadErrorCodesChart() {
|
||||
const data = await API.get('/stats/charger-error-codes');
|
||||
const wrap = document.getElementById('errorCodesChartWrap');
|
||||
if (!data.chargers || !data.chargers.length) {
|
||||
if (!data.error_codes || !data.error_codes.length) {
|
||||
wrap.innerHTML = '<div style="color:var(--gray4);font-size:13px;text-align:center;padding:30px 0">에러코드가 입력된 신고가 없습니다.</div>';
|
||||
return;
|
||||
}
|
||||
const { chargers, error_codes: codes } = data;
|
||||
const CODE_COLORS = ['#EF4444','#F59E0B','#3B82F6','#10B981','#8B5CF6','#EC4899','#94A3B8'];
|
||||
const { error_codes, charger_labels, dataset_keys } = data;
|
||||
const CHARGER_COLORS = ['#3B82F6','#EF4444','#F59E0B','#10B981','#8B5CF6','#94A3B8'];
|
||||
|
||||
wrap.style.height = (chargers.length * 32 + 50) + 'px';
|
||||
wrap.style.height = (error_codes.length * 32 + 50) + 'px';
|
||||
if (_errorCodesChart) _errorCodesChart.destroy();
|
||||
const ctx = document.getElementById('errorCodesChart').getContext('2d');
|
||||
_errorCodesChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: chargers.map(c => c.label),
|
||||
datasets: codes.map((code, i) => ({
|
||||
label: code,
|
||||
data: chargers.map(c => c[code] || 0),
|
||||
backgroundColor: CODE_COLORS[i % CODE_COLORS.length],
|
||||
labels: error_codes.map(e => e.error_code),
|
||||
datasets: dataset_keys.map((key, i) => ({
|
||||
label: charger_labels[key],
|
||||
data: error_codes.map(e => e[key] || 0),
|
||||
backgroundColor: CHARGER_COLORS[i % CHARGER_COLORS.length],
|
||||
borderRadius: 3,
|
||||
stack: 'err',
|
||||
}))
|
||||
@@ -667,11 +667,6 @@ async function loadErrorCodesChart() {
|
||||
indexAxis: 'y',
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
onClick: (evt, elems) => {
|
||||
if (!elems.length) return;
|
||||
const c = chargers[elems[0].index];
|
||||
location.href = `/pages/admin/reports.html?charger_id=${encodeURIComponent(c.charger_id)}`;
|
||||
},
|
||||
onHover: (evt, elems) => { evt.native.target.style.cursor = elems.length ? 'pointer' : 'default'; },
|
||||
plugins: {
|
||||
legend: { display: true, position: 'top',
|
||||
@@ -679,11 +674,10 @@ async function loadErrorCodesChart() {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
title: items => {
|
||||
const c = chargers[items[0].dataIndex];
|
||||
return c.label + ` (총 ${c.total}건)`;
|
||||
const e = error_codes[items[0].dataIndex];
|
||||
return `에러코드: ${e.error_code} (총 ${e.total}건)`;
|
||||
},
|
||||
label: c => `${c.dataset.label}: ${c.raw}건`,
|
||||
afterLabel: () => '(클릭하면 신고 목록으로)',
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user