{"id":12702,"date":"2026-02-04T10:27:12","date_gmt":"2026-02-04T03:27:12","guid":{"rendered":"https:\/\/www.doa.go.th\/rubberfund\/?page_id=12702"},"modified":"2026-02-18T17:54:52","modified_gmt":"2026-02-18T10:54:52","slug":"budget","status":"publish","type":"page","link":"https:\/\/www.doa.go.th\/rubberfund\/budget\/","title":{"rendered":"Budget"},"content":{"rendered":"<div class=\"gb-container gb-container-e1211399 alignwide\">\n\n<!DOCTYPE html>\n<html lang=\"th\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Budget Dashboard &#8211; \u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e2a\u0e32\u0e23\u0e2a\u0e19\u0e40\u0e17\u0e28\u0e14\u0e49\u0e32\u0e19\u0e01\u0e32\u0e23\u0e40\u0e07\u0e34\u0e19<\/title>\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"><\/script>\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&#038;family=Sarabun:wght@300;400;500;700&#038;display=swap\" rel=\"stylesheet\">\n    <style>\n        body { \n            font-family: 'Inter', 'Sarabun', sans-serif; \n            background-color: #0f172a; \n            color: #f1f5f9; \n            margin: 0;\n            padding: 0;\n        }\n        .card { \n            background: #1e293b; \n            border-radius: 1rem; \n            box-shadow: 0 10px 15px -3px rgb(0 0 0 \/ 0.3); \n            transition: transform 0.2s, box-shadow 0.2s;\n            border: 1px solid #334155; \n        }\n        .card:hover { \n            transform: translateY(-2px); \n            box-shadow: 0 20px 25px -5px rgb(0 0 0 \/ 0.4);\n        }\n        .status-dot {\n            height: 8px;\n            width: 8px;\n            border-radius: 50%;\n            display: inline-block;\n            margin-right: 6px;\n        }\n        ::-webkit-scrollbar { width: 8px; }\n        ::-webkit-scrollbar-track { background: #0f172a; }\n        ::-webkit-scrollbar-thumb { background: #334155; border-radius: 10px; }\n        ::-webkit-scrollbar-thumb:hover { background: #475569; }\n        \n        @keyframes pulse-custom {\n            0%, 100% { opacity: 1; }\n            50% { opacity: 0.5; }\n        }\n        .animate-pulse-custom {\n            animation: pulse-custom 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n        }\n    <\/style>\n<\/head>\n<body class=\"px-4 pb-8 pt-6 md:px-8 md:pt-10\">\n    <div class=\"max-w-7xl mx-auto\">\n        <!-- Header -->\n        <header class=\"flex flex-col md:flex-row md:items-center justify-between mb-8 gap-4\">\n            <div>\n                <h1 class=\"text-2xl md:text-3xl font-extrabold text-white tracking-tight\">\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e2a\u0e32\u0e23\u0e2a\u0e19\u0e40\u0e17\u0e28\u0e14\u0e49\u0e32\u0e19\u0e01\u0e32\u0e23\u0e40\u0e07\u0e34\u0e19 \u0e41\u0e25\u0e30\u0e01\u0e32\u0e23\u0e1a\u0e23\u0e34\u0e2b\u0e32\u0e23\u0e07\u0e1a\u0e1b\u0e23\u0e30\u0e21\u0e32\u0e13<\/h1>\n                <p class=\"text-slate-400 mt-1 flex items-center text-sm\">\n                    <span id=\"connectionStatus\" class=\"status-dot bg-slate-500\"><\/span>\n                    <span id=\"statusText\">\u0e01\u0e33\u0e25\u0e31\u0e07\u0e40\u0e23\u0e34\u0e48\u0e21\u0e23\u0e30\u0e1a\u0e1a&#8230;<\/span>\n                <\/p>\n            <\/div>\n            <div class=\"flex gap-3\">\n                <button id=\"refreshBtn\" onclick=\"fetchData()\" class=\"px-5 py-2.5 bg-blue-600 text-white font-semibold rounded-xl hover:bg-blue-500 flex items-center gap-2 transition-all shadow-lg active:scale-95 disabled:opacity-50 text-sm\">\n                    <svg id=\"refreshIcon\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"18\" height=\"18\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n                        <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" \/>\n                    <\/svg>\n                    \u0e23\u0e35\u0e40\u0e1f\u0e23\u0e0a\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\n                <\/button>\n            <\/div>\n        <\/header>\n\n        <!-- Stats Overview -->\n        <div class=\"grid grid-cols-1 md:grid-cols-3 gap-6 mb-8\">\n            <div class=\"card p-6 flex items-center justify-between border-l-4 border-blue-500\">\n                <div class=\"min-w-0\">\n                    <p class=\"text-[11px] font-bold text-slate-400 uppercase tracking-widest\">\u0e07\u0e1a\u0e1b\u0e23\u0e30\u0e21\u0e32\u0e13\u0e23\u0e27\u0e21<\/p>\n                    <h3 class=\"text-2xl md:text-3xl font-black text-white mt-1 truncate\" id=\"totalBudget\">\u0e3f0.00<\/h3>\n                <\/div>\n                <div class=\"bg-blue-900\/30 p-3 rounded-2xl text-blue-400\">\n                    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"28\" height=\"28\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" \/><\/svg>\n                <\/div>\n            <\/div>\n\n            <div class=\"card p-6 flex items-center justify-between border-l-4 border-emerald-500\">\n                <div class=\"min-w-0\">\n                    <p class=\"text-[11px] font-bold text-slate-400 uppercase tracking-widest\">\u0e40\u0e1a\u0e34\u0e01\u0e08\u0e48\u0e32\u0e22\u0e41\u0e25\u0e49\u0e27\u0e08\u0e23\u0e34\u0e07<\/p>\n                    <h3 class=\"text-2xl md:text-3xl font-black text-white mt-1 truncate\" id=\"spentAmount\">\u0e3f0.00<\/h3>\n                <\/div>\n                <div class=\"bg-emerald-900\/30 p-3 rounded-2xl text-emerald-400\">\n                    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"28\" height=\"28\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" \/><\/svg>\n                <\/div>\n            <\/div>\n\n            <div class=\"card p-6 border-l-4 border-orange-500\">\n                <div class=\"flex items-center justify-between mb-2\">\n                    <p class=\"text-[11px] font-bold text-slate-400 uppercase tracking-widest\">\u0e23\u0e49\u0e2d\u0e22\u0e25\u0e30\u0e01\u0e32\u0e23\u0e40\u0e1a\u0e34\u0e01\u0e08\u0e48\u0e32\u0e22<\/p>\n                    <span id=\"spentPercent\" class=\"text-2xl font-black text-orange-400\">0.00%<\/span>\n                <\/div>\n                <div class=\"w-full bg-slate-700 rounded-full h-3 overflow-hidden\">\n                    <div id=\"spentProgressBar\" class=\"bg-orange-500 h-full rounded-full transition-all duration-1000 shadow-[0_0_12px_rgba(249,115,22,0.5)]\" style=\"width: 0%\"><\/div>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- Charts Grid 1 -->\n        <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8\">\n            <div class=\"card p-6 flex flex-col\">\n                <h4 class=\"text-base font-bold text-slate-200 mb-6 flex items-center gap-2\">\n                    <span class=\"w-2 h-2 bg-blue-500 rounded-full\"><\/span>\n                    \u0e2a\u0e31\u0e14\u0e2a\u0e48\u0e27\u0e19\u0e2b\u0e21\u0e27\u0e14\u0e2b\u0e21\u0e39\u0e48\u0e07\u0e1a\u0e1b\u0e23\u0e30\u0e21\u0e32\u0e13\n                <\/h4>\n                <div class=\"flex-grow flex items-center justify-center min-h-[300px]\">\n                    <canvas id=\"categoryPieChart\"><\/canvas>\n                <\/div>\n            <\/div>\n\n            <div class=\"card p-6 flex flex-col\">\n                <h4 class=\"text-base font-bold text-slate-200 mb-6 flex items-center gap-2\">\n                    <span class=\"w-2 h-2 bg-emerald-500 rounded-full\"><\/span>\n                    \u0e40\u0e1a\u0e34\u0e01\u0e08\u0e48\u0e32\u0e22\u0e2a\u0e30\u0e2a\u0e21\u0e41\u0e22\u0e01\u0e15\u0e32\u0e21\u0e1b\u0e23\u0e30\u0e40\u0e20\u0e17\n                <\/h4>\n                <div class=\"flex-grow min-h-[300px]\">\n                    <canvas id=\"quarterlyCumulativeChart\"><\/canvas>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- Charts Grid 2 -->\n        <div class=\"grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8\">\n            <div class=\"card p-6 flex flex-col\">\n                <h4 class=\"text-base font-bold text-slate-200 mb-6 flex items-center gap-2\">\n                    <span class=\"w-2 h-2 bg-cyan-500 rounded-full\"><\/span>\n                    \u0e41\u0e1c\u0e19 vs \u0e1c\u0e25\n                <\/h4>\n                <div class=\"flex-grow min-h-[300px]\">\n                    <canvas id=\"planVsActualChart\"><\/canvas>\n                <\/div>\n            <\/div>\n\n            <div class=\"card p-6 flex flex-col\">\n                <h4 class=\"text-base font-bold text-slate-200 mb-6 flex items-center gap-2\">\n                    <span class=\"w-2 h-2 bg-indigo-500 rounded-full\"><\/span>\n                    \u0e1c\u0e25\u0e01\u0e32\u0e23\u0e40\u0e1a\u0e34\u0e01\u0e08\u0e48\u0e32\u0e22\u0e40\u0e17\u0e35\u0e22\u0e1a 2 \u0e1b\u0e35\u0e22\u0e49\u0e2d\u0e19\u0e2b\u0e25\u0e31\u0e07(%) \n                <\/h4>\n                <div class=\"flex-grow min-h-[300px]\">\n                    <canvas id=\"threeYearCompareChart\"><\/canvas>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- Footer -->\n        <footer class=\"text-center py-12 border-t border-slate-800\">\n            <p class=\"text-slate-500 text-xs font-medium uppercase tracking-widest\">\n                \u0e2d\u0e31\u0e1b\u0e40\u0e14\u0e15\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14\u0e40\u0e21\u0e37\u0e48\u0e2d: <span id=\"lastUpdate\" class=\"text-slate-300\">&#8211;<\/span>\n            <\/p>\n        <\/footer>\n    <\/div>\n\n    <script>\n        const API_URL = \"https:\/\/script.google.com\/macros\/s\/AKfycbzh_HEdO6H9zD4_v-gBZHEsZt9HjrKVEzZmssmQjsTAUOyjIpP2hWjubjOp9q4t-cxeqA\/exec\";\n        let activeCharts = {};\n\n        const formatCurrency = (val) => new Intl.NumberFormat('th-TH', { style: 'currency', currency: 'THB' }).format(val || 0);\n        const formatShort = (val) => {\n            if (val >= 1e6) return (val \/ 1e6).toFixed(2) + 'M';\n            return new Intl.NumberFormat('th-TH').format(val);\n        };\n\n        async function fetchData() {\n            const btn = document.getElementById('refreshBtn');\n            const icon = document.getElementById('refreshIcon');\n            const statusDot = document.getElementById('connectionStatus');\n            const statusText = document.getElementById('statusText');\n\n            btn.disabled = true;\n            icon.classList.add('animate-spin');\n            statusDot.className = 'status-dot bg-blue-500 animate-pulse-custom';\n            statusText.innerText = '\u0e01\u0e33\u0e25\u0e31\u0e07\u0e14\u0e36\u0e07\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14...';\n\n            try {\n                const res = await fetch(API_URL);\n                if (!res.ok) throw new Error('Network response was not ok');\n                const data = await res.json();\n                updateDashboard(data);\n                statusDot.className = 'status-dot bg-emerald-500';\n                statusText.innerText = '\u0e40\u0e0a\u0e37\u0e48\u0e2d\u0e21\u0e15\u0e48\u0e2d\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e2a\u0e33\u0e40\u0e23\u0e47\u0e08';\n                document.getElementById('lastUpdate').innerText = new Date().toLocaleString('th-TH');\n            } catch (err) {\n                console.error('API Error:', err);\n                statusDot.className = 'status-dot bg-rose-500';\n                statusText.innerText = '\u0e40\u0e01\u0e34\u0e14\u0e02\u0e49\u0e2d\u0e1c\u0e34\u0e14\u0e1e\u0e25\u0e32\u0e14\u0e43\u0e19\u0e01\u0e32\u0e23\u0e42\u0e2b\u0e25\u0e14\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25';\n            } finally {\n                btn.disabled = false;\n                icon.classList.remove('animate-spin');\n            }\n        }\n\n        function updateDashboard(data) {\n            if (!data) return;\n            document.getElementById('totalBudget').innerText = formatCurrency(data.totalBudget);\n            document.getElementById('spentAmount').innerText = formatCurrency(data.spentAmount);\n            const ratio = (data.totalBudget > 0) ? (data.spentAmount \/ data.totalBudget) * 100 : 0;\n            document.getElementById('spentPercent').innerText = ratio.toFixed(2) + '%';\n            setTimeout(() => {\n                document.getElementById('spentProgressBar').style.width = Math.min(ratio, 100) + '%';\n            }, 200);\n            renderCharts(data);\n        }\n\n        function renderCharts(data) {\n            Chart.defaults.font.family = \"'Inter', 'Sarabun'\";\n            Chart.defaults.color = '#94a3b8';\n            Chart.defaults.borderColor = 'rgba(51, 65, 85, 0.5)';\n\n            \/\/ 1. Pie Chart\n            createChart('categoryPieChart', 'pie', {\n                labels: ['\u0e07\u0e1a\u0e25\u0e07\u0e17\u0e38\u0e19', '\u0e07\u0e1a\u0e14\u0e33\u0e40\u0e19\u0e34\u0e19\u0e07\u0e32\u0e19', '\u0e07\u0e1a\u0e1a\u0e38\u0e04\u0e25\u0e32\u0e01\u0e23'],\n                datasets: [{\n                    data: [data.categories?.investment, data.categories?.operation, data.categories?.personnel],\n                    backgroundColor: ['#3b82f6', '#10b981', '#f59e0b'],\n                    borderWidth: 2,\n                    borderColor: '#1e293b'\n                }]\n            }, {\n                plugins: {\n                    legend: { position: 'bottom', labels: { padding: 20, usePointStyle: true, color: '#f1f5f9' } },\n                    tooltip: {\n                        callbacks: {\n                            label: function(context) {\n                                let label = context.label || '';\n                                if (label) label += ': ';\n                                if (context.parsed !== null) {\n                                    const val = context.parsed;\n                                    const total = context.dataset.data.reduce((a, b) => a + b, 0);\n                                    const pc = ((val \/ total) * 100).toFixed(2);\n                                    label += formatShort(val) + ' (' + pc + '%)';\n                                }\n                                return label;\n                            }\n                        }\n                    }\n                }\n            });\n\n            \/\/ 2. Cumulative Bar\n            createChart('quarterlyCumulativeChart', 'bar', {\n                labels: ['Q1', 'Q2', 'Q3', 'Q4'],\n                datasets: [\n                    { label: '\u0e07\u0e1a\u0e25\u0e07\u0e17\u0e38\u0e19', data: data.quarterlyCumulative?.investment, backgroundColor: '#3b82f6' },\n                    { label: '\u0e07\u0e1a\u0e14\u0e33\u0e40\u0e19\u0e34\u0e19\u0e07\u0e32\u0e19', data: data.quarterlyCumulative?.operation, backgroundColor: '#10b981' },\n                    { label: '\u0e07\u0e1a\u0e1a\u0e38\u0e04\u0e25\u0e32\u0e01\u0e23', data: data.quarterlyCumulative?.personnel, backgroundColor: '#f59e0b' }\n                ]\n            }, {\n                scales: { \n                    y: { stacked: true, ticks: { callback: v => formatShort(v) } },\n                    x: { stacked: true }\n                }\n            });\n\n            \/\/ 3. Plan vs Actual\n            createChart('planVsActualChart', 'bar', {\n                labels: ['Q1', 'Q2', 'Q3', 'Q4'],\n                datasets: [\n                    { label: '\u0e41\u0e1c\u0e19\u0e07\u0e32\u0e19', data: data.planVsActual?.plan, backgroundColor: 'rgba(71, 85, 105, 0.4)', borderRadius: 6 },\n                    { label: '\u0e40\u0e1a\u0e34\u0e01\u0e08\u0e48\u0e32\u0e22\u0e08\u0e23\u0e34\u0e07', data: data.planVsActual?.actual, backgroundColor: '#22d3ee', borderRadius: 6 }\n                ]\n            }, {\n                scales: { y: { ticks: { callback: v => formatShort(v) } } },\n                plugins: {\n                    tooltip: {\n                        callbacks: {\n                            label: function(context) {\n                                let label = context.dataset.label || '';\n                                if (label) label += ': ';\n                                if (context.parsed.y !== null) {\n                                    const val = context.parsed.y;\n                                    const totalBudget = data.totalBudget || 1;\n                                    const pc = ((val \/ totalBudget) * 100).toFixed(2);\n                                    label += formatShort(val) + ' (' + pc + '%)';\n                                }\n                                return label;\n                            }\n                        }\n                    }\n                }\n            });\n\n            \/\/ 4. Three Year Comparison\n            const normalize = (arr) => arr?.map(v => (v > 100 && data.totalBudget > 0) ? (v \/ data.totalBudget * 100) : v);\n            createChart('threeYearCompareChart', 'bar', {\n                labels: ['Q1', 'Q2', 'Q3', 'Q4'],\n                datasets: [\n                    { label: '\u0e1b\u0e35 2567', data: normalize(data.threeYear?.y2565), backgroundColor: '#6366f1', borderRadius: 4 },\n                    { label: '\u0e1b\u0e35 2568', data: normalize(data.threeYear?.y2566), backgroundColor: '#f43f5e', borderRadius: 4 },\n                    { label: '\u0e1b\u0e35 2569', data: normalize(data.threeYear?.y2567), backgroundColor: '#f59e0b', borderRadius: 4 }\n                ]\n            }, {\n                scales: { y: { max: 100, ticks: { callback: v => v + '%' } } },\n                plugins: {\n                    tooltip: {\n                        callbacks: {\n                            label: function(context) {\n                                let label = context.dataset.label || '';\n                                if (label) label += ': ';\n                                if (context.parsed.y !== null) {\n                                    label += Number(context.parsed.y).toFixed(2) + '%';\n                                }\n                                return label;\n                            }\n                        }\n                    }\n                }\n            });\n        }\n\n        function createChart(id, type, data, options) {\n            if (activeCharts[id]) activeCharts[id].destroy();\n            const canvas = document.getElementById(id);\n            if (!canvas) return;\n            const ctx = canvas.getContext('2d');\n            activeCharts[id] = new Chart(ctx, {\n                type,\n                data,\n                options: {\n                    responsive: true,\n                    maintainAspectRatio: false,\n                    ...options,\n                    plugins: {\n                        ...options.plugins,\n                        tooltip: {\n                            backgroundColor: '#0f172a',\n                            titleColor: '#fff',\n                            bodyColor: '#cbd5e1',\n                            padding: 12,\n                            borderColor: '#334155',\n                            borderWidth: 1,\n                            ...options.plugins?.tooltip\n                        }\n                    }\n                }\n            });\n        }\n\n        window.addEventListener('load', fetchData);\n    <\/script>\n<\/body>\n<\/html>\n\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Budget Dashboard &#8211; \u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e2a\u0e32\u0e23\u0e2a\u0e19\u0e40\u0e17\u0e28\u0e14\u0e49\u0e32\u0e19\u0e01\u0e32\u0e23\u0e40\u0e07\u0e34\u0e19 \u0e02\u0e49\u0e2d\u0e21 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"_acf_changed":false,"_eb_attr":"","footnotes":""},"class_list":["post-12702","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.doa.go.th\/rubberfund\/wp-json\/wp\/v2\/pages\/12702","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.doa.go.th\/rubberfund\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.doa.go.th\/rubberfund\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.doa.go.th\/rubberfund\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doa.go.th\/rubberfund\/wp-json\/wp\/v2\/comments?post=12702"}],"version-history":[{"count":9,"href":"https:\/\/www.doa.go.th\/rubberfund\/wp-json\/wp\/v2\/pages\/12702\/revisions"}],"predecessor-version":[{"id":13112,"href":"https:\/\/www.doa.go.th\/rubberfund\/wp-json\/wp\/v2\/pages\/12702\/revisions\/13112"}],"wp:attachment":[{"href":"https:\/\/www.doa.go.th\/rubberfund\/wp-json\/wp\/v2\/media?parent=12702"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}