403Webshell
Server IP : 104.21.73.108  /  Your IP : 216.73.216.59
Web Server : Apache/2
System : Linux cat167-197.static.lnwhostname.com 5.10.0-20-amd64 #1 SMP Debian 5.10.158-2 (2022-12-13) x86_64
User : paphayomho ( 1042)
PHP Version : 5.6.40
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
MySQL : ON  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/paphayomho/domains/paphayomhospital.go.th/private_html/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/paphayomho/domains/paphayomhospital.go.th/private_html/dashboard_papayom_1.html
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ตัวชี้วัดและผลลัพธ์ 5 ปี 2566-2570 | รพ.ป่าพะยอม</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600;700&family=Noto+Sans+Thai:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
<style>
:root {
  --primary: #0d5c8f;
  --primary-light: #1a7bbf;
  --primary-dark: #093d61;
  --secondary: #1a9e6e;
  --secondary-light: #22c587;
  --accent: #f59e0b;
  --accent2: #e74c3c;
  --bg: #f0f4f8;
  --card: #ffffff;
  --text: #1a2942;
  --text-muted: #5c7a99;
  --border: #d1dde8;
  --good: #16a34a;
  --good-bg: #dcfce7;
  --warn: #ca8a04;
  --warn-bg: #fef9c3;
  --bad: #dc2626;
  --bad-bg: #fee2e2;
  --na: #6b7280;
  --na-bg: #f3f4f6;
  --shadow: 0 2px 16px rgba(13,92,143,0.08);
  --shadow-lg: 0 8px 32px rgba(13,92,143,0.12);
  --radius: 12px;
  --radius-sm: 8px;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  font-family: 'Sarabun', 'Noto Sans Thai', sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 15px;
  line-height: 1.6;
}

/* ── HERO ── */
.hero {
  background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary) 50%, var(--primary-light) 100%);
  color: #fff;
  padding: 56px 32px 48px;
  text-align: center;
  position: relative;
  overflow: hidden;
}
.hero::before {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at 80% 20%, rgba(26,155,110,0.2) 0%, transparent 60%),
              radial-gradient(ellipse at 20% 80%, rgba(245,158,11,0.1) 0%, transparent 60%);
}
.hero-badge {
  display: inline-block;
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.3);
  border-radius: 20px;
  padding: 5px 18px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.5px;
  margin-bottom: 16px;
  position: relative;
}
.hero h1 {
  font-size: clamp(22px, 4vw, 38px);
  font-weight: 700;
  margin-bottom: 10px;
  position: relative;
}
.hero .subtitle {
  font-size: 15px;
  opacity: 0.85;
  margin-bottom: 20px;
  position: relative;
}
.hero .description {
  font-size: 14px;
  opacity: 0.75;
  max-width: 700px;
  margin: 0 auto;
  position: relative;
  line-height: 1.8;
}
.hero-dots {
  display: flex; gap: 8px; justify-content: center; margin-top: 24px; position: relative;
}
.hero-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: rgba(255,255,255,0.4);
}
.hero-dot.active { background: var(--accent); width: 28px; border-radius: 5px; }

/* ── NAV ── */
.sticky-nav {
  position: sticky; top: 0; z-index: 100;
  background: var(--primary-dark);
  border-bottom: 2px solid var(--primary-light);
  display: flex; gap: 0; overflow-x: auto;
  scrollbar-width: none;
}
.sticky-nav::-webkit-scrollbar { display: none; }
.nav-btn {
  padding: 13px 20px;
  color: rgba(255,255,255,0.7);
  font-size: 13px; font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  border: none; background: none;
  font-family: inherit;
  transition: all 0.2s;
  border-bottom: 3px solid transparent;
}
.nav-btn:hover { color: #fff; background: rgba(255,255,255,0.08); }
.nav-btn.active { color: var(--accent); border-bottom-color: var(--accent); }

/* ── CONTAINER ── */
.container { max-width: 1280px; margin: 0 auto; padding: 0 24px; }
.section { padding: 40px 0; }
.section-title {
  font-size: 20px; font-weight: 700;
  color: var(--primary-dark);
  margin-bottom: 24px;
  display: flex; align-items: center; gap: 10px;
}
.section-title::after {
  content: ''; flex: 1; height: 2px;
  background: linear-gradient(to right, var(--border), transparent);
}

/* ── SUMMARY CARDS ── */
.summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
  margin-bottom: 32px;
}
.summary-card {
  background: var(--card);
  border-radius: var(--radius);
  padding: 22px 20px;
  box-shadow: var(--shadow);
  border-top: 4px solid var(--primary);
  text-align: center;
  transition: transform 0.2s, box-shadow 0.2s;
}
.summary-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.summary-card.good { border-top-color: var(--good); }
.summary-card.warn { border-top-color: var(--warn); }
.summary-card.bad { border-top-color: var(--bad); }
.summary-card.accent { border-top-color: var(--accent); }
.summary-num {
  font-size: 40px; font-weight: 700; color: var(--primary);
  line-height: 1;
}
.summary-card.good .summary-num { color: var(--good); }
.summary-card.warn .summary-num { color: var(--warn); }
.summary-card.bad .summary-num { color: var(--bad); }
.summary-card.accent .summary-num { color: var(--accent); }
.summary-label { font-size: 13px; color: var(--text-muted); margin-top: 6px; }

/* ── PILLAR CARDS ── */
.pillar-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 20px;
}
.pillar-card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  transition: transform 0.2s, box-shadow 0.2s;
}
.pillar-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
.pillar-header {
  padding: 18px 20px 14px;
  display: flex; align-items: flex-start; gap: 14px;
}
.pillar-icon {
  width: 42px; height: 42px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; flex-shrink: 0;
  background: var(--primary);
}
.pillar-info { flex: 1; }
.pillar-code { font-size: 11px; font-weight: 700; letter-spacing: 1px; color: var(--text-muted); }
.pillar-name { font-size: 14px; font-weight: 600; color: var(--text); margin-top: 2px; line-height: 1.4; }
.pillar-status {
  padding: 3px 10px; border-radius: 12px;
  font-size: 12px; font-weight: 600; flex-shrink: 0;
}
.status-good { background: var(--good-bg); color: var(--good); }
.status-warn { background: var(--warn-bg); color: var(--warn); }
.status-bad { background: var(--bad-bg); color: var(--bad); }
.status-na { background: var(--na-bg); color: var(--na); }
.pillar-body { padding: 0 20px 18px; }
.pillar-stats {
  display: flex; gap: 16px; margin-bottom: 14px;
  font-size: 13px;
}
.pillar-stat { text-align: center; }
.pillar-stat-num { font-size: 22px; font-weight: 700; color: var(--primary); }
.pillar-stat-lbl { color: var(--text-muted); font-size: 11px; }
.progress-bar-wrap { margin-bottom: 14px; }
.progress-bar-bg {
  height: 8px; border-radius: 4px;
  background: var(--border);
  overflow: hidden;
}
.progress-bar-fill {
  height: 100%; border-radius: 4px;
  background: linear-gradient(to right, var(--secondary), var(--primary-light));
  transition: width 1s ease;
}
.progress-label {
  display: flex; justify-content: space-between;
  font-size: 12px; color: var(--text-muted); margin-top: 4px;
}
.pillar-highlights { list-style: none; }
.pillar-highlights li {
  font-size: 13px; padding: 5px 0;
  border-bottom: 1px solid var(--border);
  display: flex; gap: 6px; align-items: flex-start;
  color: var(--text);
}
.pillar-highlights li:last-child { border-bottom: none; }
.hl-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--secondary); flex-shrink: 0; margin-top: 6px;
}

/* ── FILTERS ── */
.filter-bar {
  background: var(--card);
  border-radius: var(--radius);
  padding: 20px;
  box-shadow: var(--shadow);
  margin-bottom: 20px;
  display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end;
}
.filter-group { display: flex; flex-direction: column; gap: 5px; }
.filter-label { font-size: 12px; font-weight: 600; color: var(--text-muted); }
.filter-select, .filter-input {
  padding: 8px 12px;
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: inherit; font-size: 13px;
  color: var(--text);
  background: var(--bg);
  outline: none;
  transition: border-color 0.2s;
}
.filter-select:focus, .filter-input:focus { border-color: var(--primary); }
.filter-input { min-width: 220px; }
.filter-reset {
  padding: 8px 16px;
  background: var(--primary);
  color: #fff;
  border: none; border-radius: var(--radius-sm);
  font-family: inherit; font-size: 13px; font-weight: 500;
  cursor: pointer;
  transition: background 0.2s;
}
.filter-reset:hover { background: var(--primary-dark); }
.filter-count {
  font-size: 13px; color: var(--text-muted);
  align-self: center;
  margin-left: auto;
}

