js/app.js を作成してください。全てES5互換(var, function宣言, アロー関数不使用, ?. ?? 不使用)で書いてください。
■ グローバル変数:
var API_BASE = 'tables';
var COLORS = { line:'#06C755', ocean:'#0077B6', coral:'#FF6B6B', sand:'#F4A261', purple:'#8B5CF6', teal:'#14B8A6', pink:'#EC4899', indigo:'#6366F1', amber:'#F59E0B', gray:'#6B7280' };
var CHART_COLORS = [上記10色の配列];
var allPathData = [];
var allSummaryData = [];
var currentPeriod = 'all';
var charts = {};
■ 初期化 (DOMContentLoaded):
1. setupDragDrop() — ドラッグ&ドロップ設定
2. loadAllData() → renderAll()
■ loadAllData():
- Promise.allで2つのAPI呼び出しを並列実行:
- GET tables/line_friend_path?limit=1000
- GET tables/line_monthly_summary?limit=1000&sort=-period_start
- 結果を allPathData, allSummaryData に格納
- updatePeriodSelector(), updateLastUpdate() を呼ぶ
■ 期間選択機能 (全関数):
- getUniquePeriods(): allPathDataから一意の期間リスト(start+end)を抽出、日付順ソート
- getAvailableYearMonths(): allPathDataから全年・全月を抽出
- populateYearMonthDropdowns(): 年/月のドロップダウンをデータから動的生成
- setPeriodPreset(preset): 'all','latest','3m','6m','1y'に対応
- 'all' → currentPeriod='all'
- 'latest' → 最新の単一期間
- '3m','6m','1y' → 月数を遡ってYYYY-MM|YYYY-MM形式に
- プリセットボタンのアクティブ切替(緑背景/白)
- カスタムドロップダウンをクリア
- onCustomPeriodChange(): 4つのドロップダウンからYYYY-MM|YYYY-MM形式を構築、プリセットボタンを全リセット
- clearCustomPeriod(): ドロップダウンをクリア、'全期間'に戻す
- updatePeriodInfo(text): id=periodInfoにフィルター情報を表示
- updateLastUpdate(): allSummaryDataの最新period_endをid=lastUpdateに表示
■ フィルター関数:
- getFilteredPathData(): currentPeriodが'all'なら全返却、YYYY-MM|YYYY-MMならperiod_startの年月でフィルタ、それ以外は完全一致
- getMainPaths(data): origin_pointとcampaignが空のレコードのみ返却(=経路ルートレベル)
■ タブ切替:
- switchTab(tab): navTabsの全ボタンからactive除去→該当ボタンにactive追加、tab-contentの表示切替、100msでチャートresize
- 各タブの描画関数を呼ぶ: advice→renderAdvice(), trends→renderTrends(), deep→renderDeepAnalysis(), report→renderReport(), data→renderHistory()
■ renderAll():
- getFilteredPathData()→getMainPaths()で経路データ取得
- renderKPIs(), renderPieChart(), renderBarChart(), renderGaugeChart(), renderRanking(), renderFunnelChart()を呼ぶ
■ renderKPIs():
- allPathDataからgained/blocked合計を計算
- 純増 = gained - blocked
- ブロック率 = blocked/gained*100
- 前期データがあれば前期比デルタを計算(▲プラス緑/▼マイナス赤)
- 成長率 = (今期gained - 前期gained) / 前期gained * 100
- アクティブ経路数 = gainedが1以上あるユニーク経路数
- animateNumber()で数値アニメーション
- 各KPI要素(kpiGained等)にinnerText設定
■ animateNumber(element, target, suffix):
- 0からtargetまでを600msでカウントアップアニメーション
■ renderPieChart():
- ECharts円グラフ。mainPathsの各経路のgained合計をdataに。CHART_COLORSで色分け。
- ラベルにパーセント表示。
■ renderBarChart():
- ECharts横棒グラフ。上位8経路のgained(緑)とblocked(赤)を表示。
■ renderGaugeChart():
- EChartsゲージチャート。全体ブロック率を0-50%レンジで表示。
- 色: 0-15%緑, 15-25%オレンジ, 25-50%赤。
■ renderRanking():
- TOP5経路を色付きバーとバッジで表示。HTMLで生成。
■ renderFunnelChart():
- EChartsファネルチャート。全獲得→残存(純増)の流れ。
■ renderSunburst(data):
- 経路→流入元→キャンペーンの3階層サンバーストチャート。
■ renderTreemap(data):
- 経路ごとの面積比較ツリーマップ。
■ renderPathTable(data):
- テーブルにHTML行を生成。ブロック率の色分け(高=赤、中=オレンジ、低=緑)。
■ renderTrends():
- allSummaryDataが2件未満なら空メッセージ表示
- renderMainTrend(), renderPathTrend(), renderBlockRateTrend()を呼ぶ
■ renderMainTrend(summaries):
- 折れ線+棒グラフ。獲得(緑線)、ブロック(赤線)、純増(青棒)。
- 線形回帰で予測トレンドライン(点線)を2期間先まで延長。
■ renderPathTrend():
- 上位5経路の積み上げ棒グラフ。期間別。
■ renderBlockRateTrend(summaries):
- ブロック率の折れ線 + 20%目標ラインを点線で表示。
■ renderAdvice():
- 総合スコア計算: calculateScore(gained, blockRate, sorted, topPathShare)
- renderScoreChart(score): ゲージチャート
- renderInsights(): キーインサイトHTML生成
- renderAdviceCards(): 優先度付きアドバイスカード(高:赤/中:オレンジ/低:緑)
■ calculateScore(gained, blockRate, sorted, topPathShare):
- ブロック率低い=高スコア、経路多様性高い=高スコア、獲得数多い=高スコア
- 100点満点で返却
■ CSV処理:
- setupDragDrop(): dropZone, modalDropZoneにdrag/drop/dragleaveイベント設定
- handleFileSelect(event): fileInputからprocessCSVFile()
- handleModalFileSelect(event): modalFileInputからprocessCSVFile(file, true)
- processCSVFile(file, isModal):
1. FileReaderでCSV読み込み
2. ファイル名から日付自動検出 (YYYYMMDD_YYYYMMDD形式)
3. 既存期間チェック→上書き確認ダイアログ
4. parseCSV()→saveCSVData()
5. loadAllData()→renderAll()→showNotification()
- parseCSV(text): ヘッダー行で列名判定、行ごとにオブジェクト配列化
- saveCSVData(rows, periodStart, periodEnd):
1. 各行をline_friend_pathにPOST
2. 合計を集計してline_monthly_summaryにPOST
3. カラム名は日本語/英語両対応(path/経路, gained/獲得, blocked/ブロック等)
■ データ履歴:
- renderHistory(): allSummaryDataをperiod_start降順でテーブル表示
- deletePeriod(start, end, summaryId): 確認後、該当期間のpath全削除+summary削除→再読み込み
■ モーダル:
- openUploadModal(): id=uploadModalをflex表示
- closeUploadModal(): 非表示に
■ 通知:
- showNotification(message, type): 右下にトースト通知(成功=緑/エラー=赤)、3秒で自動消去
- showUploadStatus(msg, type, isModal): アップロード結果表示
■ リサイズ対応:
- window resize時に charts オブジェクト内の全EChartsインスタンスをresize()
全てvar宣言、function宣言、forループ使用。const/let/アロー関数/?./??は禁止。