[verified] Sources table auto-derived from FACTORS registry + next-update column

- _build_sources now iterates FACTORS registry (grouped by fetch module) instead of hardcoded 5-row list -> adding a FACTOR auto-appends its source row (single source of truth, answers 'เพิ่มแหล่งควรอัตโนมัติ')
- Each source row gains ความถี่ + อัปเดตครั้งต่อไป (from frequency cadence)
- Frontend sources table: 6 columns (ข้อมูล/แหล่ง/ช่วงข้อมูล/ความถี่/อัปเดตครั้งต่อไป/อัปเดตล่าสุด), all from /api/v1/dashboard (not mock)
- Verified live: 5 sources auto-derived w/ next-update; browser shows 6 cols
This commit is contained in:
Kunthawat Greethong
2026-08-26 15:55:30 +07:00
parent 5516fc51a0
commit 2da73b8a8c
2 changed files with 83 additions and 13 deletions

View File

@@ -332,18 +332,86 @@ class RealDashboard:
return board
def _build_sources(self, auto_d, npl_d, en_d, macro_d, tourism) -> list:
"""Sources derived from the FACTORS registry — adding a factor to
factors.py auto-appends its source row here (no hardcoded list)."""
import datetime as _dt
from app import factors as factors_mod
now = _dt.datetime.now(_dt.timezone.utc).isoformat(timespec="minutes")
rows = [
{"จาก": "สินเชื่อรถยนต์ (ยอดขายรถ)", "แหล่ง": "TradingEconomics", "ข้อมูล": auto_d.get("as_of", "น่าล่าสุด")},
{"จาก": "NPL รถยนต์", "แหล่ง": "BOT FI_NP_003_S2", "ข้อมูล": npl_d.get("period", "รายไตรมาส")},
{"จาก": "โรงกลั่น (TOP)", "แหล่ง": "Thai Oil investor", "ข้อมูล": "รายไตรมาส"},
{"จาก": "ภาพรวมประเทศไทย", "แหล่ง": "BOT Thai Economy", "ข้อมูล": "รายเดือน"},
]
for r in rows:
r["dึงมาเมื่อ"] = now
# append tourism source if present
fetched = {
"auto_credit": auto_d, "auto_npl": npl_d,
"energy_thai": en_d, "macro_thai": macro_d,
}
# group FACTORS by fetch module -> one row per distinct source
source_by_module: dict = {}
for fkey, f in factors_mod.FACTORS.items():
mod = f.get("fetch")
if not mod:
continue
if mod not in source_by_module:
source_by_module[mod] = {
"mod": mod,
"source": f.get("source", mod),
"freq": f.get("frequency", "monthly"),
"factors": [],
}
source_by_module[mod]["factors"].append(fkey)
# next-update cadence per frequency (hours)
_cadence = {"daily": 24, "monthly": 24 * 30, "quarterly": 24 * 91,
"annual": 24 * 365, "weekly": 24 * 7}
rows = []
for mod, meta in source_by_module.items():
data = fetched.get(mod) or {}
_source_label = {
"auto_credit": "TradingEconomics",
"auto_npl": "BOT FI_NP_003_S2",
"energy_thai": "Thai Oil investor",
"macro_thai": "BOT Thai Economy",
"bot_tourism": "BOT Tourism",
}
freq = meta["freq"]
as_of = data.get("as_of") or data.get("period") or _period(data, meta["factors"])
next_in_h = _cadence.get(freq, 24 * 30)
next_at = (now_plus(now, next_in_h))
rows.append({
"แหล่ง": _source_label.get(mod, meta["source"]),
"ขอบเขต": " | ".join(factors_mod.FACTORS[k]["name_th"] for k in meta["factors"]),
"ข้อมูล": as_of or "",
"ความถี่": freq_th(freq),
"อัปเดตครั้งต่อไป": next_at,
"dึงมาเมื่อ": now,
})
# tourism (fetched separately)
if tourism and isinstance(tourism, dict):
rows.append({"จาก": "ท่องเที่ยว", "แหล่ง": tourism.get("source", {}).get("source_id", "BOT"),
"ข้อมูล": tourism.get("period", ""), "dึงมาเมื่อ": now})
rows.insert(0, {
"แหล่ง": "BOT Tourism",
"ขอบเขต": "นักท่องเที่ยว",
"ข้อมูล": tourism.get("period", "") or "",
"ความถี่": "รายเดือน",
"อัปเดตครั้งต่อไป": now_plus(now, 24 * 30),
"dึงมาเมื่อ": now,
})
return rows
def now_plus(iso_now: str, hours: float) -> str:
import datetime as _dt
base = _dt.datetime.fromisoformat(iso_now)
return (base + _dt.timedelta(hours=hours)).isoformat(timespec="minutes")
def freq_th(freq: str) -> str:
return {"daily": "รายวัน", "weekly": "รายสัปดาห์", "monthly": "รายเดือน",
"quarterly": "รายไตรมาส", "annual": "รายปี"}.get(freq, freq)
def _period(data: dict, factor_keys: list) -> str:
from app import factors as factors_mod
for k in factor_keys:
f = factors_mod.FACTORS.get(k, {})
vk = f.get("value_key")
if vk and data.get(vk) is not None:
return f.get("name_th", k)
return "--"

View File

@@ -549,14 +549,16 @@ onMounted(loadDashboard)
<table class="source-table">
<thead>
<tr>
<th>อม</th><th>แหล</th><th>วงขอม</th><th>ปเดต</th>
<th>อม</th><th>แหล</th><th>วงขอม</th><th>ความถ</th><th>ปเดตครงตอไป</th><th>ปเดตลาส</th>
</tr>
</thead>
<tbody>
<tr v-for="(s, i) in dashboardSources" :key="i">
<td>{{ s['จาก'] }}</td>
<td>{{ s['จาก'] || s['ขอบเขต'] }}</td>
<td class="source-name">{{ s['แหล่ง'] }}</td>
<td class="muted-cell">{{ s['ข้อมูล'] }}</td>
<td class="muted-cell">{{ s['ความถี่'] || '—' }}</td>
<td class="muted-cell">{{ s['อัปเดตครั้งต่อไป'] ? formatDate(s['อัปเดตครั้งต่อไป']) : '—' }}</td>
<td class="muted-cell">{{ s['dึงมาเมื่อ'] ? formatDate(s['dึงมาเมื่อ']) : '—' }}</td>
</tr>
</tbody>