/* ── TABLE ── */
.table-wrap {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: auto;
}
table {
  width: 100%; border-collapse: collapse;
  font-size: 13px;
}
thead th {
  background: var(--primary-dark);
  color: #fff;
  padding: 11px 12px;
  text-align: left;
  white-space: nowrap;
  font-weight: 600;
  font-size: 12px;
  position: sticky; top: 0;
  cursor: pointer;
  user-select: none;
}
thead th:hover { background: var(--primary); }
thead th .sort-icon { margin-left: 4px; opacity: 0.5; }
tbody tr { transition: background 0.15s; }
tbody tr:nth-child(even) { background: #f8fbff; }
tbody tr:hover { background: #e8f4ff; }
td { padding: 9px 12px; vertical-align: top; border-bottom: 1px solid var(--border); }
.td-kpi { max-width: 200px; font-weight: 500; }
.td-okr { max-width: 280px; font-size: 12px; color: var(--text-muted); }
.td-year { text-align: center; }
.badge-level {
  display: inline-block; padding: 2px 8px;
  border-radius: 10px; font-size: 11px; font-weight: 700;
}
.badge-R { background: #dbeafe; color: #1d4ed8; }
.badge-P { background: #ede9fe; color: #6d28d9; }
.badge-U { background: #fee2e2; color: #991b1b; }
.badge-I { background: #dcfce7; color: #166534; }
.badge-status {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px; border-radius: 10px;
  font-size: 11px; font-weight: 600; white-space: nowrap;
}
.badge-บรรลุ { background: var(--good-bg); color: var(--good); }
.badge-ใกล้บรรลุ { background: var(--warn-bg); color: var(--warn); }
.badge-ไม่บรรลุ { background: var(--bad-bg); color: var(--bad); }
.badge-ไม่มีข้อมูล { background: var(--na-bg); color: var(--na); }
.trend-arrow { font-size: 16px; }
.gap-val { font-size: 12px; font-weight: 600; }
.gap-pos { color: var(--good); }
.gap-neg { color: var(--bad); }
.gap-na { color: var(--na); }

/* ── CHARTS ── */
.charts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
  gap: 20px;
}
.chart-card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 22px;
}
.chart-title {
  font-size: 15px; font-weight: 600; color: var(--primary-dark);
  margin-bottom: 16px;
}
.chart-container { position: relative; height: 280px; }
.heatmap-wrap { overflow-x: auto; }
.heatmap-table {
  width: 100%; border-collapse: separate; border-spacing: 3px;
  font-size: 12px;
}
.heatmap-table th {
  padding: 8px 12px; text-align: center;
  background: var(--primary-dark); color: #fff;
  border-radius: 6px; font-size: 11px;
}
.heatmap-table td {
  padding: 10px 8px; text-align: center;
  border-radius: 6px; font-weight: 600; font-size: 12px;
  cursor: default;
}
.hm-good { background: #bbf7d0; color: #15803d; }
.hm-warn { background: #fef08a; color: #92400e; }
.hm-bad { background: #fecaca; color: #991b1b; }
.hm-na { background: #f3f4f6; color: #9ca3af; }
.hm-mixed { background: #ddd6fe; color: #5b21b6; }
.hm-row-label { font-weight: 600; color: var(--text); background: #f8fbff !important; text-align: left; border-radius: 6px; padding: 10px 12px; }

/* ── KPI SELECTOR ── */
.kpi-selector {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-bottom: 14px;
}
.kpi-chip {
  padding: 5px 12px; border-radius: 20px;
  border: 1.5px solid var(--border);
  font-size: 12px; cursor: pointer;
  background: #fff; color: var(--text-muted);
  font-family: inherit;
  transition: all 0.2s; white-space: nowrap;
}
.kpi-chip.active {
  background: var(--primary); border-color: var(--primary);
  color: #fff;
}

/* ── HIGHLIGHT SECTION ── */
.highlight-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 20px;
}
.highlight-card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 22px;
}
.highlight-card-title {
  font-size: 15px; font-weight: 700;
  margin-bottom: 16px;
  display: flex; align-items: center; gap: 8px;
}
.highlight-icon { font-size: 20px; }
.highlight-list { list-style: none; }
.highlight-list li {
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  display: flex; gap: 8px; align-items: flex-start;
  line-height: 1.5;
}
.highlight-list li:last-child { border-bottom: none; }

/* ── RECOMMENDATION ── */
.rec-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 14px;
}
.rec-card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px;
  border-left: 4px solid var(--primary);
  display: flex; gap: 14px;
}
.rec-num {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--primary); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 700; flex-shrink: 0;
}
.rec-content { flex: 1; }
.rec-title { font-size: 14px; font-weight: 600; color: var(--primary-dark); margin-bottom: 5px; }
.rec-detail { font-size: 13px; color: var(--text-muted); line-height: 1.6; }

/* ── DISCLAIMER ── */
.disclaimer {
  background: #fffbeb;
  border: 1px solid #fcd34d;
  border-radius: var(--radius-sm);
  padding: 12px 16px;
  font-size: 12px;
  color: #92400e;
  margin: 24px 0;
  display: flex; gap: 8px; align-items: flex-start;
}

/* ── FOOTER ── */
.footer {
  background: var(--primary-dark);
  color: rgba(255,255,255,0.7);
  text-align: center;
  padding: 24px;
  font-size: 13px;
}

/* ── PRINT ── */
@media print {
  .sticky-nav, .filter-bar, .filter-reset { display: none !important; }
  .section { page-break-inside: avoid; }
  body { background: #fff; font-size: 12px; }
  .chart-container { height: 220px; }
  .hero { padding: 24px; }
  .hero h1 { font-size: 22px; }
}
@media (max-width: 640px) {
  .summary-grid { grid-template-columns: repeat(2, 1fr); }
  .pillar-grid { grid-template-columns: 1fr; }
  .charts-grid { grid-template-columns: 1fr; }
  .filter-bar { flex-direction: column; }
}
</style>
</head>
<body>

<!-- HERO -->
<section class="hero">
  <div class="hero-badge">โรงพยาบาลป่าพะยอม · จ.พัทลุง | HCODE 11422</div>
  <h1>ตัวชี้วัดและผลลัพธ์ 5 ปี 2566–2570</h1>
  <p class="subtitle">Strategic KPI & Quality Outcome Roadmap | แผนยุทธศาสตร์ รพ.ป่าพะยอม</p>
  <p class="description">
    รายงานการติดตามเป้าหมายระยะ 5 ปี เชื่อมโยงยุทธศาสตร์ P1–P7<br>
    ครอบคลุมผลลัพธ์บริการ คุณภาพ ความปลอดภัย การเงินการคลัง และการพัฒนาบุคลากร<br>
    จัดทำเพื่อสื่อสารต่อ สรพ. และผู้บริหาร โดยอ้างอิงข้อมูลจริงจากไฟล์ตัวชี้วัด ปีงบประมาณ 2566–2569
  </p>
  <div class="hero-dots">
    <div class="hero-dot"></div><div class="hero-dot active"></div><div class="hero-dot"></div>
  </div>
</section>

<!-- STICKY NAV -->
<nav class="sticky-nav" id="stickyNav">
  <button class="nav-btn active" onclick="scrollToSection('summary')">📊 ภาพรวม</button>
  <button class="nav-btn" onclick="scrollToSection('pillars')">🏛️ ยุทธศาสตร์ P1–P7</button>
  <button class="nav-btn" onclick="scrollToSection('table')">📋 ตาราง KPI</button>
  <button class="nav-btn" onclick="scrollToSection('charts')">📈 กราฟ</button>
  <button class="nav-btn" onclick="scrollToSection('highlights')">💡 ประเด็น สรพ.</button>
  <button class="nav-btn" onclick="scrollToSection('recs')">✅ ข้อเสนอแนะ</button>
</nav>

<div class="container">

<!-- DISCLAIMER -->
<div class="disclaimer" style="margin-top:20px">
  ⚠️ <span><strong>หมายเหตุ:</strong> ข้อมูลอ้างอิงจากไฟล์ตัวชี้วัดที่แนบ และควรตรวจสอบความครบถ้วนก่อนใช้เป็นเอกสารทางการ ข้อมูลปี 2569 เป็นผลดำเนินงานช่วง ต.ค.–มี.ค. และข้อมูลปี 2570 ยังไม่มีผลการดำเนินงาน</span>
</div>

<!-- ── SECTION 1: SUMMARY ── -->
<section class="section" id="summary">
  <h2 class="section-title">📊 Executive Summary – ภาพรวมตัวชี้วัด</h2>
  <div class="summary-grid" id="summaryGrid"></div>
</section>

<!-- ── SECTION 2: PILLARS ── -->
<section class="section" id="pillars">
  <h2 class="section-title">🏛️ Strategic Pillar Dashboard – ผลลัพธ์รายยุทธศาสตร์</h2>
  <div class="pillar-grid" id="pillarGrid"></div>
</section>

<!-- ── SECTION 3: TABLE ── -->
<section class="section" id="table">
  <h2 class="section-title">📋 ตาราง KPI แบบ Interactive</h2>
  <div class="filter-bar">
    <div class="filter-group">
      <label class="filter-label">ยุทธศาสตร์</label>
      <select class="filter-select" id="filterPillar" onchange="applyFilters()">
        <option value="">ทั้งหมด</option>
        <option value="P1">P1 – ลดป่วยรายใหม่</option>
        <option value="P2">P2 – ลดป่วยตาย</option>
        <option value="P3">P3 – IT มาตรฐาน</option>
        <option value="P4">P4 – คุณภาพบริการ</option>
        <option value="P5">P5 – ภาคีเครือข่าย</option>
        <option value="P6">P6 – การเงิน</option>
        <option value="P7">P7 – บุคลากร</option>
      </select>
    </div>
    <div class="filter-group">
      <label class="filter-label">ระดับตัวชี้วัด</label>
      <select class="filter-select" id="filterLevel" onchange="applyFilters()">
        <option value="">ทั้งหมด</option>
        <option value="R">R</option>
        <option value="P">P</option>
        <option value="U">U</option>
        <option value="I">I</option>
      </select>
    </div>
    <div class="filter-group">
      <label class="filter-label">สถานะปี 2569</label>
      <select class="filter-select" id="filterStatus" onchange="applyFilters()">
        <option value="">ทั้งหมด</option>
        <option value="บรรลุ">✅ บรรลุ</option>
        <option value="ใกล้บรรลุ">🟡 ใกล้บรรลุ</option>
        <option value="ไม่บรรลุ">❌ ไม่บรรลุ</option>
        <option value="ไม่มีข้อมูล">➖ ไม่มีข้อมูล</option>
      </select>
    </div>
    <div class="filter-group">
      <label class="filter-label">ค้นหา KPI / OKRs</label>
      <input class="filter-input" id="filterSearch" placeholder="พิมพ์คำค้นหา..." oninput="applyFilters()">
    </div>
    <button class="filter-reset" onclick="resetFilters()">รีเซ็ต</button>
    <span class="filter-count" id="filterCount"></span>
  </div>
  <div class="table-wrap">
    <table id="kpiTable">
      <thead>
        <tr>
          <th onclick="sortTable('pillar')">ยุทธศาสตร์ <span class="sort-icon">↕</span></th>
          <th onclick="sortTable('level')">ระดับ <span class="sort-icon">↕</span></th>
          <th onclick="sortTable('kpi')">KPI <span class="sort-icon">↕</span></th>
          <th>OKRs/KRA</th>
          <th class="td-year">เป้า 66</th>
          <th class="td-year">เป้า 67</th>
          <th class="td-year">เป้า 68</th>
          <th class="td-year">เป้า 69</th>
          <th class="td-year">ผล 66</th>
          <th class="td-year">ผล 67</th>
          <th class="td-year">ผล 68</th>
          <th class="td-year">ผล 69</th>
          <th onclick="sortTable('status')">สถานะ 69 <span class="sort-icon">↕</span></th>
          <th>Gap</th>
          <th>Trend</th>
          <th>ข้อสังเกต</th>
        </tr>
      </thead>
      <tbody id="tableBody"></tbody>
    </table>
  </div>
</section>

<!-- ── SECTION 4: CHARTS ── -->
<section class="section" id="charts">
  <h2 class="section-title">📈 Trend Visualization – การวิเคราะห์แนวโน้ม</h2>
  <div class="charts-grid">
    <div class="chart-card">
      <div class="chart-title">สถานะตัวชี้วัดปี 2569 แยกตามยุทธศาสตร์</div>
      <div class="chart-container"><canvas id="chartStatus"></canvas></div>
    </div>
    <div class="chart-card" style="grid-column: span 1;">
      <div class="chart-title">เปรียบเทียบ Target vs Actual – เลือก KPI</div>
      <div class="kpi-selector" id="kpiSelector"></div>
      <div class="chart-container"><canvas id="chartTrend"></canvas></div>
    </div>
    <div class="chart-card" style="grid-column: 1 / -1;">
      <div class="chart-title">Heatmap ผลลัพธ์ P1–P7 × ปี 2566–2569 (สีแสดงสัดส่วนการบรรลุเป้าหมาย)</div>
      <div class="heatmap-wrap" id="heatmapWrap"></div>
    </div>
  </div>
</section>

<!-- ── SECTION 5: HIGHLIGHTS ── -->
<section class="section" id="highlights">
  <h2 class="section-title">💡 ประเด็นสื่อสารต่อ สรพ.</h2>
  <div class="highlight-grid">
    <div class="highlight-card">
      <div class="highlight-card-title"><span class="highlight-icon">🌟</span> จุดแข็ง – Strong Points</div>
      <ul class="highlight-list" id="hlStrengths"></ul>
    </div>
    <div class="highlight-card">
      <div class="highlight-card-title"><span class="highlight-icon">🔧</span> โอกาสพัฒนา – Improvement Areas</div>
      <ul class="highlight-list" id="hlOpportunities"></ul>
    </div>
    <div class="highlight-card" style="grid-column: 1 / -1;">
      <div class="highlight-card-title"><span class="highlight-icon">🔗</span> ความเชื่อมโยงเชิงระบบ – System Linkage</div>
      <ul class="highlight-list" id="hlSystemic"></ul>
    </div>
  </div>
</section>

<!-- ── SECTION 6: RECOMMENDATIONS ── -->
<section class="section" id="recs">
  <h2 class="section-title">✅ ข้อเสนอแนะเชิงบริหาร</h2>
  <div class="rec-list" id="recList"></div>
</section>

<div class="disclaimer">
  📄 <span>รายงานนี้จัดทำจากไฟล์ตัวชี้วัดและค่าเป้าหมายท้าทายความสำเร็จ (Roadmap) โรงพยาบาลป่าพะยอม ปีงบประมาณ 2566–2570 อัปเดตผลปี 2569 | ข้อมูลที่ไม่มีในไฟล์แสดงเป็น "ไม่มีข้อมูล" และผลปี 2569 เป็นข้อมูลช่วง ต.ค.–มี.ค. | ควรตรวจสอบและรับรองโดยผู้รับผิดชอบก่อนใช้เป็นเอกสารทางการ</span>
</div>
</div><!-- /container -->

<footer class="footer">
  โรงพยาบาลป่าพะยอม | อำเภอป่าพะยอม จังหวัดพัทลุง | โรงพยาบาลชุมชนขนาด 45 เตียง | HCODE 11422<br>
  Strategic KPI Dashboard 2566–2570 | จัดทำด้วย Data Storytelling & HA Quality Framework
</footer>

<script>
// ════════════════════════════════════════════════════════════════
// DATA EMBEDDED FROM EXCEL (ข้อมูลจากไฟล์ตัวชี้วัดที่แนบ)
// โครงสร้าง: pillar, kpiGroup, level (R/P/U/I), kpi, okr,
//            target:{66,67,68,69,70}, actual:{66,67,68,69,70}
// ════════════════════════════════════════════════════════════════
const RAW_DATA = [
  {
    "pillar": "P1",
    "kpiGroup": "1. อัตราการเจ็บป่วยรายใหม่ DM",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ DM",
    "okr": "ร้อยละการตรวจติดตามยืนยันวินิจฉัยกลุ่มสงสัยป่วยโรคเบาหวาน",
    "target": {
      "66": "≥80",
      "67": "≥80",
      "68": "≥85",
      "69": "≥90",
      "70": "≥95"
    },
    "actual": {
      "66": 72.8,
      "67": 78.16,
      "68": 80.77,
      "69": 87.5,
      "70": null
    },
    "direction": ">",
    "owner": "สาลี"
  },
  {
    "pillar": "P1",
    "kpiGroup": "1. อัตราการเจ็บป่วยรายใหม่ DM",
    "level": "R",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ DM",
    "okr": "อัตราผู้ป่วยเบาหวานรายใหม่กลุ่มในเสี่ยง <2%",
    "target": {
      "66": 1.9,
      "67": 1.8,
      "68": 1.7,
      "69": 1.6,
      "70": 1.5
    },
    "actual": {
      "66": 1.16,
      "67": 2.72,
      "68": 1.86,
      "69": 1.38,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P1",
    "kpiGroup": "2. อัตราการเจ็บป่วยรายใหม่ HT",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ HT",
    "okr": "ร้อยละการตรวจติดตามยืนยันวินิจฉัยกลุ่มสงสัยป่วยความดันโลหิตสูง",
    "target": {
      "66": "≥80",
      "67": "≥80",
      "68": "≥85",
      "69": "≥90",
      "70": "≥95"
    },
    "actual": {
      "66": 94.64,
      "67": 88.58,
      "68": 95.6,
      "69": 92.05,
      "70": null
    },
    "direction": ">",
    "owner": "สาลี"
  },
  {
    "pillar": "P1",
    "kpiGroup": "2. อัตราการเจ็บป่วยรายใหม่ HT",
    "level": "R",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ HT",
    "okr": "อัตราผู้ป่วยความดันรายใหม่ในกลุ่มเสี่ยง <2%",
    "target": {
      "66": 3.5,
      "67": 3,
      "68": 2.5,
      "69": 2,
      "70": 1.5
    },
    "actual": {
      "66": 4.66,
      "67": 7.34,
      "68": 2.24,
      "69": 2.87,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P1",
    "kpiGroup": "3.อัตราการเจ็บป่วยรายใหม่ Stroke",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ Stroke",
    "okr": "อัตราการเจ็บป่วยรายใหม่ stroke ในผู้ป่วยกลุ่มโรค HT DM<1%",
    "target": {
      "66": 1.5,
      "67": 1.4,
      "68": 1.3,
      "69": 1.2,
      "70": 1
    },
    "actual": {
      "66": 1.49,
      "67": 8.13,
      "68": 3.31,
      "69": 0.39,
      "70": null
    },
    "direction": "<",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P1",
    "kpiGroup": "4. อัตราการเจ็บป่วยรายใหม่COPD/Asthma",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่COPD/Asthma",
    "okr": "อัตราการป่วยรายใหม่ในผู้ป่วย Asthma < 5 : แสนประชากร",
    "target": {
      "66": 5,
      "67": 5,
      "68": 5,
      "69": 5,
      "70": 5
    },
    "actual": {
      "66": 28.05,
      "67": 8.45,
      "68": 2.38,
      "69": 2.84,
      "70": null
    },
    "direction": "<",
    "owner": "กมวรรณ"
  },
  {
    "pillar": "P1",
    "kpiGroup": "4. อัตราการเจ็บป่วยรายใหม่COPD/Asthma",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่COPD/Asthma",
    "okr": "อัตราการป่วยรายใหม่ในผู้ป่วย COPD < 5 : แสนประชากร",
    "target": {
      "66": 5,
      "67": 5,
      "68": 5,
      "69": 5,
      "70": 5
    },
    "actual": {
      "66": 2.8,
      "67": 0,
      "68": 2.82,
      "69": 0,
      "70": null
    },
    "direction": "<",
    "owner": "กมวรรณ"
  },
  {
    "pillar": "P1",
    "kpiGroup": "5. อัตราการเจ็บป่วยรายใหม่ ACS",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ ACS",
    "okr": "อัตราการเจ็บป่วยรายใหม่ ACS ในผู้ป่วยกลุ่มเสี่ยง HT, DM,DLP <0.2%",
    "target": {
      "66": 0.5,
      "67": 0.4,
      "68": 0.3,
      "69": 0.2,
      "70": 0.2
    },
    "actual": {
      "66": 0.11,
      "67": 1.44,
      "68": 0.36,
      "69": 0.13,
      "70": null
    },
    "direction": "<",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P1",
    "kpiGroup": "6.อัตราการเจ็บป่วยรายใหม่ Head injury",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ Head injury",
    "okr": "ร้อยละความสำเร็จมาตรการขับขี่ปลอดภัย (สวมหมวกนิรภัย) 100%",
    "target": {
      "66": 60,
      "67": 70,
      "68": 80,
      "69": 90,
      "70": 100
    },
    "actual": {
      "66": 50,
      "67": 90,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P1",
    "kpiGroup": "6.อัตราการเจ็บป่วยรายใหม่ Head injury",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ Head injury",
    "okr": "ร้อยละความสำเร็จมาตรการป้องกันจุดเสี่ยง 100%",
    "target": {
      "66": 50,
      "67": 60,
      "68": 70,
      "69": 80,
      "70": 100
    },
    "actual": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P1",
    "kpiGroup": "7.อัตราการเจ็บป่วยรายใหม่ DHF",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ DHF",
    "okr": "ค่าลูกน้ำยุงลายHI<5,CI<5 (ชุมชน)สถานพยาบาล CI=0",
    "target": {
      "66": "<10/0",
      "67": "<10/0",
      "68": "<10/0",
      "69": "<10/0",
      "70": "<10/0"
    },
    "actual": {
      "66": 0.874,
      "67": 0.912,
      "68": 0.8083,
      "69": 0,
      "70": null
    },
    "direction": "<",
    "owner": "สาลี"
  },
  {
    "pillar": "P1",
    "kpiGroup": "7.อัตราการเจ็บป่วยรายใหม่ DHF",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ DHF",
    "okr": "อัตราป่วยด้วยโรคไข้เลือดออกต่อแสนประชากร(ตำบลป่าพะยอม)",
    "target": {
      "66": 50,
      "67": 50,
      "68": 50,
      "69": 50,
      "70": 50
    },
    "actual": {
      "66": 0,
      "67": 1.338,
      "68": 1.3216,
      "69": 33.18,
      "70": null
    },
    "direction": ">",
    "owner": "สาลี"
  },
  {
    "pillar": "P1",
    "kpiGroup": "8. อัตราการเข้ารับบริการผู้ป่วยยาเสพติด",
    "level": "I",
    "kpi": "อัตราการเข้ารับบริการผู้ป่วยยาเสพติด",
    "okr": "จำนวนผู้ป่วยยาเสพติดเข้ารับการบำบัด 1 ตำบล/1คน/เดือน",
    "target": {
      "66": null,
      "67": null,
      "68": 24,
      "69": 36,
      "70": 48
    },
    "actual": {
      "66": null,
      "67": null,
      "68": null,
      "69": null,
      "70": null
    },
    "direction": ">",
    "owner": "มนสิชา"
  },
  {
    "pillar": "P1",
    "kpiGroup": "9.อัตราการเจ็บป่วยรายใหม่ TB",
    "level": "I",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ TB",
    "okr": "อัตราการเกิดวัณโรครายใหม่จากลุ่มสัมผัสผู้ป่วย",
    "target": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": 0
    },
    "actual": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": null
    },
    "direction": "<",
    "owner": "เสาวนีย์"
  },
  {
    "pillar": "P1",
    "kpiGroup": "9.อัตราการเจ็บป่วยรายใหม่ TB",
    "level": "I",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ TB",
    "okr": "อัตราสำเร็จของการรักษาวัณโรคปอดรายใหม่",
    "target": {
      "66": "≥85%",
      "67": "≥85%",
      "68": "≥85%",
      "69": "≥85%",
      "70": "≥85%"
    },
    "actual": {
      "66": 100,
      "67": 96.58,
      "68": 91.03,
      "69": 77.78,
      "70": null
    },
    "direction": ">",
    "owner": "เสาวณีย์"
  },
  {
    "pillar": "P1",
    "kpiGroup": "10. อัตราการเจ็บป่วยรายใหม่ HIV",
    "level": "I",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ HIV",
    "okr": "ร้อยละของผู้เข้ารับบริการที่ได้รับคำแนะนำให้ใช้ PrEP/PEP ได้เริ่มใช้ PrEP/PEP",
    "target": {
      "66": 55,
      "67": 65,
      "68": 75,
      "69": 85,
      "70": 95
    },
    "actual": {
      "66": 99.84,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "สุวิทย์"
  },
  {
    "pillar": "P1",
    "kpiGroup": "10. อัตราการเจ็บป่วยรายใหม่ HIV",
    "level": "I",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ HIV",
    "okr": "ร้อยละของผู้เข้ารับบริการเริ่มใช้ PrEP ที่ใช้ต่อเนื่อง ครบ 3 เดือน",
    "target": {
      "66": 80,
      "67": 85,
      "68": 90,
      "69": 95,
      "70": 100
    },
    "actual": {
      "66": 99.84,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "สุวิทย์"
  },
  {
    "pillar": "P1",
    "kpiGroup": "10. อัตราการเจ็บป่วยรายใหม่ HIV",
    "level": "I",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ HIV",
    "okr": "ร้อยละของผู้เข้ารับบริการเริ่มใช้ PrEP/PEP ใช้ต่อเนื่อง ครบ 1 เดือน",
    "target": {
      "66": 80,
      "67": 85,
      "68": 90,
      "69": 95,
      "70": 100
    },
    "actual": {
      "66": 99.84,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "สุวิทย์"
  },
  {
    "pillar": "P1",
    "kpiGroup": "11.ประสิทธิภาพการบริหารจัดการความเสี่ยงด้านคลินิก",
    "level": "P",
    "kpi": "ประสิทธิภาพการบริหารจัดการความเสี่ยงด้านคลินิก",
    "okr": "ร้อยละการได้รับ Antibiotic ภายใน 1 ชม. ผู้ป่วย Sepsis(≥90%)",
    "target": {
      "66": 90,
      "67": 90,
      "68": 90,
      "69": 90,
      "70": 90
    },
    "actual": {
      "66": 68.85,
      "67": 80.58,
      "68": 90.41,
      "69": 88.89,
      "70": null
    },
    "direction": ">",
    "owner": "อรวรรณ"
  },
  {
    "pillar": "P1",
    "kpiGroup": "11.ประสิทธิภาพการบริหารจัดการความเสี่ยงด้านคลินิก",
    "level": "R",
    "kpi": "ประสิทธิภาพการบริหารจัดการความเสี่ยงด้านคลินิก",
    "okr": "อัตราการติดเชื้อในโรงพยาบาล (<0.5 : 1000 วันนอน)",
    "target": {
      "66": 0.5,
      "67": 0.5,
      "68": 0.5,
      "69": 0.5,
      "70": 0.4
    },
    "actual": {
      "66": 0.56,
      "67": 1.5,
      "68": 0.26,
      "69": 0.22,
      "70": null
    },
    "direction": "<",
    "owner": "อรวรรณ"
  },
  {
    "pillar": "P1",
    "kpiGroup": "11.ประสิทธิภาพการบริหารจัดการความเสี่ยงด้านคลินิก",
    "level": "P",
    "kpi": "ประสิทธิภาพการบริหารจัดการความเสี่ยงด้านคลินิก",
    "okr": "อุบัติการณ์ความเสี่ยงระดับ E ขึ้นไปได้รับการวางมาตรการ(RCA)",
    "target": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "สาลี"
  },
  {
    "pillar": "P1",
    "kpiGroup": "12.Dental carie",
    "level": "U",
    "kpi": "Dental carie",
    "okr": "ร้อยละของเด็กอายุ 0-2 ปีได้รับการแคลือบ/ทาฟลูออไรด์เฉพาะที่",
    "target": {
      "66": 55,
      "67": 55,
      "68": 55,
      "69": 55,
      "70": 55
    },
    "actual": {
      "66": null,
      "67": null,
      "68": null,
      "69": null,
      "70": null
    },
    "direction": ">",
    "owner": "วสัน"
  },
  {
    "pillar": "P1",
    "kpiGroup": "12.Dental carie",
    "level": "U",
    "kpi": "Dental carie",
    "okr": "ร้อยละผู้สูงอายุได้รับดารคัดกรองรอยโรคก่อระเร็ง PMD",
    "target": {
      "66": null,
      "67": 65,
      "68": 70,
      "69": 75,
      "70": 80
    },
    "actual": {
      "66": 31.44,
      "67": 59.2,
      "68": 83.55,
      "69": 61.08,
      "70": null
    },
    "direction": ">",
    "owner": "วสัน"
  },
  {
    "pillar": "P1",
    "kpiGroup": "13.อัตราการเจ็บป่วยรายใหม่ ผู้ป่วยเสพติดเข้าถึงบริการและอยู่ในระบบ (ร้อยละ 70)",
    "level": "U",
    "kpi": "อัตราการเจ็บป่วยรายใหม่ ผู้ป่วยเสพติดเข้าถึงบริการและอยู่ในระบบ (ร้อยละ 70)",
    "okr": "ร้อยละของผู้ป่วยยาเสพติดเข้าสู่กระบวนการรักษาและได้รับการดูแลต่อเนื่องจนถึงการติดตาม",
    "target": {
      "66": 55,
      "67": 60,
      "68": 65,
      "69": 70,
      "70": 75
    },
    "actual": {
      "66": 78.47,
      "67": 66.67,
      "68": 79,
      "69": 90,
      "70": null
    },
    "direction": ">",
    "owner": "มนสิชา"
  },
  {
    "pillar": "P2",
    "kpiGroup": "14. อัตราการป่วยตาย DM",
    "level": "U",
    "kpi": "อัตราการป่วยตาย DM",
    "okr": "ร้อยละผู้ป่วยเบาหวานที่ควบคุมระดับน้ำตาลได้ดี >40%",
    "target": {
      "66": 40,
      "67": 41,
      "68": 42,
      "69": 43,
      "70": 44
    },
    "actual": {
      "66": 28.24,
      "67": 35.36,
      "68": 41.24,
      "69": 36.96,
      "70": null
    },
    "direction": ">",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P2",
    "kpiGroup": "14. อัตราการป่วยตาย DM",
    "level": "U",
    "kpi": "อัตราการป่วยตาย DM",
    "okr": "อัตราการขาดนัดในผู้ป่วยเบาหวาน<5%",
    "target": {
      "66": 50,
      "67": 55,
      "68": 60,
      "69": 65,
      "70": 70
    },
    "actual": {
      "66": 1.82,
      "67": 3.71,
      "68": 4.22,
      "69": 3.05,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P2",
    "kpiGroup": "14. อัตราการป่วยตาย DM",
    "level": "U",
    "kpi": "อัตราการป่วยตาย DM",
    "okr": "อัตราการแทรกซ้อนในผู้ป่วยเบาหวาน <5%",
    "target": {
      "66": 5,
      "67": 4,
      "68": 3,
      "69": 2,
      "70": 1
    },
    "actual": {
      "66": 0.52,
      "67": 4.17,
      "68": 4.04,
      "69": 3.93,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P2",
    "kpiGroup": "14. อัตราการป่วยตาย DM",
    "level": "U",
    "kpi": "อัตราการป่วยตาย DM",
    "okr": "อัตราผู้ป่วยเบาหวานมาโรงพยาบาลก่อนนัดด้วยภาวะน้ำตาลต่ำ <5%",
    "target": {
      "66": 10,
      "67": 12,
      "68": 14,
      "69": 16,
      "70": 18
    },
    "actual": {
      "66": 1.29,
      "67": 0.77,
      "68": 2.11,
      "69": 1.4,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P2",
    "kpiGroup": "14. อัตราการป่วยตาย DM",
    "level": "U",
    "kpi": "อัตราการป่วยตาย DM",
    "okr": "อัตราผู้ป่วยเบาหวานมาโรงพยาบาลก่อนนัดด้วยภาวะน้ำตาลสูงวิกฤติ<10%",
    "target": {
      "66": 5,
      "67": 4.5,
      "68": 4,
      "69": 3.5,
      "70": 3
    },
    "actual": {
      "66": 2.01,
      "67": 2.21,
      "68": 6.7,
      "69": 4.45,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P2",
    "kpiGroup": "15. อัตราการป่วยตาย HT",
    "level": "U",
    "kpi": "อัตราการป่วยตาย HT",
    "okr": "ร้อยละผู้ป่วย HT ที่ความคุมระดับ BP >70%",
    "target": {
      "66": 68,
      "67": 69,
      "68": 70,
      "69": 71,
      "70": 72
    },
    "actual": {
      "66": 66.09,
      "67": 69.69,
      "68": 58.73,
      "69": 56,
      "70": null
    },
    "direction": ">",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P2",
    "kpiGroup": "15. อัตราการป่วยตาย HT",
    "level": "U",
    "kpi": "อัตราการป่วยตาย HT",
    "okr": "อัตราการขาดนัดในผู้ป่วย HT<5%",
    "target": {
      "66": 9,
      "67": 8,
      "68": 7,
      "69": 6,
      "70": 5
    },
    "actual": {
      "66": 3.34,
      "67": 4.78,
      "68": 3.99,
      "69": 4.84,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P2",
    "kpiGroup": "15. อัตราการป่วยตาย HT",
    "level": "U",
    "kpi": "อัตราการป่วยตาย HT",
    "okr": "อัตราผู้ป่วยความดันโลหิตสูงมีภาวะความดันโลหิตสูงวิกฤติ <2%",
    "target": {
      "66": 0.6,
      "67": 0.5,
      "68": 0.4,
      "69": 0.3,
      "70": 0.2
    },
    "actual": {
      "66": 0.23,
      "67": 0.17,
      "68": 0.22,
      "69": 0.2,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P2",
    "kpiGroup": "15. อัตราการป่วยตาย HT",
    "level": "U",
    "kpi": "อัตราการป่วยตาย HT",
    "okr": "อัตราผู้ป่วยแทรกซ้อนรายใหม่ในผู้ป่วย HT <5%",
    "target": {
      "66": 5,
      "67": 4,
      "68": 3,
      "69": 2,
      "70": 1
    },
    "actual": {
      "66": 0.2,
      "67": 0.21,
      "68": 0.2,
      "69": 0.76,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P2",
    "kpiGroup": "16. อัตราการป่วยตาย Stroke",
    "level": "P",
    "kpi": "อัตราการป่วยตาย Stroke",
    "okr": "Stroke รายใหม่ได้รับการติดตามเยี่ยมจนครบ 6 เดือน >80%",
    "target": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": 100,
      "67": 96.25,
      "68": 93.87,
      "69": 90.24,
      "70": null
    },
    "direction": ">",
    "owner": "ทิพวรรณ"
  },
  {
    "pillar": "P2",
    "kpiGroup": "16. อัตราการป่วยตาย Stroke",
    "level": "U",
    "kpi": "อัตราการป่วยตาย Stroke",
    "okr": "ผู้ป่วย Stroke ไดรับการฟื้นฟูมีคะแนน Bathel index > 15 คะแนน",
    "target": {
      "66": 60,
      "67": 65,
      "68": 70,
      "69": 75,
      "70": 80
    },
    "actual": {
      "66": 70.83,
      "67": 72.22,
      "68": 85.71,
      "69": 65.85,
      "70": null
    },
    "direction": ">",
    "owner": "ทิพวรรณ"
  },
  {
    "pillar": "P2",
    "kpiGroup": "16. อัตราการป่วยตาย Stroke",
    "level": "P",
    "kpi": "อัตราการป่วยตาย Stroke",
    "okr": "ภาวะแทรกซ้อนในผู้ป่วย Stroke<20",
    "target": {
      "66": 5,
      "67": 5,
      "68": 5,
      "69": 5,
      "70": 5
    },
    "actual": {
      "66": 5.26,
      "67": 14.81,
      "68": 6.12,
      "69": 2.43,
      "70": null
    },
    "direction": "<",
    "owner": "ทิพวรรณ"
  },
  {
    "pillar": "P2",
    "kpiGroup": "16. อัตราการป่วยตาย Stroke",
    "level": "R",
    "kpi": "อัตราการป่วยตาย Stroke",
    "okr": "อัตราผู้ป่วย Stroke fast tract ได้รับการส่งต่อภายใน 30นาที>80%",
    "target": {
      "66": 40,
      "67": 50,
      "68": 60,
      "69": 70,
      "70": 80
    },
    "actual": {
      "66": 33.55,
      "67": 51,
      "68": 42.3,
      "69": 70,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "16. อัตราการป่วยตาย Stroke",
    "level": "P",
    "kpi": "อัตราการป่วยตาย Stroke",
    "okr": "อัตราผู้ป่วย Stroke ที่มาถึงรพ.ภายใน 3 ชม.>50%",
    "target": {
      "66": 40,
      "67": 42,
      "68": 46,
      "69": 48,
      "70": 50
    },
    "actual": {
      "66": 48.34,
      "67": 31.7,
      "68": 35.13,
      "69": 60,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "16. อัตราการป่วยตาย Stroke",
    "level": "U",
    "kpi": "อัตราการป่วยตาย Stroke",
    "okr": "อัตราผู้ป่วย Stroke มาด้วยระบบ EMS>50%",
    "target": {
      "66": 20,
      "67": 30,
      "68": 40,
      "69": 50,
      "70": 50
    },
    "actual": {
      "66": 20.61,
      "67": 9.63,
      "68": 12.16,
      "69": 15,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "17. อัตราการป่วยตาย COPD/Asthma",
    "level": "U",
    "kpi": "อัตราการป่วยตาย COPD/Asthma",
    "okr": "ผู้ป่วยคลินิก COPD/Asthma ใช้ยาพ่นถูกต้องร้อยละ 80",
    "target": {
      "66": 80,
      "67": 82,
      "68": 84,
      "69": 86,
      "70": 88
    },
    "actual": {
      "66": 81.07,
      "67": 85,
      "68": 85,
      "69": 80.07,
      "70": null
    },
    "direction": ">",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P2",
    "kpiGroup": "17. อัตราการป่วยตาย COPD/Asthma",
    "level": "R",
    "kpi": "อัตราการป่วยตาย COPD/Asthma",
    "okr": "อัตราการเกิด respirayory failure COPD/Asthma ในหอผู้ป่วยใน",
    "target": {
      "66": 5,
      "67": 4,
      "68": 3,
      "69": 2,
      "70": 1
    },
    "actual": {
      "66": 1.29,
      "67": 2.09,
      "68": 4.02,
      "69": 1.02,
      "70": null
    },
    "direction": ">",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P2",
    "kpiGroup": "17. อัตราการป่วยตาย COPD/Asthma",
    "level": "U",
    "kpi": "อัตราการป่วยตาย COPD/Asthma",
    "okr": "อัตราป่วยตายด้วยโรค Asthma< 5 ในโรงพยาบาล",
    "target": {
      "66": 5,
      "67": 4,
      "68": 3,
      "69": 2,
      "70": 1
    },
    "actual": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": null
    },
    "direction": "<",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P2",
    "kpiGroup": "17. อัตราการป่วยตาย COPD/Asthma",
    "level": "U",
    "kpi": "อัตราการป่วยตาย COPD/Asthma",
    "okr": "อัตราป่วยตายด้วยโรค COPD< 5 ในโรงพยาบาล",
    "target": {
      "66": 5,
      "67": 4,
      "68": 3,
      "69": 2,
      "70": 1
    },
    "actual": {
      "66": 6.34,
      "67": 5.35,
      "68": 6.45,
      "69": 2.88,
      "70": null
    },
    "direction": "<",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P2",
    "kpiGroup": "18. อัตราการป่วยตาย ACS",
    "level": "U",
    "kpi": "อัตราการป่วยตาย ACS",
    "okr": "อัตราการได้รับ SK ในผู้ป่วย ASC ภายใน 30 นาที หลังจากได้รับการวินิจฉัยแล้วภายใน 100 %",
    "target": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": null,
      "67": null,
      "68": null,
      "69": null,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "18. อัตราการป่วยตาย ACS",
    "level": "P",
    "kpi": "อัตราการป่วยตาย ACS",
    "okr": "อัตราผู้ป่วย ACS ที่มาถึงรพ.ภายใน 3 ชม.≥80%",
    "target": {
      "66": 85,
      "67": 90,
      "68": 95,
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": 100,
      "67": 41.6,
      "68": 85.7,
      "69": 71.42,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "18. อัตราการป่วยตาย ACS",
    "level": "U",
    "kpi": "อัตราการป่วยตาย ACS",
    "okr": "อัตราผู้ป่วย ACS มาด้วยระบบ EMS>50%",
    "target": {
      "66": 20,
      "67": 25,
      "68": 30,
      "69": 40,
      "70": 50
    },
    "actual": {
      "66": 20,
      "67": 8.33,
      "68": 0,
      "69": 0,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "18. อัตราการป่วยตาย ACS",
    "level": "R",
    "kpi": "อัตราการป่วยตาย ACS",
    "okr": "อัตราผู้ป่วย ACS ได้รับการวินิจฉัยประเมิน EKG ภายใน10 นาที 100%",
    "target": {
      "66": 85,
      "67": 90,
      "68": 95,
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": 20,
      "67": 62.5,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "18. อัตราการป่วยตาย ACS",
    "level": "U",
    "kpi": "อัตราการป่วยตาย ACS",
    "okr": "อัตราผู้ป่วย ACS ได้รับการส่งต่อถึงศูนย์หัวใจ ภายใน 80 นาที 100%",
    "target": {
      "66": 60,
      "67": 70,
      "68": 80,
      "69": 90,
      "70": 100
    },
    "actual": {
      "66": 56.25,
      "67": 41.6,
      "68": 48.18,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "19. อัตราการป่วยตาย Head injury",
    "level": "U",
    "kpi": "อัตราการป่วยตาย Head injury",
    "okr": "อัตราผู้ป่วย moderate head injury ได้รับการส่งต่อภายใน 45 นาที 100%",
    "target": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "19. อัตราการป่วยตาย Head injury",
    "level": "U",
    "kpi": "อัตราการป่วยตาย Head injury",
    "okr": "อัตราผู้ป่วย severe head injury ได้รับการส่งต่อภายใน 1 ชั่วโมง 100%",
    "target": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": 100,
      "67": 100,
      "68": 91.66,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "19. อัตราการป่วยตาย Head injury",
    "level": "U",
    "kpi": "อัตราการป่วยตาย Head injury",
    "okr": "อัตราผู้ป่วยบาดเจ็บศีรษะและลำคอมาด้วยระบบ EMS>80%",
    "target": {
      "66": 50,
      "67": 60,
      "68": 70,
      "69": 80,
      "70": 80
    },
    "actual": {
      "66": 26.31,
      "67": 27.27,
      "68": 24.75,
      "69": 14.54,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P2",
    "kpiGroup": "20. อัตราการป่วยตาย DHF",
    "level": "P",
    "kpi": "อัตราการป่วยตาย DHF",
    "okr": "- อัตราการป่วยตาย DHF",
    "target": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": 0
    },
    "actual": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": null
    },
    "direction": "<",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P2",
    "kpiGroup": "20. อัตราการป่วยตาย DHF",
    "level": "P",
    "kpi": "อัตราการป่วยตาย DHF",
    "okr": "อัตราการเกิด DSS ในโรงพยาบาล",
    "target": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": 0
    },
    "actual": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": null
    },
    "direction": "<",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P2",
    "kpiGroup": "21. อัตราฆ่าตัวตาย",
    "level": "R",
    "kpi": "อัตราฆ่าตัวตาย",
    "okr": "ร้อยละของผู้ป่วยพยายามฆ่าตัวตายเข้าถึงบริการที่มีประสิทธิภาพ",
    "target": {
      "66": 80,
      "67": 80,
      "68": 90,
      "69": 90,
      "70": 90
    },
    "actual": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": "<",
    "owner": "มนสิชา"
  },
  {
    "pillar": "P2",
    "kpiGroup": "22. อัตราการป่วยตาย TB",
    "level": "U",
    "kpi": "อัตราการป่วยตาย TB",
    "okr": "อัตราการตายด้วยโรควัณโรค ไม่เกินร้อยละ5",
    "target": {
      "66": "<5",
      "67": "<5",
      "68": "<5",
      "69": "<5",
      "70": "<5"
    },
    "actual": {
      "66": 7.33,
      "67": 2.04,
      "68": 11.71,
      "69": 9.09,
      "70": null
    },
    "direction": "<",
    "owner": "เสาวณีย์"
  },
  {
    "pillar": "P2",
    "kpiGroup": "23. อัตราการป่วยตาย HIV",
    "level": "U",
    "kpi": "อัตราการป่วยตาย HIV",
    "okr": "ร้อยละของผู้ป่วยที่มีค่า VL < 40 copies",
    "target": {
      "66": 90,
      "67": 95,
      "68": 95,
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": 16.5,
      "67": 92.43,
      "68": 97.5,
      "69": 96.4,
      "70": null
    },
    "direction": "<",
    "owner": "สุวิทย์"
  },
  {
    "pillar": "P2",
    "kpiGroup": "23. อัตราการป่วยตาย HIV",
    "level": "U",
    "kpi": "อัตราการป่วยตาย HIV",
    "okr": "ร้อยละของผู้ป่วยรับประทานยาต่อเนื่อง (Adherence) >ร้อยละ 90",
    "target": {
      "66": 90,
      "67": 95,
      "68": 95,
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": 57.33,
      "67": 98,
      "68": 97.5,
      "69": 98,
      "70": null
    },
    "direction": ">",
    "owner": "สุวิทย์"
  },
  {
    "pillar": "P3",
    "kpiGroup": "24.ความมั่นคงปลอดภัยไซเบอร์",
    "level": "R",
    "kpi": "ความมั่นคงปลอดภัยไซเบอร์",
    "okr": "ประเมินความมั่นคงปลอดภัยไซเบอร์",
    "target": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่าน",
      "70": "ผ่าน"
    },
    "actual": {
      "66": "na",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่าน",
      "70": null
    },
    "direction": "text",
    "owner": "จริยาพร"
  },
  {
    "pillar": "P3",
    "kpiGroup": "25. โรงพยาบาลอัจฉริยะ",
    "level": "R",
    "kpi": "โรงพยาบาลอัจฉริยะ",
    "okr": "ประเมินโรงพยาบาลอัจฉริยะ",
    "target": {
      "66": "เงิน",
      "67": "ทอง",
      "68": "ทอง",
      "69": "ทอง",
      "70": "เพชร"
    },
    "actual": {
      "66": "na",
      "67": "เงิน",
      "68": "เงิน",
      "69": "เงิน",
      "70": null
    },
    "direction": "text",
    "owner": "จริยาพร"
  },
  {
    "pillar": "P3",
    "kpiGroup": "26 มาตรฐาน HAIT",
    "level": "R",
    "kpi": "มาตรฐาน HAIT",
    "okr": "ผ่านมาตรฐาน HAIT",
    "target": {
      "66": "ได้รับคัดเลือกเป็น รพ. นำร่องของจังหวัด",
      "67": null,
      "68": null,
      "69": "ผ่านการประเมิน HAIT",
      "70": null
    },
    "actual": {
      "66": "รอรับการประเมิน",
      "67": "รอรับการประเมิน",
      "68": "รอรับการประเมิน",
      "69": "รอดำเนินการ",
      "70": null
    },
    "direction": "text",
    "owner": "จริยาพร"
  },
  {
    "pillar": "P3",
    "kpiGroup": "27. ระบบบริหารจัดการสารสนเทศและพัสดุ",
    "level": "I",
    "kpi": "ระบบบริหารจัดการสารสนเทศและพัสดุ",
    "okr": "การประยุกต์ใช้งานระบบบริหารจัดการสารสนเทศและพัสดุ>80%",
    "target": {
      "66": 60,
      "67": 65,
      "68": 70,
      "69": 75,
      "70": 80
    },
    "actual": {
      "66": 12.12,
      "67": 85,
      "68": 88.88,
      "69": 88.88,
      "70": null
    },
    "direction": ">",
    "owner": "จริยาพร"
  },
  {
    "pillar": "P4",
    "kpiGroup": "28.มาตรฐานระบบบริการสุขภาพ(HS4)",
    "level": "P",
    "kpi": "มาตรฐานระบบบริการสุขภาพ(HS4)",
    "okr": "ผ่านมาตรฐานระบบบริการสุขภาพ >60%",
    "target": {
      "66": 70,
      "67": 75,
      "68": 80,
      "69": 85,
      "70": 90
    },
    "actual": {
      "66": 25.33,
      "67": 63.33,
      "68": 93,
      "69": "รอผลการประเมิน",
      "70": null
    },
    "direction": ">",
    "owner": "จริยาพร"
  },
  {
    "pillar": "P4",
    "kpiGroup": "29.ได้รับมาตรฐาน Green & Clean Hospital Challenge",
    "level": "I",
    "kpi": "ได้รับมาตรฐาน Green & Clean Hospital Challenge",
    "okr": "ได้รับมาตรฐาน Green & Clean Hospital Excellence",
    "target": {
      "66": "ระดับดีมาก Plus",
      "67": "ระดับดีมากPlus",
      "68": "ระดับดีมากPlus",
      "69": "ระดับดีมากPlus",
      "70": "ระดับดีมากPlus"
    },
    "actual": {
      "66": null,
      "67": null,
      "68": "ผ่านเกณฑ์มาตราฐาน",
      "69": "ไม่ผ่าน",
      "70": null
    },
    "direction": "text",
    "owner": "อรวรรณ"
  },
  {
    "pillar": "P4",
    "kpiGroup": "30.นโยบายEMS",
    "level": "I",
    "kpi": "นโยบายEMS",
    "okr": "ผ่านการประเมินการพัฒนาสถานบริการตามนโยบายEMS>80%",
    "target": {
      "66": "> 80",
      "67": "> 85",
      "68": "> 90",
      "69": "> 95",
      "70": "> 100"
    },
    "actual": {
      "66": "รอรับการประเมิน",
      "67": 92.86,
      "68": 92.86,
      "69": null,
      "70": null
    },
    "direction": ">",
    "owner": "นิภารัตน์"
  },
  {
    "pillar": "P4",
    "kpiGroup": "31. มาตรฐาน HA",
    "level": "R",
    "kpi": "มาตรฐาน HA",
    "okr": "ผ่านมาตรฐาน HA",
    "target": {
      "66": "ผ่านการรับรอง",
      "67": "ผ่านการรับรอง",
      "68": "ผ่านการรับรอง",
      "69": "ผ่านการรับรอง",
      "70": "ผ่านการรับรอง"
    },
    "actual": {
      "66": "ผ่านการรับรอง",
      "67": "ผ่านการรับรอง",
      "68": "ผ่านการรับรอง",
      "69": "ผ่านการรับรอง",
      "70": null
    },
    "direction": "text",
    "owner": "สุวิทย์"
  },
  {
    "pillar": "P4",
    "kpiGroup": "32. คลินิก COPD/Asthma คุณภาพ",
    "level": "I",
    "kpi": "คลินิก COPD/Asthma คุณภาพ",
    "okr": "ผ่านเกณฑ์ประเมิน easy asthma clinic",
    "target": {
      "66": "ผ่านเกณฑ์ประเมิน easy asthma clinic",
      "67": "ผ่านเกณฑ์ประเมิน easy asthma clinic",
      "68": "ผ่านเกณฑ์ประเมิน easy asthma clinic",
      "69": "ผ่านเกณฑ์ประเมิน easy asthma clinic",
      "70": "ผ่านเกณฑ์ประเมิน easy asthma clinic"
    },
    "actual": {
      "66": "ผ่านเกณฑ์",
      "67": "ผ่านเกณฑ์",
      "68": "ผ่านเกณฑ์",
      "69": "รอรับการประเมิน",
      "70": null
    },
    "direction": "text",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P4",
    "kpiGroup": "33. คลินิก NCD plus คุณภาพ",
    "level": "R",
    "kpi": "คลินิก NCD plus คุณภาพ",
    "okr": "ผ่านเกณฑ์ NCD Clinic Award",
    "target": {
      "66": "ดีเด่น",
      "67": "ดีเด่น",
      "68": "ดีเด่น",
      "69": "ดีเด่น",
      "70": "ดีเด่น"
    },
    "actual": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ระดับดีมาก",
      "69": "รอรับประเมิน",
      "70": null
    },
    "direction": "text",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P4",
    "kpiGroup": "33. คลินิก NCD plus คุณภาพ",
    "level": "I",
    "kpi": "คลินิก NCD plus คุณภาพ",
    "okr": "ระยะเวลารอคอยภายในคลินิก<2ชม.",
    "target": {
      "66": 150,
      "67": 140,
      "68": 130,
      "69": 120,
      "70": 110
    },
    "actual": {
      "66": 61.5,
      "67": 60.2,
      "68": 59.6,
      "69": 56.42,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P4",
    "kpiGroup": "34. คลินิกจิตเวชและยาเสพติด คุณภาพ",
    "level": "U",
    "kpi": "คลินิกจิตเวชและยาเสพติด คุณภาพ",
    "okr": "ผ่านมาตรฐานบริการยาเสพติด",
    "target": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่าน",
      "70": "ผ่าน"
    },
    "actual": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่าน",
      "70": null
    },
    "direction": "text",
    "owner": null
  },
  {
    "pillar": "P4",
    "kpiGroup": "34. คลินิกจิตเวชและยาเสพติด คุณภาพ",
    "level": "U",
    "kpi": "คลินิกจิตเวชและยาเสพติด คุณภาพ",
    "okr": "ผ่านมาตรฐานบริการสุขภาพจิตและจิตเวช ระดับ 1",
    "target": {
      "66": 2,
      "67": 2,
      "68": 1,
      "69": 1,
      "70": 1
    },
    "actual": {
      "66": "เตรียมการ",
      "67": 2,
      "68": 2,
      "69": "ระดับ 2",
      "70": null
    },
    "direction": ">",
    "owner": "มนสิชา"
  },
  {
    "pillar": "P4",
    "kpiGroup": "35. คลินิก HIV คุณภาพ",
    "level": "I",
    "kpi": "คลินิก HIV คุณภาพ",
    "okr": "ผ่านการประเมินหน่วยบริการคุณภาพโรคเอดส์",
    "target": {
      "66": "เตรียม",
      "67": "เตรียม",
      "68": "เตรียม",
      "69": "ผ่านการรับรอง",
      "70": "ผ่านการรับรอง"
    },
    "actual": {
      "66": "อยู่ระหว่างการเตรียม",
      "67": "อยู่ระหว่างการเตรียม",
      "68": "อยู่ระหว่างการเตรียม",
      "69": "กำลังดำเนินการ",
      "70": null
    },
    "direction": "text",
    "owner": "สุวิทย์"
  },
  {
    "pillar": "P4",
    "kpiGroup": "36. การจัดตั้ง Premium service",
    "level": "I",
    "kpi": "การจัดตั้ง Premium service",
    "okr": "การจัดตั้ง Premium service",
    "target": {
      "66": "ห้องตรวจพิเศษ",
      "67": "หอผู้ป่วยพิเศษ",
      "68": null,
      "69": null,
      "70": null
    },
    "actual": {
      "66": "ห้องตรวจพิเศษ",
      "67": "หอพิเศษ",
      "68": "หอพิเศษ",
      "69": "ตึกพิเศษ 11 ห้อง",
      "70": null
    },
    "direction": ">",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P4",
    "kpiGroup": "37. ห้องยาคุณภาพ",
    "level": "R",
    "kpi": "ห้องยาคุณภาพ",
    "okr": "ผ่านเกณฑ์ความปลอดภัยด้านยา",
    "target": {
      "66": "ระดับ3",
      "67": "ระดับ3",
      "68": "ระดับ4",
      "69": "ระดับ4",
      "70": "ระดับ4"
    },
    "actual": {
      "66": 3,
      "67": 3,
      "68": 4,
      "69": "ผ่าน",
      "70": null
    },
    "direction": ">",
    "owner": "สุนิสา"
  },
  {
    "pillar": "P4",
    "kpiGroup": "38. บริการกายภาพบำบัดคุณภาพ",
    "level": "I",
    "kpi": "บริการกายภาพบำบัดคุณภาพ",
    "okr": "ผ่านเกณฑ์มาตรฐานกายภาพบำบัด",
    "target": {
      "66": "ดีเยี่ยม",
      "67": null,
      "68": null,
      "69": "ผ่านการรับรองคุณภาพบริการกายภาพบำบัดจากสภากายภาพบำบัด",
      "70": null
    },
    "actual": {
      "66": "ระดับดี",
      "67": "ระดับดี",
      "68": "ระดับดี",
      "69": "ระดับดีมาก",
      "70": null
    },
    "direction": "text",
    "owner": "ทิพวรรณ"
  },
  {
    "pillar": "P4",
    "kpiGroup": "38. บริการกายภาพบำบัดคุณภาพ",
    "level": "P",
    "kpi": "บริการกายภาพบำบัดคุณภาพ",
    "okr": "พัฒนาศูนย์ฟื้นฟูผู้สูงอายุและผู้ป่วยระยะกลาง",
    "target": {
      "66": "จัดตั้งศูนย์ฟื้นฟูผู้สูงอายุและผู้ป่วยระยะกลาง",
      "67": null,
      "68": null,
      "69": "มีศูนย์ฟื้นฟูผู้สูงอายุและผู้ป่วยระยะกลางให้บริการ",
      "70": null
    },
    "actual": {
      "66": "ยังไม่ได้จัดตั้งศูนย์",
      "67": "ยังไม่ได้จัดตั้งศูนย์",
      "68": "ยังไม่ได้จัดตั้งศูนย์",
      "69": null,
      "70": null
    },
    "direction": ">",
    "owner": "ทิพวรรณ"
  },
  {
    "pillar": "P4",
    "kpiGroup": "39.มาตรฐานทางห้องปฏิบัติการ (LA)และรังสีวินิจฉัย",
    "level": "U",
    "kpi": "มาตรฐานทางห้องปฏิบัติการ (LA)และรังสีวินิจฉัย",
    "okr": "ตรวจประเมินระบบบริหารคุณภาพตามมาตรฐานห้องปฏิบัติการรังสีวินิจฉัย",
    "target": {
      "66": "ผ่าน **3 ปีครั้ง",
      "67": null,
      "68": null,
      "69": "ผ่าน **3 ปีครั้ง",
      "70": null
    },
    "actual": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่่าน",
      "70": null
    },
    "direction": ">",
    "owner": "วรรณ์สิริย์"
  },
  {
    "pillar": "P4",
    "kpiGroup": "39.มาตรฐานทางห้องปฏิบัติการ (LA)และรังสีวินิจฉัย",
    "level": "U",
    "kpi": "มาตรฐานทางห้องปฏิบัติการ (LA)และรังสีวินิจฉัย",
    "okr": "ผ่านเกณฑ์คุณภาพตามมาตรฐานห้องปฏิบัติการ(LA)",
    "target": {
      "66": "ผ่าน **3 ปีครั้ง",
      "67": null,
      "68": null,
      "69": "ผ่าน **3 ปีครั้ง",
      "70": null
    },
    "actual": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่าน",
      "70": null
    },
    "direction": ">",
    "owner": "นันท์นภัส"
  },
  {
    "pillar": "P4",
    "kpiGroup": "39.มาตรฐานทางห้องปฏิบัติการ (LA)และรังสีวินิจฉัย",
    "level": "U",
    "kpi": "มาตรฐานทางห้องปฏิบัติการ (LA)และรังสีวินิจฉัย",
    "okr": "มีใบอนุญาตมีไว้ในครอบครองหรือใช้เครื่องกำเนิดรังสี",
    "target": {
      "66": "มี",
      "67": "มี",
      "68": "มี",
      "69": "มี",
      "70": "มี"
    },
    "actual": {
      "66": "มี",
      "67": "มี",
      "68": "มี",
      "69": "มี",
      "70": null
    },
    "direction": ">",
    "owner": "วรรณ์สิริย์"
  },
  {
    "pillar": "P4",
    "kpiGroup": "40. คลินิกวัยรุ่น",
    "level": "U",
    "kpi": "คลินิกวัยรุ่น",
    "okr": "ผ่านเกณฑ์คุณภาพตามมาตรฐานคลินิกวัยรุ่น",
    "target": {
      "66": "ผ่าน",
      "67": "รอปรับตามเกณฑ์ กรมอนามัย",
      "68": null,
      "69": null,
      "70": null
    },
    "actual": {
      "66": "รอรับการประเมิน",
      "67": "รอรับการประเมิน",
      "68": "รอรับการประเมิน",
      "69": "รอประเมิน ปี 2569",
      "70": null
    },
    "direction": "text",
    "owner": "เสาวณีย์"
  },
  {
    "pillar": "P4",
    "kpiGroup": "41. บริการแพทย์แผนไทยคุณภาพ",
    "level": "U",
    "kpi": "บริการแพทย์แผนไทยคุณภาพ",
    "okr": "มาตรฐานรพ.สส.พท",
    "target": {
      "66": "ดีมาก",
      "67": "ดีมาก",
      "68": "ดีเยี่ยม",
      "69": "ดีเยี่ยม",
      "70": "ดีเยี่ยม"
    },
    "actual": {
      "66": "รอรับการประเมิน",
      "67": "ดีเยี่ยม",
      "68": "ดีเยี่ยม",
      "69": "รอผลการประเมิน",
      "70": null
    },
    "direction": "text",
    "owner": "ไพลิน"
  },
  {
    "pillar": "P4",
    "kpiGroup": "41. บริการแพทย์แผนไทยคุณภาพ",
    "level": "U",
    "kpi": "บริการแพทย์แผนไทยคุณภาพ",
    "okr": "ร้อยละของผู้ป่วยนอกที่ได้รับบริการการแพทย์แผนไทยและการแพทย์ทางเลือก > 16%",
    "target": {
      "66": 16,
      "67": 16,
      "68": 18,
      "69": 18,
      "70": 20
    },
    "actual": {
      "66": 15.37,
      "67": 9.7,
      "68": 76.85,
      "69": 11.55,
      "70": null
    },
    "direction": ">",
    "owner": "ไพลิน"
  },
  {
    "pillar": "P4",
    "kpiGroup": "42. ห้องฉุกเฉินคุณภาพ",
    "level": "U",
    "kpi": "ห้องฉุกเฉินคุณภาพ",
    "okr": "ผ่านเกณฑ์ห้องฉุกเฉินคุณภาพ≥50คะแนน",
    "target": {
      "66": 50,
      "67": 60,
      "68": 60,
      "69": 60,
      "70": 70
    },
    "actual": {
      "66": 56.6,
      "67": 58.5,
      "68": 60.1,
      "69": 57.25,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P4",
    "kpiGroup": "42. ห้องฉุกเฉินคุณภาพ",
    "level": "U",
    "kpi": "ห้องฉุกเฉินคุณภาพ",
    "okr": "ระดับความพึงพอใจของผู้รับบริการแผนกอุบัติเหตุ-ฉุกเฉิน >80%",
    "target": {
      "66": 80,
      "67": 80,
      "68": 80,
      "69": 80,
      "70": 80
    },
    "actual": {
      "66": 89.38,
      "67": 88.48,
      "68": 88.51,
      "69": 86.75,
      "70": null
    },
    "direction": ">",
    "owner": "จำรูญศรี"
  },
  {
    "pillar": "P4",
    "kpiGroup": "43. หอผู้ป่วยในคุณภาพ",
    "level": "U",
    "kpi": "หอผู้ป่วยในคุณภาพ",
    "okr": "case manager",
    "target": {
      "66": 4,
      "67": 5,
      "68": 6,
      "69": 8,
      "70": 10
    },
    "actual": {
      "66": null,
      "67": 5,
      "68": 3,
      "69": 3,
      "70": null
    },
    "direction": ">",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P4",
    "kpiGroup": "43. หอผู้ป่วยในคุณภาพ",
    "level": "U",
    "kpi": "หอผู้ป่วยในคุณภาพ",
    "okr": "ข้อร้องเรียน",
    "target": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": 0
    },
    "actual": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": null
    },
    "direction": "<",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P4",
    "kpiGroup": "43. หอผู้ป่วยในคุณภาพ",
    "level": "U",
    "kpi": "หอผู้ป่วยในคุณภาพ",
    "okr": "ระดับความพึงพอใจ>90%",
    "target": {
      "66": 90,
      "67": 90,
      "68": 90,
      "69": 90,
      "70": 90
    },
    "actual": {
      "66": 88.46,
      "67": 89.23,
      "68": 88.61,
      "69": 89.26,
      "70": null
    },
    "direction": ">",
    "owner": "กมลวรรณ"
  },
  {
    "pillar": "P4",
    "kpiGroup": "44. OPD คุณภาพ",
    "level": "U",
    "kpi": "OPD คุณภาพ",
    "okr": "ผ่านการรับรองOPDคุณภาพ",
    "target": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่าน",
      "70": "ผ่าน"
    },
    "actual": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่าน",
      "70": null
    },
    "direction": "text",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P4",
    "kpiGroup": "44. OPD คุณภาพ",
    "level": "U",
    "kpi": "OPD คุณภาพ",
    "okr": "ระดับความพึงพอใจ>85%",
    "target": {
      "66": 0.9,
      "67": 0.91,
      "68": 0.92,
      "69": 0.93,
      "70": 0.94
    },
    "actual": {
      "66": 89.46,
      "67": 91.5,
      "68": 92.3,
      "69": 88.99,
      "70": null
    },
    "direction": ">",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P4",
    "kpiGroup": "44. OPD คุณภาพ",
    "level": "U",
    "kpi": "OPD คุณภาพ",
    "okr": "ระยะเวลาเวลารอคอย<60นาที waiting time",
    "target": {
      "66": 56,
      "67": 54,
      "68": 52,
      "69": 50,
      "70": 48
    },
    "actual": {
      "66": 56,
      "67": 45.43,
      "68": 48.25,
      "69": 54.14,
      "70": null
    },
    "direction": "<",
    "owner": "ศศิธร"
  },
  {
    "pillar": "P4",
    "kpiGroup": "45. LR คุณภาพ",
    "level": "U",
    "kpi": "LR คุณภาพ",
    "okr": "ผ่านการรับรองห้องคลอดคุณภาพ",
    "target": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่าน",
      "70": "ผ่าน"
    },
    "actual": {
      "66": "ผ่าน",
      "67": "ผ่าน",
      "68": "ผ่าน",
      "69": "ผ่าน",
      "70": null
    },
    "direction": "text",
    "owner": "ณาตยา"
  },
  {
    "pillar": "P5",
    "kpiGroup": "46.การขับเคลื่อนงานป้องกันควบคุมโรคและภัยสุขภาพด้วยกลไกการพัฒนาคุณภาพชีวิตระดับอำเภอ (พชอ.)",
    "level": "R",
    "kpi": "การขับเคลื่อนงานป้องกันควบคุมโรคและภัยสุขภาพด้วยกลไกการพัฒนาคุณภาพชีวิตระดับอำเภอ (พชอ.)",
    "okr": "ร้อยละแผนงานโครงการที่ชุมชนมีส่วนร่วม > 50%",
    "target": {
      "66": 50,
      "67": 50,
      "68": 50,
      "69": 50,
      "70": 50
    },
    "actual": {
      "66": 100,
      "67": 100,
      "68": 100,
      "69": 100,
      "70": null
    },
    "direction": ">",
    "owner": "สาลี"
  },
  {
    "pillar": "P6",
    "kpiGroup": "47.ระดับความเสี่ยงทางการเงิน(Risk Score) ≤ 3",
    "level": "R",
    "kpi": "ระดับความเสี่ยงทางการเงิน(Risk Score) ≤ 3",
    "okr": "ระดับความเสี่ยงทางการเงิน(Risk Score) ≤ 3",
    "target": {
      "66": 0,
      "67": 0,
      "68": 0,
      "69": 0,
      "70": 0
    },
    "actual": {
      "66": 1,
      "67": 1,
      "68": 1,
      "69": 0.16,
      "70": null
    },
    "direction": "<",
    "owner": "นิภารัตน์"
  },
  {
    "pillar": "P6",
    "kpiGroup": "48.CMI",
    "level": "U",
    "kpi": "CMI",
    "okr": "การเพิ่มขึ้นของค่า CMI >=0.6",
    "target": {
      "66": 0.5,
      "67": 0.52,
      "68": 0.56,
      "69": 0.58,
      "70": 0.6
    },
    "actual": {
      "66": 0.56,
      "67": 0.58,
      "68": 0.6434,
      "69": 0.69,
      "70": null
    },
    "direction": ">",
    "owner": "สริยาภรณ์"
  },
  {
    "pillar": "P6",
    "kpiGroup": "49. อัตราครองเตียง > 85 %",
    "level": "U",
    "kpi": "อัตราครองเตียง > 85 %",
    "okr": "อัตราการครองเตียง>85%",
    "target": {
      "66": ">85",
      "67": ">90",
      "68": ">95",
      "69": 100,
      "70": 100
    },
    "actual": {
      "66": 52.47,
      "67": 66.48,
      "68": 73.76,
      "69": 77.19,
      "70": null
    },
    "direction": ">",
    "owner": "สริยาภรณ์"
  },
  {
    "pillar": "P6",
    "kpiGroup": "50. sum Adj RW",
    "level": "U",
    "kpi": "sum Adj RW",
    "okr": "Sum Adj-RW>1,400",
    "target": {
      "66": 1200,
      "67": 1250,
      "68": 1300,
      "69": 1350,
      "70": 1400
    },
    "actual": {
      "66": 1646,
      "67": 2254,
      "68": 2584,
      "69": 1477.94,
      "70": null
    },
    "direction": ">",
    "owner": "สริยาภรณ์"
  },
  {
    "pillar": "P6",
    "kpiGroup": "51. Current ratio ,cash ratio ,Quick ratio",
    "level": "U",
    "kpi": "Current ratio ,cash ratio ,Quick ratio",
    "okr": "Current ratio",
    "target": {
      "66": 1.5,
      "67": 1.5,
      "68": 1.5,
      "69": 1.5,
      "70": 1.5
    },
    "actual": {
      "66": 3.53,
      "67": 5.41,
      "68": 2.32,
      "69": 2.08,
      "70": null
    },
    "direction": ">",
    "owner": null
  },
  {
    "pillar": "P6",
    "kpiGroup": "51. Current ratio ,cash ratio ,Quick ratio",
    "level": "U",
    "kpi": "Current ratio ,cash ratio ,Quick ratio",
    "okr": "QR",
    "target": {
      "66": 1,
      "67": 1,
      "68": 1,
      "69": 1,
      "70": 1
    },
    "actual": {
      "66": 3.41,
      "67": 5.02,
      "68": 1.94,
      "69": 1.84,
      "70": null
    },
    "direction": ">",
    "owner": "นิภารัตน์"
  },
  {
    "pillar": "P6",
    "kpiGroup": "51. Current ratio ,cash ratio ,Quick ratio",
    "level": "U",
    "kpi": "Current ratio ,cash ratio ,Quick ratio",
    "okr": "cash ratio",
    "target": {
      "66": 0.8,
      "67": 0.8,
      "68": 0.8,
      "69": 0.8,
      "70": 0.8
    },
    "actual": {
      "66": 3.13,
      "67": 4.09,
      "68": 1.1,
      "69": 1.17,
      "70": null
    },
    "direction": ">",
    "owner": null
  },
  {
    "pillar": "P6",
    "kpiGroup": "52. EBIDA",
    "level": "U",
    "kpi": "EBIDA",
    "okr": ">3000000",
    "target": {
      "66": ">3000000",
      "67": ">3000000",
      "68": ">3000000",
      "69": ">3000000",
      "70": ">3000000"
    },
    "actual": {
      "66": -11665498.65,
      "67": -7154891.12,
      "68": -16409487.77,
      "69": 5558815.645,
      "70": null
    },
    "direction": ">",
    "owner": "นิภารัตน์"
  },
  {
    "pillar": "P6",
    "kpiGroup": "53. OPD/IPD unit cost",
    "level": "P",
    "kpi": "OPD/IPD unit cost",
    "okr": "IPD unit cost",
    "target": {
      "66": 24396.36,
      "67": "21.581.28",
      "68": 20429.37,
      "69": 18347.55,
      "70": 18000
    },
    "actual": {
      "66": 25646.09,
      "67": 15127.64,
      "68": 17628.9,
      "69": 15122.8,
      "70": null
    },
    "direction": ">",
    "owner": "พรทิพย์"
  },
  {
    "pillar": "P6",
    "kpiGroup": "53. OPD/IPD unit cost",
    "level": "P",
    "kpi": "OPD/IPD unit cost",
    "okr": "OPD unit cost",
    "target": {
      "66": 1054.22,
      "67": 1023.26,
      "68": 1062.11,
      "69": 1040.59,
      "70": 1050
    },
    "actual": {
      "66": 674.69,
      "67": 898.02,
      "68": 805.77,
      "69": 740.76,
      "70": null
    },
    "direction": ">",
    "owner": "พรทิพย์"
  },
  {
    "pillar": "P6",
    "kpiGroup": "54.ค่าสาธารณูปโภค",
    "level": "I",
    "kpi": "ค่าสาธารณูปโภค",
    "okr": "หน่วยการใช้ไฟฟ้าลดลงปีละ >= 5%",
    "target": {
      "66": ">5%",
      "67": ">5%",
      "68": ">5%",
      "69": ">5%",
      "70": ">5%"
    },
    "actual": {
      "66": 311.1,
      "67": 302.52,
      "68": 233.67,
      "69": null,
      "70": null
    },
    "direction": ">",
    "owner": "นิภารัตน์"
  },
  {
    "pillar": "P7",
    "kpiGroup": "55.ร้อยละความพึงพอใจของบุคลากร >70",
    "level": "R",
    "kpi": "ร้อยละความพึงพอใจของบุคลากร >70",
    "okr": "ร้ออยละความพึงพอใจของบุคลากร >70",
    "target": {
      "66": 70,
      "67": 75,
      "68": 80,
      "69": 85,
      "70": 90
    },
    "actual": {
      "66": 75.08,
      "67": null,
      "68": 81.64,
      "69": 81.64,
      "70": null
    },
    "direction": ">",
    "owner": "ทีม HRD"
  },
  {
    "pillar": "P7",
    "kpiGroup": "56.อัตราความคงอยู่ของบุคลากรด้านสุขภาพ >70",
    "level": "R",
    "kpi": "อัตราความคงอยู่ของบุคลากรด้านสุขภาพ >70",
    "okr": "อัตราความคงอยู่ของบุคลากรด้านสุขภาพ >70",
    "target": {
      "66": 70,
      "67": 72,
      "68": 74,
      "69": 76,
      "70": 78
    },
    "actual": {
      "66": 98.03,
      "67": 98.25,
      "68": 97.25,
      "69": 97.25,
      "70": null
    },
    "direction": ">",
    "owner": "ทีม HRD"
  },
  {
    "pillar": "P7",
    "kpiGroup": "57.จำนวน CQI/R2R//Innovation/งานวิจัย >5 เรื่อง/ปี",
    "level": "R",
    "kpi": "จำนวน CQI/R2R//Innovation/งานวิจัย >5 เรื่อง/ปี",
    "okr": "จำนวน CQI/R2R//Innovation/งานวิจัย >5 เรื่อง/ปี",
    "target": {
      "66": 5,
      "67": 5,
      "68": 5,
      "69": 5,
      "70": 5
    },
    "actual": {
      "66": 7,
      "67": 15,
      "68": 15,
      "69": 19,
      "70": null
    },
    "direction": ">",
    "owner": "ทีม HRD"
  }
];

// ════════════════════════════════════════════════════════════
// PILLAR METADATA
// ════════════════════════════════════════════════════════════
const PILLAR_META = {
  P1: { name:'ลดการเจ็บป่วยรายใหม่ในโรคยุทธศาสตร์ทุกกลุ่มวัย', icon:'🦠', color:'#0d9488' },
  P2: { name:'ลดการป่วยตายในโรคยุทธศาสตร์ในทุกกลุ่มวัย', icon:'❤️‍🩹', color:'#dc2626' },
  P3: { name:'ระบบเทคโนโลยีและสารสนเทศได้มาตรฐานสากล', icon:'💻', color:'#2563eb' },
  P4: { name:'หน่วยบริการทุกระดับผ่านเกณฑ์คุณภาพ', icon:'🏥', color:'#7c3aed' },
  P5: { name:'เพิ่มศักยภาพภาคีเครือข่ายระดับอำเภอ', icon:'🤝', color:'#059669' },
  P6: { name:'โรงพยาบาลมีเสถียรภาพด้านการเงินการคลัง', icon:'💰', color:'#d97706' },
  P7: { name:'บุคลากรเป็นเลิศ', icon:'👥', color:'#db2777' }
};

// ════════════════════════════════════════════════════════════
// STATUS EVALUATION LOGIC
// direction: '>' = higher better, '<' = lower better
//            '=' = must equal target, 'text' = qualitative
// ════════════════════════════════════════════════════════════
function evalStatus(row, year = 68) {
  const t = row.target[year];
  const a = row.actual[year];

  if (a === null || a === undefined || a === '') return 'ไม่มีข้อมูล';

  const aStr = String(a).trim();
  const tStr = t !== null && t !== undefined ? String(t).trim() : '';

  // ── Special cases: direction = 'special' ──────────────────────────
  // ใช้ evalFn แทน direction เพื่อ handle logic เฉพาะรายตัวชี้วัด
  if (typeof row.evalFn === 'function') {
    return row.evalFn(a, t, aStr, tStr, row, year);
  }

  // ── Qualitative / text ──────────────────────────────────────────
  if (row.direction === 'text') {
    const passWords = ['ผ่าน','ระดับดี','ดีเยี่ยม','ดีมาก','ดี','ระดับ','มี'];
    const failWords = ['รอรับ','ยังไม่','ไม่ได้','เตรียม','อยู่ระหว่าง'];
    const goodMatch = passWords.some(w => aStr.includes(w));
    const failMatch = failWords.some(w => aStr.includes(w));
    if (goodMatch && !failMatch) return 'บรรลุ';
    if (failMatch) return 'ไม่บรรลุ';
    return 'ไม่มีข้อมูล';
  }

  // ── Must equal ──────────────────────────────────────────────────
  if (row.direction === '=') {
    if (tStr === '' || t === null) return 'ไม่มีข้อมูล';
    const aNum = parseFloat(aStr);
    const tNum = parseFloat(tStr);
    if (!isNaN(aNum) && !isNaN(tNum)) return aNum === tNum ? 'บรรลุ' : 'ไม่บรรลุ';
    return aStr === tStr ? 'บรรลุ' : 'ไม่บรรลุ';
  }

  // ── Numeric: higher better / lower better ───────────────────────
  const aNum = parseFloat(aStr);
  if (isNaN(aNum)) return 'ไม่มีข้อมูล';

  const tClean = tStr.replace(/[≥≤<>]/g,'').replace(/%/g,'').trim();
  const tNum = parseFloat(tClean);
  if (isNaN(tNum)) return 'ไม่มีข้อมูล';

  if (row.direction === '>') {
    if (aNum >= tNum) return 'บรรลุ';
    if (aNum >= tNum * 0.9) return 'ใกล้บรรลุ';
    return 'ไม่บรรลุ';
  }
  if (row.direction === '<') {
    if (aNum <= tNum) return 'บรรลุ';
    if (aNum <= tNum * 1.1) return 'ใกล้บรรลุ';
    return 'ไม่บรรลุ';
  }
  return 'ไม่มีข้อมูล';
}

function getTrend(row) {
  const vals = [66, 67, 68, 69]
    .map(y => parseFloat(row.actual[y]))
    .filter(v => !isNaN(v));
  if (vals.length < 2) return '➖';
  const last = vals[vals.length - 1];
  const first = vals[0];
  const diff = last - first;
  if (row.direction === '>') return diff > 0.5 ? '📈' : diff < -0.5 ? '📉' : '➡️';
  if (row.direction === '<') return diff < -0.5 ? '📈' : diff > 0.5 ? '📉' : '➡️';
  return '➡️';
}

function getGap(row, year = 68) {
  const a = row.actual[year];
  const t = row.target[year];
  if (a === null || t === null || row.direction === 'text' || row.direction === '=') return null;
  const aNum = parseFloat(String(a).replace(/[≥≤<>%]/g,''));
  const tNum = parseFloat(String(t).replace(/[≥≤<>%]/g,''));
  if (isNaN(aNum) || isNaN(tNum)) return null;
  return aNum - tNum;
}

function fmtNum(v) {
  if (v === null || v === undefined) return '–';
  if (typeof v === 'string') return v;
  if (typeof v === 'number') {
    if (Number.isInteger(v)) return v.toLocaleString('th-TH');
    return v.toLocaleString('th-TH', {maximumFractionDigits:2});
  }
  return String(v);
}

// ════════════════════════════════════════════════════════════
// COMPUTE SUMMARY
// ════════════════════════════════════════════════════════════
function computeSummary() {
  const latestYear = 69;
  const total = RAW_DATA.length;
  const pillars = 7;
  const has68 = RAW_DATA.filter(r => r.actual[latestYear] !== null && r.actual[latestYear] !== undefined && r.actual[latestYear] !== '').length;
  const statuses = RAW_DATA.map(r => evalStatus(r, latestYear));
  const achieved = statuses.filter(s => s === 'บรรลุ').length;
  const near = statuses.filter(s => s === 'ใกล้บรรลุ').length;
  const fail = statuses.filter(s => s === 'ไม่บรรลุ').length;
  const noData = statuses.filter(s => s === 'ไม่มีข้อมูล').length;
  return { total, pillars, has68, achieved, near, fail, noData };
}

// ════════════════════════════════════════════════════════════
// BUILD SUMMARY CARDS
// ════════════════════════════════════════════════════════════
function buildSummary() {
  const s = computeSummary();
  const grid = document.getElementById('summaryGrid');
  const cards = [
    { num: s.pillars, label: 'ยุทธศาสตร์ P1–P7', cls: '' },
    { num: s.total, label: 'ตัวชี้วัด/OKRs ทั้งหมด', cls: '' },
    { num: s.has68, label: 'มีผลดำเนินงานปี 2569', cls: 'accent' },
    { num: s.achieved, label: '✅ บรรลุเป้าหมายปี 2569', cls: 'good' },
    { num: s.near, label: '🟡 ใกล้บรรลุ (±10%)', cls: 'warn' },
    { num: s.fail, label: '❌ ไม่บรรลุ / ต้องเร่งพัฒนา', cls: 'bad' },
    { num: s.noData, label: '➖ ไม่มีข้อมูลปี 2569', cls: '' },
  ];
  grid.innerHTML = cards.map(c => `
    <div class="summary-card ${c.cls}">
      <div class="summary-num">${c.num}</div>
      <div class="summary-label">${c.label}</div>
    </div>
  `).join('');
}

// ════════════════════════════════════════════════════════════
// BUILD PILLAR CARDS
// ════════════════════════════════════════════════════════════
function buildPillars() {
  const grid = document.getElementById('pillarGrid');
  const pillars = ['P1','P2','P3','P4','P5','P6','P7'];
  grid.innerHTML = pillars.map(p => {
    const rows = RAW_DATA.filter(r => r.pillar === p);
    const statuses = rows.map(r => evalStatus(r, 69));
    const good = statuses.filter(s => s === 'บรรลุ').length;
    const near = statuses.filter(s => s === 'ใกล้บรรลุ').length;
    const fail = statuses.filter(s => s === 'ไม่บรรลุ').length;
    const hasData = rows.filter(r => r.actual[69] !== null && r.actual[69] !== undefined && r.actual[69] !== '').length;
    const total = rows.length;
    const pct = total > 0 ? Math.round((good / total) * 100) : 0;
    let overallStatus = 'status-na';
    let statusLabel = 'ไม่มีข้อมูล';
    if (hasData > 0) {
      if (fail > good && fail > 1) { overallStatus = 'status-bad'; statusLabel = 'ต้องเร่งพัฒนา'; }
      else if (good >= fail) { overallStatus = 'status-good'; statusLabel = 'ดี'; }
      else { overallStatus = 'status-warn'; statusLabel = 'เฝ้าระวัง'; }
    }
    const meta = PILLAR_META[p];
    const highlights = getPillarHighlights(p, rows);

    return `
    <div class="pillar-card">
      <div class="pillar-header">
        <div class="pillar-icon" style="background:${meta.color};">${meta.icon}</div>
        <div class="pillar-info">
          <div class="pillar-code">${p}</div>
          <div class="pillar-name">${meta.name}</div>
        </div>
        <div class="pillar-status ${overallStatus}">${statusLabel}</div>
      </div>
      <div class="pillar-body">
        <div class="pillar-stats">
          <div class="pillar-stat"><div class="pillar-stat-num">${total}</div><div class="pillar-stat-lbl">OKRs</div></div>
          <div class="pillar-stat"><div class="pillar-stat-num" style="color:var(--good)">${good}</div><div class="pillar-stat-lbl">บรรลุ</div></div>
          <div class="pillar-stat"><div class="pillar-stat-num" style="color:var(--warn)">${near}</div><div class="pillar-stat-lbl">ใกล้บรรลุ</div></div>
          <div class="pillar-stat"><div class="pillar-stat-num" style="color:var(--bad)">${fail}</div><div class="pillar-stat-lbl">ไม่บรรลุ</div></div>
        </div>
        <div class="progress-bar-wrap">
          <div class="progress-bar-bg">
            <div class="progress-bar-fill" style="width:${pct}%; background:linear-gradient(to right,${meta.color},${meta.color}aa)"></div>
          </div>
          <div class="progress-label"><span>ความสำเร็จปี 2569</span><span>${pct}% (${good}/${total})</span></div>
        </div>
        <ul class="pillar-highlights">
          ${highlights.map(h => `<li><span class="hl-dot" style="background:${meta.color}"></span>${h}</li>`).join('')}
        </ul>
      </div>
    </div>`;
  }).join('');
}

function getPillarHighlights(p, rows) {
  const withData = rows.filter(r => r.actual[69] !== null && r.actual[69] !== undefined && r.actual[69] !== '');
  const good = withData.filter(r => evalStatus(r, 69) === 'บรรลุ').slice(0, 3);
  const fail = withData.filter(r => evalStatus(r, 69) === 'ไม่บรรลุ').slice(0, 2);
  const hl = [];
  good.forEach(r => hl.push(`${r.kpi}: ปี 2569 = ${fmtNum(r.actual[69])} บรรลุเป้า ${fmtNum(r.target[69])}`));
  fail.forEach(r => hl.push(`${r.kpi}: ปี 2569 = ${fmtNum(r.actual[69])} ต่ำ/เกินเป้า ${fmtNum(r.target[69])} ต้องติดตาม`));
  if (hl.length === 0) hl.push('ยังไม่มีข้อมูลปี 2569 เพียงพอสำหรับสรุปประเด็นรายยุทธศาสตร์');
  return hl.slice(0, 5);
}

// ════════════════════════════════════════════════════════════
// BUILD TABLE
// ════════════════════════════════════════════════════════════
let currentData = [...RAW_DATA];
let sortKey = null;
let sortAsc = true;

function buildTable(data) {
  const tbody = document.getElementById('tableBody');
  document.getElementById('filterCount').textContent = `แสดง ${data.length} รายการ จาก ${RAW_DATA.length}`;
  
  tbody.innerHTML = data.map(row => {
    const status69 = evalStatus(row, 69);
    const trend = getTrend(row);
    const gap = getGap(row, 69);
    let gapHtml = '<span class="gap-na">–</span>';
    if (gap !== null) {
      const sign = gap > 0 ? '+' : '';
      const cls = (row.direction === '<' && gap <= 0) || (row.direction === '>' && gap >= 0) ? 'gap-pos' : 'gap-neg';
      gapHtml = `<span class="gap-val ${cls}">${sign}${fmtNum(gap)}</span>`;
    }
    const note = getNote(row);
    return `
    <tr>
      <td><span style="font-weight:700;color:${PILLAR_META[row.pillar].color}">${row.pillar}</span></td>
      <td><span class="badge-level badge-${row.level}">${row.level}</span></td>
      <td class="td-kpi">${row.kpi}</td>
      <td class="td-okr">${row.okr}</td>
      <td class="td-year">${fmtNum(row.target[66])}</td>
      <td class="td-year">${fmtNum(row.target[67])}</td>
      <td class="td-year">${fmtNum(row.target[68])}</td>
      <td class="td-year">${fmtNum(row.target[69])}</td>
      <td class="td-year">${fmtNum(row.actual[66])}</td>
      <td class="td-year">${fmtNum(row.actual[67])}</td>
      <td class="td-year">${fmtNum(row.actual[68])}</td>
      <td class="td-year">${fmtNum(row.actual[69])}</td>
      <td><span class="badge-status badge-${status69}">${status69}</span></td>
      <td>${gapHtml}</td>
      <td class="trend-arrow">${trend}</td>
      <td style="font-size:12px;color:var(--text-muted);max-width:180px;">${note}</td>
    </tr>`;
  }).join('');
}

function getNote(row) {
  const s = evalStatus(row, 69);
  if (s === 'บรรลุ') return '✅ บรรลุเป้าหมายปี 2569';
  if (s === 'ใกล้บรรลุ') return '🟡 ใกล้บรรลุ ควรติดตามต่อเนื่อง';
  if (s === 'ไม่บรรลุ') return '❌ ต้องวางแผนปรับปรุง';
  if (row.actual[69] === null || row.actual[69] === undefined || row.actual[69] === '') {
    if (row.actual[68] !== null && row.actual[68] !== undefined && row.actual[68] !== '') return '⚠️ ขาดข้อมูลปี 69 (มีปี 68)';
    return '➖ ยังไม่มีข้อมูลผลดำเนินงาน';
  }
  return '➖ ประเมินไม่ได้ (ตัวชี้วัดเชิงคุณภาพ)';
}

function applyFilters() {
  const pillar = document.getElementById('filterPillar').value;
  const level = document.getElementById('filterLevel').value;
  const status = document.getElementById('filterStatus').value;
  const search = document.getElementById('filterSearch').value.toLowerCase();
  currentData = RAW_DATA.filter(row => {
    if (pillar && row.pillar !== pillar) return false;
    if (level && row.level !== level) return false;
    if (status && evalStatus(row, 69) !== status) return false;
    if (search) {
      const haystack = (row.kpi + ' ' + row.okr + ' ' + row.kpiGroup).toLowerCase();
      if (!haystack.includes(search)) return false;
    }
    return true;
  });
  if (sortKey) doSort();
  else buildTable(currentData);
}

function resetFilters() {
  document.getElementById('filterPillar').value = '';
  document.getElementById('filterLevel').value = '';
  document.getElementById('filterStatus').value = '';
  document.getElementById('filterSearch').value = '';
  currentData = [...RAW_DATA];
  buildTable(currentData);
}

function sortTable(key) {
  if (sortKey === key) sortAsc = !sortAsc;
  else { sortKey = key; sortAsc = true; }
  doSort();
}
function doSort() {
  currentData.sort((a, b) => {
    let va = a[sortKey] || '';
    let vb = b[sortKey] || '';
    if (sortKey === 'status') { va = evalStatus(a,69); vb = evalStatus(b,69); }
    return sortAsc ? String(va).localeCompare(String(vb), 'th') : String(vb).localeCompare(String(va), 'th');
  });
  buildTable(currentData);
}

// ════════════════════════════════════════════════════════════
// BUILD CHARTS
// ════════════════════════════════════════════════════════════
let trendChart = null;
let selectedKpiIdx = 0;

// chart 1: status by pillar
function buildStatusChart() {
  const pillars = ['P1','P2','P3','P4','P5','P6','P7'];
  const achieved = [], near = [], fail = [], nodata = [];
  pillars.forEach(p => {
    const rows = RAW_DATA.filter(r => r.pillar === p);
    const statuses = rows.map(r => evalStatus(r, 69));
    achieved.push(statuses.filter(s => s === 'บรรลุ').length);
    near.push(statuses.filter(s => s === 'ใกล้บรรลุ').length);
    fail.push(statuses.filter(s => s === 'ไม่บรรลุ').length);
    nodata.push(statuses.filter(s => s === 'ไม่มีข้อมูล').length);
  });
  const ctx = document.getElementById('chartStatus').getContext('2d');
  new Chart(ctx, {
    type: 'bar',
    data: {
      labels: pillars,
      datasets: [
        { label: 'บรรลุ', data: achieved, backgroundColor: '#16a34a' },
        { label: 'ใกล้บรรลุ', data: near, backgroundColor: '#ca8a04' },
        { label: 'ไม่บรรลุ', data: fail, backgroundColor: '#dc2626' },
        { label: 'ไม่มีข้อมูล', data: nodata, backgroundColor: '#d1d5db' }
      ]
    },
    options: {
      responsive: true, maintainAspectRatio: false,
      plugins: { legend: { position: 'bottom', labels: { font: { family: 'Sarabun', size: 12 } } } },
      scales: {
        x: { stacked: true, ticks: { font: { family: 'Sarabun', size: 12 } } },
        y: { stacked: true, ticks: { font: { family: 'Sarabun' } }, title: { display: true, text: 'จำนวนตัวชี้วัด', font: { family: 'Sarabun' } } }
      }
    }
  });
}

// chart 2: trend for selected KPI
const TREND_KPIS = [
  { label:'HIV PrEP เริ่มใช้', row: RAW_DATA.find(r => r.okr.includes('PrEP/PEP') && r.okr.includes('เริ่มใช้ PrEP/PEP')) },
  { label:'DM ควบคุมน้ำตาล', row: RAW_DATA.find(r => r.okr.includes('ควบคุมระดับน้ำตาล')) },
  { label:'HT แทรกซ้อน', row: RAW_DATA.find(r => r.okr.includes('แทรกซ้อนรายใหม่ในผู้ป่วย HT')) },
  { label:'Sepsis AB', row: RAW_DATA.find(r => r.okr.includes('Antibiotic ภายใน 1 ชม')) },
  { label:'Sum Adj-RW', row: RAW_DATA.find(r => r.okr.includes('Adj-RW')) },
  { label:'ความพึงพอใจบุคลากร', row: RAW_DATA.find(r => r.okr.includes('ความพึงพอใจของบุคลากร')) },
  { label:'CQI/R2R', row: RAW_DATA.find(r => r.okr.includes('CQI/R2R')) },
  { label:'HS4', row: RAW_DATA.find(r => r.okr.includes('มาตรฐานระบบบริการสุขภาพ')) },
  { label:'CMI', row: RAW_DATA.find(r => r.okr.includes('CMI')) },
  { label:'TB อัตราตาย', row: RAW_DATA.find(r => r.okr.includes('ตายด้วยโรควัณโรค')) },
].filter(k => k.row);

function buildKpiSelector() {
  const sel = document.getElementById('kpiSelector');
  sel.innerHTML = TREND_KPIS.map((k, i) => `
    <button class="kpi-chip ${i === 0 ? 'active' : ''}" onclick="selectKpi(${i})">${k.label}</button>
  `).join('');
}

function selectKpi(idx) {
  selectedKpiIdx = idx;
  document.querySelectorAll('.kpi-chip').forEach((c, i) => c.classList.toggle('active', i === idx));
  buildTrendChart();
}

function buildTrendChart() {
  const k = TREND_KPIS[selectedKpiIdx];
  const row = k.row;
  const years = ['66','67','68','69'];
  const targets = years.map(y => {
    const t = row.target[parseInt(y)];
    if (t === null || t === undefined) return null;
    const num = parseFloat(String(t).replace(/[≥≤<>%]/g,''));
    return isNaN(num) ? null : num;
  });
  const actuals = years.map(y => {
    const a = row.actual[parseInt(y)];
    if (a === null || a === undefined) return null;
    const num = parseFloat(String(a));
    return isNaN(num) ? null : num;
  });

  const ctx = document.getElementById('chartTrend').getContext('2d');
  if (trendChart) trendChart.destroy();
  trendChart = new Chart(ctx, {
    type: 'line',
    data: {
      labels: years.map(y => `ปี 25${y}`),
      datasets: [
        {
          label: 'เป้าหมาย', data: targets,
          borderColor: '#94a3b8', borderDash: [6,3],
          pointStyle: 'rectRot', pointRadius: 5,
          backgroundColor: 'transparent'
        },
        {
          label: 'ผลจริง', data: actuals,
          borderColor: '#0d5c8f', borderWidth: 2.5,
          pointRadius: 6, pointBackgroundColor: '#0d5c8f',
          backgroundColor: 'rgba(13,92,143,0.08)',
          fill: true, tension: 0.35
        }
      ]
    },
    options: {
      responsive: true, maintainAspectRatio: false,
      plugins: {
        title: { display: true, text: k.label + ' – Target vs Actual', font: { family: 'Sarabun', size: 14 } },
        legend: { position: 'bottom', labels: { font: { family: 'Sarabun' } } }
      },
      scales: {
        x: { ticks: { font: { family: 'Sarabun' } } },
        y: { ticks: { font: { family: 'Sarabun' } } }
      }
    }
  });
}

// chart 3: heatmap
function buildHeatmap() {
  const pillars = ['P1','P2','P3','P4','P5','P6','P7'];
  const years = [66, 67, 68, 69];
  const wrap = document.getElementById('heatmapWrap');

  const getCellClass = (p, y) => {
    const rows = RAW_DATA.filter(r => r.pillar === p);
    const hasActual = rows.filter(r => r.actual[y] !== null && r.actual[y] !== undefined && r.actual[y] !== '');
    if (hasActual.length === 0) return { cls:'hm-na', label:'–' };
    const statuses = hasActual.map(r => evalStatus(r, y));
    const good = statuses.filter(s => s === 'บรรลุ').length;
    const fail = statuses.filter(s => s === 'ไม่บรรลุ').length;
    const total = statuses.length;
    const pct = Math.round((good / total) * 100);
    if (pct >= 70) return { cls:'hm-good', label:`${pct}%` };
    if (pct >= 40) return { cls:'hm-mixed', label:`${pct}%` };
    if (pct >= 1) return { cls:'hm-bad', label:`${pct}%` };
    return { cls:'hm-warn', label:`${pct}%` };
  };

  let html = `<table class="heatmap-table"><thead><tr>
    <th>ยุทธศาสตร์</th>
    <th>ปี 2566</th><th>ปี 2567</th><th>ปี 2568</th><th>ปี 2569</th>
  </tr></thead><tbody>`;

  pillars.forEach(p => {
    html += `<tr><td class="hm-row-label">${p} – ${PILLAR_META[p].name.substring(0,20)}...</td>`;
    years.forEach(y => {
      const c = getCellClass(p, y);
      html += `<td class="${c.cls}" title="${p} ปี 25${y} : ${c.label} ของตัวชี้วัดที่มีข้อมูล">${c.label}</td>`;
    });
    html += '</tr>';
  });
  html += '</tbody></table>';
  html += `<p style="font-size:12px;color:var(--text-muted);margin-top:8px">
    🟢 ≥70% บรรลุ | 🟣 40–69% | 🔴 1–39% | ⬛ ไม่มีข้อมูล | ตัวเลขแสดงสัดส่วนตัวชี้วัดที่มีข้อมูลและบรรลุเป้าหมาย</p>`;
  wrap.innerHTML = html;
}

// ════════════════════════════════════════════════════════════
// HIGHLIGHTS
// ════════════════════════════════════════════════════════════
function buildHighlights() {
  const rows69 = RAW_DATA.filter(r => r.actual[69] !== null && r.actual[69] !== undefined && r.actual[69] !== '');
  const strengths = rows69.filter(r => evalStatus(r, 69) === 'บรรลุ').slice(0, 10).map(r =>
    `✅ <strong>${r.pillar} ${r.kpi}:</strong> ปี 2569 = ${fmtNum(r.actual[69])} บรรลุเป้า ${fmtNum(r.target[69])}`
  );
  const opportunities = rows69.filter(r => evalStatus(r, 69) === 'ไม่บรรลุ').slice(0, 10).map(r =>
    `⚠️ <strong>${r.pillar} ${r.kpi}:</strong> ปี 2569 = ${fmtNum(r.actual[69])} เป้า ${fmtNum(r.target[69])} ควรวิเคราะห์สาเหตุและกำหนดผู้รับผิดชอบติดตาม`
  );
  const systemic = [
    `🔗 <strong>Data completeness:</strong> มีข้อมูลผลดำเนินงานปี 2569 จำนวน ${rows69.length} รายการจากทั้งหมด ${RAW_DATA.length} รายการ`,
    '🔗 <strong>P1→P2:</strong> ผลลัพธ์การป้องกันโรคสำคัญเชื่อมต่อกับภาระโรคและการเสียชีวิตในกลุ่ม NCD/Stroke/ACS',
    '🔗 <strong>P4→P6:</strong> คุณภาพบริการและมาตรฐานคลินิกส่งผลต่อ CMI, Adj-RW และเสถียรภาพทางการเงิน',
    '🔗 <strong>P7→ทุกยุทธศาสตร์:</strong> กำลังคนและ CQI/R2R เป็นปัจจัยสนับสนุนการบรรลุ KPI รายยุทธศาสตร์'
  ];

  function buildList(id, items) {
    const el = document.getElementById(id);
    el.innerHTML = (items.length ? items : ['➖ ยังไม่มีข้อมูลเพียงพอ']).map(i => `<li><span>•</span><span>${i}</span></li>`).join('');
  }
  buildList('hlStrengths', strengths);
  buildList('hlOpportunities', opportunities);
  buildList('hlSystemic', systemic);
}

// ════════════════════════════════════════════════════════════
// RECOMMENDATIONS
// ════════════════════════════════════════════════════════════
function buildRecommendations() {
  const failing = RAW_DATA.filter(r => r.actual[69] !== null && r.actual[69] !== undefined && r.actual[69] !== '' && evalStatus(r, 69) === 'ไม่บรรลุ').slice(0, 5);
  const recs = failing.map(r => ({
    title: `จัดทำ Action Plan ปี 2569: ${r.pillar} ${r.kpi}`,
    detail: `${r.okr} มีผลปี 2569 = ${fmtNum(r.actual[69])} เทียบเป้า ${fmtNum(r.target[69])} ผู้รับผิดชอบ: ${r.owner || 'ควรกำหนดเจ้าภาพ'} ควรวิเคราะห์ gap รายไตรมาสและติดตามในการประชุมบริหาร`
  }));
  recs.push({
    title: 'ยกระดับระบบ Dashboard รายไตรมาส',
    detail: 'ข้อมูลปี 2569 เป็นช่วง ต.ค.–มี.ค. ควรกำหนดรอบอัปเดตทุกไตรมาส ระบุเจ้าภาพข้อมูล และตรวจสอบ KPI ที่ยังไม่มีผลดำเนินงานก่อนใช้เป็นเอกสารทางการ'
  });

  const el = document.getElementById('recList');
  el.innerHTML = recs.map((r, i) => `
    <div class="rec-card">
      <div class="rec-num">${i + 1}</div>
      <div class="rec-content">
        <div class="rec-title">${r.title}</div>
        <div class="rec-detail">${r.detail}</div>
      </div>
    </div>
  `).join('');
}

// ════════════════════════════════════════════════════════════
// NAV SCROLL
// ════════════════════════════════════════════════════════════
function scrollToSection(id) {
  const el = document.getElementById(id);
  if (el) {
    const offset = el.getBoundingClientRect().top + window.pageYOffset - 50;
    window.scrollTo({ top: offset, behavior: 'smooth' });
  }
}

// highlight active nav on scroll
const sectionIds = ['summary','pillars','table','charts','highlights','recs'];
window.addEventListener('scroll', () => {
  let current = sectionIds[0];
  sectionIds.forEach(id => {
    const el = document.getElementById(id);
    if (el && el.getBoundingClientRect().top < 120) current = id;
  });
  document.querySelectorAll('.nav-btn').forEach((btn, i) => {
    btn.classList.toggle('active', sectionIds[i] === current);
  });
});

// ════════════════════════════════════════════════════════════
// INIT
// ════════════════════════════════════════════════════════════
document.addEventListener('DOMContentLoaded', () => {
  buildSummary();
  buildPillars();
  buildTable(RAW_DATA);
  buildHighlights();
  buildRecommendations();

  // Charts – with CDN fallback check
  if (typeof Chart !== 'undefined') {
    buildStatusChart();
    buildKpiSelector();
    buildTrendChart();
    buildHeatmap();
  } else {
    document.getElementById('charts').innerHTML = `
      <div style="padding:40px;text-align:center;background:#fff;border-radius:12px;box-shadow:var(--shadow)">
        <p style="font-size:16px;color:var(--text-muted)">⚠️ ไม่สามารถโหลด Chart.js ได้ (อาจไม่มีการเชื่อมต่ออินเทอร์เน็ต)<br>กราฟจะแสดงได้เมื่อมีการเชื่อมต่อ</p>
      </div>`;
  }
  document.getElementById('filterCount').textContent = `แสดง ${RAW_DATA.length} รายการ`;
});
</script>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v833ccba57c9e4d2798f2e76cebdd09a11778172276447" integrity="sha512-57MDmcccJXYtNnH+ZiBwzC4jb2rvgVCEokYN+L/nLlmO8rfYT/gIpW2A569iJ/3b+0UEasghjuZH/ma3wIs/EQ==" data-cf-beacon='{"version":"2024.11.0","token":"f90a79f4a0d64129aa8b9445b8d95ffc","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>

Youez - 2016 - github.com/yon3zu
LinuXploit