{"id":153,"date":"2026-09-12T09:01:54","date_gmt":"2026-09-12T01:01:54","guid":{"rendered":"https:\/\/annion.kingbig.idv.tw\/wedding\/?page_id=153"},"modified":"2026-09-12T09:01:54","modified_gmt":"2026-09-12T01:01:54","slug":"wedding-table-calculator","status":"publish","type":"page","link":"https:\/\/wedplan.tw\/?page_id=153","title":{"rendered":"\u5a5a\u5bb4\u684c\u6578\u8a66\u7b97\u5668"},"content":{"rendered":"        <div\n            id=\"wtc-44941\"\n            class=\"wtc-wrap\"\n            data-wtc\n            data-ajax-url=\"https:\/\/wedplan.tw\/wp-admin\/admin-ajax.php\"\n            data-nonce=\"9ea46f2d28\"\n            data-confirmed=\"0\"\n            data-project-guests=\"0\"\n        >\n            <style>\n            #wtc-44941{\n                --wtc-bg:#fffaf7;\n                --wtc-card:#ffffff;\n                --wtc-line:#eadfd9;\n                --wtc-text:#302725;\n                --wtc-muted:#6d625e;\n                --wtc-accent:#9d5e55;\n                --wtc-accent-dark:#7f4942;\n                --wtc-soft:#f7eeea;\n                --wtc-good:#356b51;\n                max-width:920px;\n                margin:24px auto;\n                color:var(--wtc-text);\n                font-size:16px;\n                line-height:1.65;\n            }\n            #wtc-44941 *{box-sizing:border-box}\n            #wtc-44941 .wtc-hero{\n                padding:28px;\n                border:1px solid var(--wtc-line);\n                border-radius:18px;\n                background:linear-gradient(135deg,#fffaf7 0%,#fff 100%);\n                margin-bottom:18px;\n            }\n            #wtc-44941 .wtc-kicker{\n                margin:0 0 6px;\n                font-size:15px;\n                color:var(--wtc-accent-dark);\n                letter-spacing:.04em;\n            }\n            #wtc-44941 h2{\n                margin:0 0 8px;\n                font-size:30px;\n                line-height:1.25;\n            }\n            #wtc-44941 .wtc-sub{\n                margin:0;\n                color:var(--wtc-muted);\n            }\n            #wtc-44941 .wtc-grid{\n                display:grid;\n                grid-template-columns:repeat(3,minmax(0,1fr));\n                gap:16px;\n            }\n            #wtc-44941 .wtc-card{\n                border:1px solid var(--wtc-line);\n                background:var(--wtc-card);\n                border-radius:16px;\n                padding:22px;\n                margin-bottom:18px;\n            }\n            #wtc-44941 label{\n                display:block;\n                font-size:16px;\n                color:var(--wtc-text);\n            }\n            #wtc-44941 label > span{\n                display:block;\n                margin-bottom:7px;\n            }\n            #wtc-44941 input[type=\"number\"]{\n                width:100%;\n                min-height:46px;\n                border:1px solid #cfc3bd;\n                border-radius:10px;\n                padding:9px 12px;\n                background:#fff;\n                color:#2d2725;\n                font-size:17px;\n            }\n            #wtc-44941 input[type=\"number\"]:focus{\n                border-color:var(--wtc-accent);\n                outline:3px solid rgba(157,94,85,.13);\n            }\n            #wtc-44941 .wtc-help{\n                display:block;\n                margin-top:5px;\n                color:var(--wtc-muted);\n                font-size:15px;\n            }\n            #wtc-44941 .wtc-actions{\n                display:flex;\n                flex-wrap:wrap;\n                gap:10px;\n                margin-top:18px;\n            }\n            #wtc-44941 button{\n                min-height:44px;\n                border-radius:10px;\n                border:1px solid var(--wtc-accent);\n                padding:9px 16px;\n                font-size:16px;\n                cursor:pointer;\n            }\n            #wtc-44941 .wtc-primary{\n                background:var(--wtc-accent);\n                color:#fff;\n            }\n            #wtc-44941 .wtc-primary:hover{\n                background:var(--wtc-accent-dark);\n            }\n            #wtc-44941 .wtc-secondary{\n                background:#fff;\n                color:var(--wtc-accent-dark);\n            }\n            #wtc-44941 .wtc-secondary:hover{\n                background:var(--wtc-soft);\n            }\n            #wtc-44941 .wtc-result{\n                display:grid;\n                grid-template-columns:repeat(3,minmax(0,1fr));\n                gap:12px;\n                margin-top:18px;\n            }\n            #wtc-44941 .wtc-stat{\n                padding:18px;\n                border-radius:14px;\n                background:var(--wtc-soft);\n                border:1px solid var(--wtc-line);\n            }\n            #wtc-44941 .wtc-stat span{\n                display:block;\n                color:var(--wtc-muted);\n                font-size:15px;\n                margin-bottom:3px;\n            }\n            #wtc-44941 .wtc-stat strong{\n                display:block;\n                font-size:28px;\n                line-height:1.2;\n            }\n            #wtc-44941 .wtc-result-note{\n                margin:14px 0 0;\n                color:var(--wtc-muted);\n            }\n            #wtc-44941 .wtc-bridge{\n                margin-top:16px;\n                padding:16px;\n                border-radius:12px;\n                background:#fbf8f5;\n                border:1px dashed #d7c8c0;\n            }\n            #wtc-44941 .wtc-bridge p{\n                margin:0 0 10px;\n            }\n            #wtc-44941 .wtc-status{\n                margin:10px 0 0!important;\n                color:var(--wtc-good);\n                min-height:1.6em;\n            }\n            #wtc-44941 .wtc-formula{\n                margin:0;\n                padding-left:1.2em;\n                color:var(--wtc-muted);\n            }\n            #wtc-44941 .wtc-formula li+li{margin-top:6px}\n            #wtc-44941 .wtc-warning{\n                color:#8a4f25;\n            }\n            #wtc-44941 .wtc-hidden{display:none!important}\n            @media(max-width:700px){\n                #wtc-44941 .wtc-grid,\n                #wtc-44941 .wtc-result{\n                    grid-template-columns:1fr;\n                }\n                #wtc-44941 .wtc-hero,\n                #wtc-44941 .wtc-card{\n                    padding:18px;\n                }\n                #wtc-44941 h2{font-size:25px}\n            }\n            <\/style>\n\n            <section class=\"wtc-hero\">\n                <p class=\"wtc-kicker\">\u5a5a\u79ae\u898f\u5283\u5de5\u5177<\/p>\n                <h2>\u5a5a\u5bb4\u684c\u6578\u8a66\u7b97\u5668<\/h2>\n                <p class=\"wtc-sub\">\u5148\u4f30\u300c\u5be6\u969b\u8981\u958b\u5e7e\u684c\u300d\uff0c\u518d\u628a\u9810\u5099\u684c\u53e6\u5916\u7b97\u9032\u5834\u5730\u4fdd\u7559\u6578\uff0c\u907f\u514d\u684c\u6578\u6293\u592a\u7dca\u6216\u591a\u8a02\u592a\u591a\u3002<\/p>\n            <\/section>\n\n            <section class=\"wtc-card\">\n                <div class=\"wtc-grid\">\n                    <label>\n                        <span>\u8cd3\u5ba2\u540d\u55ae\u4eba\u6578<\/span>\n                        <input type=\"number\" min=\"1\" max=\"100000\" step=\"1\"\n                               value=\"120\"\n                               data-field=\"invited\">\n                        <small class=\"wtc-help\">\u82e5\u5df2\u7d93\u662f\u300c\u78ba\u5b9a\u6703\u51fa\u5e2d\u300d\u7684\u4eba\u6578\uff0c\u51fa\u5e2d\u7387\u8acb\u586b 100%\u3002<\/small>\n                    <\/label>\n\n                    <label>\n                        <span>\u9810\u4f30\u51fa\u5e2d\u7387\uff08%\uff09<\/span>\n                        <input type=\"number\" min=\"1\" max=\"100\" step=\"1\"\n                               value=\"90\"\n                               data-field=\"attendance\">\n                        <small class=\"wtc-help\">\u5c1a\u672a\u5b8c\u5168\u56de\u8986\u6642\uff0c\u53ef\u5148\u7528\u9810\u4f30\u51fa\u5e2d\u7387\u6293\u684c\u6578\u3002<\/small>\n                    <\/label>\n\n                    <label>\n                        <span>\u5de5\u4f5c\u4eba\u54e1\uff0f\u5ee0\u5546\u7528\u9910\u4eba\u6578<\/span>\n                        <input type=\"number\" min=\"0\" max=\"10000\" step=\"1\"\n                               value=\"0\"\n                               data-field=\"staff\">\n                        <small class=\"wtc-help\">\u4f8b\u5982\u5a5a\u651d\u3001\u5a5a\u9304\u3001\u4e3b\u6301\u3001\u5a5a\u4f01\u7b49\u9700\u8981\u53e6\u5916\u5b89\u6392\u5ea7\u4f4d\u7684\u4eba\u3002<\/small>\n                    <\/label>\n\n                    <label>\n                        <span>\u4e00\u822c\u684c\u6bcf\u684c\u4eba\u6578<\/span>\n                        <input type=\"number\" min=\"4\" max=\"30\" step=\"1\"\n                               value=\"10\"\n                               data-field=\"perTable\">\n                        <small class=\"wtc-help\">\u53f0\u7063\u5a5a\u5bb4\u5e38\u898b\u70ba 10 \u4eba\u6216 12 \u4eba\u4e00\u684c\uff0c\u8acb\u4f9d\u5834\u5730\u65b9\u6848\u586b\u5beb\u3002<\/small>\n                    <\/label>\n\n                    <label>\n                        <span>\u5176\u4e2d\u4e3b\u684c\u4eba\u6578<\/span>\n                        <input type=\"number\" min=\"0\" max=\"30\" step=\"1\"\n                               value=\"10\"\n                               data-field=\"mainTable\">\n                        <small class=\"wtc-help\">\u4e3b\u684c\u5df2\u5305\u542b\u5728\u8cd3\u5ba2\u4eba\u6578\u5167\uff1b\u6c92\u6709\u7368\u7acb\u4e3b\u684c\u53ef\u586b 0\u3002<\/small>\n                    <\/label>\n\n                    <label>\n                        <span>\u9810\u5099\u684c\u6578<\/span>\n                        <input type=\"number\" min=\"0\" max=\"20\" step=\"1\"\n                               value=\"1\"\n                               data-field=\"reserve\">\n                        <small class=\"wtc-help\">\u9810\u5099\u684c\u4e0d\u8a08\u5165\u300c\u5efa\u8b70\u958b\u684c\u300d\uff0c\u53ea\u5217\u5165\u5834\u5730\u61c9\u9810\u7559\u684c\u6578\u3002<\/small>\n                    <\/label>\n                <\/div>\n\n                <div class=\"wtc-actions\">\n                    <button type=\"button\" class=\"wtc-primary\" data-action=\"calculate\">\u91cd\u65b0\u8a66\u7b97<\/button>\n\n                    \n                                    <\/div>\n\n                <div class=\"wtc-result\" aria-live=\"polite\">\n                    <div class=\"wtc-stat\">\n                        <span>\u9810\u4f30\u51fa\u5e2d\u8cd3\u5ba2<\/span>\n                        <strong><b data-result=\"estimatedGuests\">0<\/b> \u4eba<\/strong>\n                    <\/div>\n                    <div class=\"wtc-stat\">\n                        <span>\u5efa\u8b70\u5be6\u969b\u958b\u684c<\/span>\n                        <strong><b data-result=\"openTables\">0<\/b> \u684c<\/strong>\n                    <\/div>\n                    <div class=\"wtc-stat\">\n                        <span>\u5834\u5730\u61c9\u9810\u7559<\/span>\n                        <strong><b data-result=\"preparedTables\">0<\/b> \u684c<\/strong>\n                    <\/div>\n                <\/div>\n\n                <p class=\"wtc-result-note\" data-result=\"detail\"><\/p>\n\n                                    <div class=\"wtc-bridge\">\n                        <p>\u672a\u767b\u5165\u4e5f\u53ef\u4ee5\u8a66\u7b97\uff1b\u767b\u5165\u5f8c\u53ef\u5e36\u5165 RSVP \u5df2\u78ba\u8a8d\u51fa\u5e2d\u4eba\u6578\uff0c\u4e26\u628a\u684c\u6578\u5b58\u56de\u300c\u6211\u7684\u5a5a\u79ae\u300d\u3002<\/p>\n                    <\/div>\n                            <\/section>\n\n            <section class=\"wtc-card\">\n                <strong>\u9019\u500b\u8a66\u7b97\u5668\u600e\u9ebc\u7b97\uff1f<\/strong>\n                <ul class=\"wtc-formula\">\n                    <li>\u9810\u4f30\u51fa\u5e2d\u8cd3\u5ba2 = \u8cd3\u5ba2\u540d\u55ae\u4eba\u6578 \u00d7 \u51fa\u5e2d\u7387\uff0c\u63a1\u7121\u689d\u4ef6\u9032\u4f4d\u3002<\/li>\n                    <li>\u9700\u8981\u5b89\u6392\u5ea7\u4f4d\u7684\u4eba\u6578 = \u9810\u4f30\u51fa\u5e2d\u8cd3\u5ba2 + \u5de5\u4f5c\u4eba\u54e1\uff0f\u5ee0\u5546\u7528\u9910\u4eba\u6578\u3002<\/li>\n                    <li>\u6709\u4e3b\u684c\u6642\u5148\u6263\u9664\u4e3b\u684c\u4eba\u6578\uff0c\u518d\u4ee5\u4e00\u822c\u684c\u6bcf\u684c\u4eba\u6578\u5411\u4e0a\u53d6\u6574\uff0c\u6700\u5f8c\u52a0\u56de 1 \u684c\u4e3b\u684c\u3002<\/li>\n                    <li>\u300c\u5834\u5730\u61c9\u9810\u7559\u300d= \u5efa\u8b70\u5be6\u969b\u958b\u684c + \u9810\u5099\u684c\uff1b\u5132\u5b58\u5230\u300c\u6211\u7684\u5a5a\u79ae\u300d\u6642\u53ea\u4fdd\u5b58\u5be6\u969b\u958b\u684c\u6578\u3002<\/li>\n                <\/ul>\n            <\/section>\n\n            <script>\n            (function(){\n                var root = document.getElementById(\"wtc-44941\");\n                if (!root || root.dataset.wtcReady === '1') return;\n                root.dataset.wtcReady = '1';\n\n                function field(name){\n                    return root.querySelector('[data-field=\"' + name + '\"]');\n                }\n\n                function num(name, fallback){\n                    var el = field(name);\n                    if (!el) return fallback || 0;\n                    var n = Number(el.value);\n                    return Number.isFinite(n) ? n : (fallback || 0);\n                }\n\n                function clamp(n, min, max){\n                    return Math.min(max, Math.max(min, n));\n                }\n\n                function calculate(){\n                    var invited = Math.max(0, Math.round(num('invited', 0)));\n                    var attendance = clamp(num('attendance', 100), 1, 100);\n                    var staff = Math.max(0, Math.round(num('staff', 0)));\n                    var perTable = Math.max(1, Math.round(num('perTable', 10)));\n                    var mainTable = Math.max(0, Math.round(num('mainTable', 0)));\n                    var reserve = Math.max(0, Math.round(num('reserve', 0)));\n\n                    var estimatedGuests = Math.ceil(invited * attendance \/ 100);\n                    var seatTotal = estimatedGuests + staff;\n\n                    var mainGuests = Math.min(mainTable, seatTotal);\n                    var regularGuests = Math.max(0, seatTotal - mainGuests);\n                    var regularTables = regularGuests > 0 ? Math.ceil(regularGuests \/ perTable) : 0;\n                    var openTables = regularTables + (mainGuests > 0 ? 1 : 0);\n                    var preparedTables = openTables + reserve;\n\n                    var resultEstimated = root.querySelector('[data-result=\"estimatedGuests\"]');\n                    var resultOpen = root.querySelector('[data-result=\"openTables\"]');\n                    var resultPrepared = root.querySelector('[data-result=\"preparedTables\"]');\n                    var detail = root.querySelector('[data-result=\"detail\"]');\n\n                    if (resultEstimated) resultEstimated.textContent = estimatedGuests.toLocaleString('zh-TW');\n                    if (resultOpen) resultOpen.textContent = openTables.toLocaleString('zh-TW');\n                    if (resultPrepared) resultPrepared.textContent = preparedTables.toLocaleString('zh-TW');\n\n                    var parts = [];\n                    parts.push('\u9700\u5b89\u6392\u5ea7\u4f4d\u5171 ' + seatTotal.toLocaleString('zh-TW') + ' \u4eba');\n                    if (mainGuests > 0) {\n                        parts.push('\u5176\u4e2d\u4e3b\u684c ' + mainGuests.toLocaleString('zh-TW') + ' \u4eba');\n                    }\n                    parts.push('\u4e00\u822c\u684c\u7d04 ' + regularTables.toLocaleString('zh-TW') + ' \u684c');\n                    if (reserve > 0) {\n                        parts.push('\u53e6\u4fdd\u7559 ' + reserve.toLocaleString('zh-TW') + ' \u684c\u9810\u5099\u684c');\n                    }\n                    if (detail) detail.textContent = parts.join('\uff1b') + '\u3002';\n\n                    root.dataset.estimatedGuests = String(estimatedGuests);\n                    root.dataset.openTables = String(openTables);\n                    root.dataset.preparedTables = String(preparedTables);\n\n                    return {\n                        estimatedGuests: estimatedGuests,\n                        openTables: openTables,\n                        preparedTables: preparedTables\n                    };\n                }\n\n                \/\/ \u5373\u6642\u8a08\u7b97\uff1a\u9664\u4e86 input\uff0c\u518d\u76e3\u807d change \/ keyup\u3002\n                \/\/ \u67d0\u4e9b\u700f\u89bd\u5668\u6703\u5728\u91cd\u65b0\u6574\u7406\u5f8c\u81ea\u52d5\u9084\u539f\u8868\u55ae\u503c\uff0c\u4f46\u4e0d\u89f8\u767c input\uff0c\n                \/\/ \u56e0\u6b64\u53e6\u5916\u7528\u503c\u5feb\u7167\u540c\u6b65\uff0c\u907f\u514d\u756b\u9762\u986f\u793a\u820a\u7d50\u679c\u3002\n                function getFieldSnapshot(){\n                    return [\n                        field('invited') ? field('invited').value : '',\n                        field('attendance') ? field('attendance').value : '',\n                        field('staff') ? field('staff').value : '',\n                        field('perTable') ? field('perTable').value : '',\n                        field('mainTable') ? field('mainTable').value : '',\n                        field('reserve') ? field('reserve').value : ''\n                    ].join('|');\n                }\n\n                var lastSnapshot = getFieldSnapshot();\n\n                function recalcIfChanged(){\n                    var current = getFieldSnapshot();\n                    if (current !== lastSnapshot) {\n                        lastSnapshot = current;\n                        calculate();\n                    }\n                }\n\n                ['input', 'change', 'keyup'].forEach(function(eventName){\n                    root.addEventListener(eventName, function(e){\n                        if (e.target && e.target.matches('[data-field]')) {\n                            lastSnapshot = getFieldSnapshot();\n                            calculate();\n                        }\n                    });\n                });\n\n                \/\/ \u8655\u7406\u700f\u89bd\u5668\u81ea\u52d5\u586b\u503c\u3001\u8fd4\u56de\u4e0a\u4e00\u9801\u5f8c\u9084\u539f\u6b04\u4f4d\u7b49\u60c5\u6cc1\u3002\n                window.setInterval(recalcIfChanged, 400);\n\n                root.addEventListener('click', function(e){\n                    var btn = e.target.closest('[data-action]');\n                    if (!btn) return;\n\n                    var action = btn.getAttribute('data-action');\n\n                    if (action === 'calculate') {\n                        calculate();\n                        return;\n                    }\n\n                    if (action === 'load-confirmed') {\n                        var confirmed = Number(root.getAttribute('data-confirmed') || 0);\n                        if (confirmed > 0) {\n                            field('invited').value = confirmed;\n                            field('attendance').value = 100;\n                            calculate();\n                            lastSnapshot = getFieldSnapshot();\n                        }\n                        return;\n                    }\n\n                    if (action === 'load-project') {\n                        var projectGuests = Number(root.getAttribute('data-project-guests') || 0);\n                        if (projectGuests > 0) {\n                            field('invited').value = projectGuests;\n                            calculate();\n                            lastSnapshot = getFieldSnapshot();\n                        }\n                        return;\n                    }\n\n                    if (action === 'save') {\n                        var result = calculate();\n                        var status = root.querySelector('[data-status]');\n\n                        if (!result.estimatedGuests || !result.openTables) {\n                            if (status) status.textContent = '\u8acb\u5148\u8f38\u5165\u6b63\u78ba\u7684\u4eba\u6578\u5f8c\u518d\u5132\u5b58\u3002';\n                            return;\n                        }\n\n                        btn.disabled = true;\n                        if (status) status.textContent = '\u5132\u5b58\u4e2d\u2026';\n\n                        var body = new URLSearchParams();\n                        body.set('action', 'wtc_save_to_my_wedding');\n                        body.set('nonce', root.getAttribute('data-nonce') || '');\n                        body.set('guest_count', String(result.estimatedGuests));\n                        body.set('table_count', String(result.openTables));\n\n                        fetch(root.getAttribute('data-ajax-url'), {\n                            method: 'POST',\n                            credentials: 'same-origin',\n                            headers: {'Content-Type': 'application\/x-www-form-urlencoded; charset=UTF-8'},\n                            body: body.toString()\n                        })\n                        .then(function(r){ return r.json(); })\n                        .then(function(json){\n                            if (!json || !json.success) {\n                                throw new Error(json && json.data && json.data.message ? json.data.message : '\u5132\u5b58\u5931\u6557\u3002');\n                            }\n                            if (status) status.textContent = json.data.message;\n                        })\n                        .catch(function(err){\n                            if (status) status.textContent = err.message || '\u5132\u5b58\u5931\u6557\u3002';\n                        })\n                        .finally(function(){\n                            btn.disabled = false;\n                        });\n                    }\n                });\n\n                calculate();\n            })();\n            <\/script>\n        <\/div>\n        \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"_links":{"self":[{"href":"https:\/\/wedplan.tw\/index.php?rest_route=\/wp\/v2\/pages\/153"}],"collection":[{"href":"https:\/\/wedplan.tw\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/wedplan.tw\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/wedplan.tw\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wedplan.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=153"}],"version-history":[{"count":0,"href":"https:\/\/wedplan.tw\/index.php?rest_route=\/wp\/v2\/pages\/153\/revisions"}],"wp:attachment":[{"href":"https:\/\/wedplan.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}