[verified] Remove tourism-only sections (01 surprise pulse, 02 provenance, 03 signal table, 04 research run); thesis across 3 themes; sources show fetch date

- Removed 'เชื่อถือข้อมูลได้ไหม' (02), 'ตารางสัญญาณ' dup (03), 'หลักฐานพอจะรองรับ study' (04), tourism surprise pulse — superseded by 3-theme panel + sources table
- 05 บันทึกการวิเคราะห์ now lists thesis per theme (tourism/auto/energy) with surprise
- Sources table shows fetched-at date (ข้อ 2)
- All dashboard analysis is real (no mock); automation note: no cron yet (data fetched on-demand + daily cache)
- Verified: build + browser 8 checks pass
This commit is contained in:
Kunthawat Greethong
2026-08-25 20:53:24 +07:00
parent e2f059cb71
commit 4b6ce2c09e
2 changed files with 17 additions and 104 deletions

View File

@@ -518,113 +518,14 @@ onMounted(loadDashboard)
<td>{{ s['จาก'] }}</td>
<td class="source-name">{{ s['แหล่ง'] }}</td>
<td class="muted-cell">{{ s['ข้อมูล'] }}</td>
<td class="muted-cell">{{ s['dึงมาเมื่อ'] }}</td>
<td class="muted-cell">{{ s['dึงมาเมื่อ'] ? formatDate(s['dึงมาเมื่อ']) : '—' }}</td>
</tr>
</tbody>
</table>
</div>
</section>
<section class="hero-grid" id="factors">
<article class="panel pulse-panel">
<div class="panel-header">
<div>
<div class="section-kicker">01 / งทเปลยนไป</div>
<h2>ความตางจากปกต</h2>
</div>
<span class="confidence-tag">{{ positiveObservations }}/{{ observationRows.length }} เปนบวก</span>
</div>
<div class="pulse-lead">
<span class="pulse-number">{{ formatNumber(summary.theme_surprise) }}σ</span>
<span class="pulse-copy"> tourism {{ summary.theme_surprise >= 0 ? 'สูงกว่า' : 'ต่ำกว่า' }}าตามฤดกาล เป input ไมใชคำสงซอขาย.</span>
</div>
<div class="observation-list">
<div v-for="observation in observationRows" :key="observation.metric_key" class="observation-row">
<div class="observation-name">{{ observation.metric_key.replaceAll('_', ' ') }}</div>
<div class="observation-track"><div class="observation-bar" :class="Number(observation.surprise) >= 0 ? 'bar-positive' : 'bar-negative'" :style="{ width: `${Math.min(Math.abs(Number(observation.surprise)) / maxSurprise * 100, 100)}%` }"></div></div>
<div class="observation-value" :class="Number(observation.surprise) >= 0 ? 'positive-text' : 'negative-text'">{{ Number(observation.surprise) >= 0 ? '+' : '' }}{{ formatNumber(observation.surprise) }}σ</div>
</div>
</div>
</article>
<article class="panel lineage-panel" id="lineage">
<div class="panel-header">
<div>
<div class="section-kicker">02 / มาของขอม</div>
<h2>เชอถอขอมลไดไหม?</h2>
</div>
<span class="status-tag" :class="summary.data_health.status === 'high' ? '' : 'warning-tag'">{{ displayLabel(summary.data_health.status) }}</span>
</div>
<div class="lineage-list">
<div class="lineage-item"><span>แหลงขอม</span><strong>{{ summary.data_health.source_id }}</strong></div>
<div class="lineage-item"><span>เผยแพร</span><strong>{{ formatDate(summary.data_health.published_at) }}</strong></div>
<div class="lineage-item"><span>งขอม</span><strong>{{ formatDate(summary.data_health.retrieved_at) }}</strong></div>
<div class="lineage-item"><span>Vintage</span><strong>{{ summary.data_health.vintage_id }}</strong></div>
<div class="lineage-item"><span>ประว</span><strong>{{ summary.data_health.history_points || '—' }} points</strong></div>
<div class="lineage-item"><span>Parser</span><strong>{{ summary.data_health.parser_version || '—' }}</strong></div>
<div class="lineage-item"><span>Replay</span><strong>{{ summary.data_health.replayable ? 'มี' : 'ไม่มี' }}</strong></div>
<div class="lineage-item"><span>Raw hash</span><strong>{{ summary.data_health.raw_payload_hash ? summary.data_health.raw_payload_hash.slice(0, 16) : '—' }}</strong></div>
</div>
<div class="lineage-note">กสญญาณพกทมา, เวลาเผยแพร และ vintage ของม อมลทกแกภายหลงไมเคยเขยนทบอดตแบบเงยบ.</div>
</article>
</section>
<section class="panel signal-panel" id="signals">
<div class="panel-header signal-header">
<div>
<div class="section-kicker">03 / ผลลพธเชงกำหนด</div>
<h2>ตารางสญญาณ</h2>
</div>
<div class="strategy-meta">{{ signalData.strategy_version }} <span>·</span> target weights ไมใชคำสงซอขาย</div>
</div>
<div class="table-wrap">
<table>
<thead><tr><th>นด</th><th></th><th>ศทาง</th><th>Score</th><th>Exposure</th><th>เหตผล</th><th>Target</th><th></th></tr></thead>
<tbody>
<tr v-for="signal in signals" :key="signal.symbol">
<td class="muted-cell">{{ String(signal.rank).padStart(2, '0') }}</td>
<td><strong class="symbol-name">{{ signal.symbol }}</strong><span class="confidence-cell">{{ Math.round(signal.confidence * 100) }}% confidence</span></td>
<td><span class="side-pill" :class="signal.side.toLowerCase()">{{ signal.side }}</span></td>
<td class="score-cell" :class="signal.score >= 0 ? 'positive-text' : 'negative-text'">{{ signal.score >= 0 ? '+' : '' }}{{ formatNumber(signal.score) }}</td>
<td>{{ signal.coefficient >= 0 ? '+' : '' }}{{ formatNumber(signal.coefficient) }}</td>
<td><span class="reason-code" v-for="code in signal.reason_codes" :key="code">{{ code }}</span></td>
<td class="target-cell">{{ signal.target_weight >= 0 ? '+' : '' }}{{ (signal.target_weight * 100).toFixed(1) }}%</td>
<td><button class="row-action" @click="chooseSignal(signal)">Paper entry</button></td>
</tr>
</tbody>
</table>
</div>
</section>
<section class="panel research-panel" id="research-run">
<div class="panel-header">
<div>
<div class="section-kicker">04 / Research run</div>
<h2>หลกฐานพอจะรองร study เชงพรรณนาไหม?</h2>
</div>
<button class="primary-button" :disabled="researchRunning" @click="runResearch">{{ researchRunning ? 'กำลังรัน' : 'รัน exploratory study' }}</button>
</div>
<div v-if="researchRun" class="research-grid">
<div>
<div class="research-status" :class="researchRun.result_scope === 'non_pit_descriptive_only' ? 'status-descriptive' : researchRun.status === 'ready' ? 'status-ready' : 'status-blocked'">{{ researchRun.result_scope === 'non_pit_descriptive_only' ? 'descriptive only' : displayLabel(researchRun.status) }}</div>
<div class="research-reason">{{ researchReason(researchRun) }}</div>
<div class="research-meta">Run {{ researchRun.run_id }} · {{ formatDate(researchRun.generated_at) }} · {{ displayLabel(researchRun.result_scope) }}</div>
</div>
<div class="gate-list">
<div class="gate-row"><span>Independent vintages</span><strong>{{ researchRun.gates.vintages.available_events }} / {{ researchRun.gates.vintages.required_events }} · {{ displayLabel(researchRun.gates.vintages.status) }}</strong></div>
<div class="gate-row"><span>ราคา</span><strong>{{ displayLabel(researchRun.gates.prices.quality) || 'ไม่มี' }} · {{ displayLabel(researchRun.gates.prices.status) }}</strong></div>
</div>
</div>
<div v-if="researchRun?.result?.windows" class="research-results">
<div v-for="(windowResult, windowKey) in researchRun.result.windows" :key="windowKey" class="research-result-row">
<span>+{{ windowKey }} sessions</span>
<strong :class="windowResult.net_return >= 0 ? 'positive-text' : 'negative-text'">{{ (windowResult.net_return * 100).toFixed(2) }}% net</strong>
<span>{{ (windowResult.hit_rate * 100).toFixed(0) }}% hit · {{ windowResult.event_count }} events</span>
</div>
</div>
<div v-if="!researchRun" class="empty-research">ยังไม่มี frozen research run. รันการตรวจเพื่อเก็บ input กับ gate decision ปัจจุบัน.</div>
</section>
<!-- Sections 01-04 (tourism-only surprise, provenance, signal table, frozen research) removed per user: superseded by the 3-theme panel + sources table above. -->
<section class="panel sim-panel" id="simulation">
<div class="panel-header signal-header">
<div>
@@ -697,9 +598,15 @@ onMounted(loadDashboard)
<section class="bottom-grid">
<article class="panel thesis-panel">
<div class="section-kicker">05 / นทกการวเคราะห</div>
<h2>านสญญาณเปนสมมตฐาน.</h2>
<p>อม tourism {{ summary.theme_surprise >= 0 ? 'สูงกว่า' : 'ต่ำกว่า' }}าทคาด เปนตวกำหนดวาหนตวไหนได score บวกหรอลบ ระบบหยดกอนส execution งตองมคน review valuation, price-in, liquidity และ risk.</p>
<div class="thesis-rule"><span></span>Surprise × Exposure × Confidence</div>
<h2>านสญญาณเปนสมมตฐาน (3 ).</h2>
<div class="thesis-list">
<div v-for="t in dashboardThemes" :key="t.id" class="thesis-row">
<strong class="thesis-theme">{{ t.label_th }}</strong>
<span class="thesis-text">{{ t.thesis || '—' }}</span>
<span class="thesis-surprise">{{ t.surprise != null ? formatNumber(t.surprise,2) + 'σ' : '—' }}</span>
</div>
</div>
<div class="thesis-rule"><span></span>ความตาง (surprise) × การเขาถงธ × ความเชอม</div>
</article>
</section>
</template>

View File

@@ -144,6 +144,12 @@ tbody tr:hover { background: rgba(255,255,255,.025); }
.source-name { color: var(--accent); }
.combined-cell { color: var(--mint); font-weight: 600; font-family: 'DM Mono', monospace; }
.thesis-list { display: flex; flex-direction: column; gap: 10px; margin: 12px 0; }
.thesis-row { display: flex; gap: 10px; align-items: baseline; padding-bottom: 8px; border-bottom: 1px solid var(--line-weak, rgba(255,255,255,.05)); }
.thesis-theme { min-width: 130px; color: var(--accent); }
.thesis-text { flex: 1; font-size: 12px; color: var(--text-2, #99a); }
.thesis-surprise { font-family: 'DM Mono', monospace; color: var(--mint); }
/* ---- Simulation panel ---- */
.sim-panel { margin-top: 18px; }
.sim-controls { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 14px; }