{"id":645,"date":"2024-12-03T20:04:06","date_gmt":"2024-12-03T12:04:06","guid":{"rendered":"http:\/\/172.104.110.232\/wordpress\/?page_id=645"},"modified":"2025-01-21T16:36:18","modified_gmt":"2025-01-21T08:36:18","slug":"%e5%9b%9b%e6%88%bf%e5%aa%bd%e4%bd%ba%e7%a5%9637%e4%b8%96%e7%a5%96%e8%ad%9c%e6%a8%b9%e7%8b%80%e5%9c%96","status":"publish","type":"page","link":"https:\/\/chenclan.com.tw\/?page_id=645","title":{"rendered":"\u56db\u623f\u5abd\u4f7a\u7956(37\u4e16)\u7956\u8b5c\u6a39\u72c0\u5716"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Family Tree with Search<\/title>\n    <link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jstree\/3.3.12\/themes\/default\/style.min.css\">\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jquery\/3.6.0\/jquery.min.js\"><\/script>\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jstree\/3.3.12\/jstree.min.js\"><\/script>\n    <style>\n        #familyTree {\n            max-height: 500px;\n            overflow-x: auto;\n            overflow-y: auto;\n            border: 1px solid #ccc;\n            padding: 10px;\n        }\n\n        .search-container {\n            display: flex;\n            align-items: center;\n            gap: 10px;\n            margin-bottom: 10px;\n        }\n\n        #searchBox {\n            flex: 1;\n            padding: 5px;\n        }\n\n        #searchButton {\n            padding: 5px 10px;\n            cursor: pointer;\n        }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"search-container\">\n        <input type=\"text\" id=\"searchBox\" placeholder=\"\u8f38\u5165\u540d\u7a31\u641c\u5c0b...\" \/>\n        <button id=\"searchButton\">\u641c\u5c0b<\/button>\n    <\/div>\n    <div id=\"familyTree\"><\/div>\n\n    <script>\n        function chineseToNumber(chineseNumber) {\n            if (!chineseNumber || !\/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341]+$\/.test(chineseNumber)) return NaN;\n            const chineseDigits = { '\u4e00': 1, '\u4e8c': 2, '\u4e09': 3, '\u56db': 4, '\u4e94': 5, '\u516d': 6, '\u4e03': 7, '\u516b': 8, '\u4e5d': 9, '\u5341': 10 };\n            let result = 0, temp = 0;\n\n            for (let char of chineseNumber) {\n                if (char === '\u5341') {\n                    temp = temp === 0 ? 10 : temp * 10;\n                } else {\n                    temp += chineseDigits[char] || 0;\n                }\n            }\n            return result + temp;\n        }\n\n        function combineColumns(row) {\n            const combinedInfo = row.slice(3, 11)\n                .filter(value => value.trim())\n                .map(value => `(${value.trim()})`)\n                .join(\"\");\n            return `${row[2]?.trim() || \"\u672a\u77e5\u7bc0\u9ede\"}${combinedInfo}`;\n        }\n\n        function parseCSV(csvContent) {\n            const rows = csvContent.trim().split(\"\\n\").map(row => row.split(\",\").map(col => col.trim()));\n            const errors = [];\n            const data = rows.map((row, index) => {\n                const id = row[1]?.trim() || null;\n                const name = combineColumns(row);\n                const generation = chineseToNumber(row[14]?.trim());\n                const parentId = row[15]?.trim() || null;\n\n                if (!id) {\n                    errors.push(`\u7b2c ${index + 1} \u884c\u7f3a\u5c11 ID: ${row}`);\n                }\n                if (isNaN(generation)) {\n                    errors.push(`\u7b2c ${index + 1} \u884c\u7121\u6cd5\u89e3\u6790\u4e16\u4ee3: ${row}`);\n                }\n                return { id, name, generation, parentId };\n            });\n\n            const validData = data.filter(row => row.id && !isNaN(row.generation));\n            if (errors.length > 0) {\n                console.warn(\"\u7121\u6548\u6578\u64da\uff1a\", errors);\n                alert(`\u767c\u73fe\u4ee5\u4e0b\u932f\u8aa4\uff1a\\n${errors.join(\"\\n\")}`);\n            }\n\n            const missingParents = validData.filter(row => row.parentId && !validData.some(d => d.id === row.parentId));\n            if (missingParents.length > 0) {\n                const missingMessages = missingParents.map(row => `\u7bc0\u9ede ${row.name} (ID: ${row.id}) \u7684\u7236\u7bc0\u9ede ${row.parentId} \u7121\u6548`);\n                console.warn(\"\u7121\u6548\u7684\u7236\u7bc0\u9ede\uff1a\", missingMessages);\n                \/\/alert(`\u7121\u6548\u7684\u7236\u7bc0\u9ede\uff1a\\n${missingMessages.join(\"\\n\")}`);\n            }\n\n            return validData;\n        }\n\n        function buildTree(data) {\n            const nodeMap = {};\n            const tree = [];\n\n            data.forEach(row => {\n                nodeMap[row.id] = { \n                    id: row.id, \n                    text: `${row.name} (${row.generation})`, \n                    children: [], \n                    icon: \"jstree-file\", \/\/ \u9810\u8a2d\u5716\u793a\n                    state: { opened: true } \/\/ \u9810\u8a2d\u5c55\u958b\u7bc0\u9ede\n                };\n            });\n\n            data.forEach(row => {\n                if (row.parentId && nodeMap[row.parentId]) {\n                    nodeMap[row.parentId].children.push(nodeMap[row.id]);\n                    nodeMap[row.parentId].icon = \"jstree-folder\"; \/\/ \u6709\u5b50\u7bc0\u9ede\u5247\u4f7f\u7528\u6587\u4ef6\u593e\u5716\u793a\n                } else if (!row.parentId) {\n                    tree.push(nodeMap[row.id]); \/\/ \u6839\u7bc0\u9ede\n                }\n            });\n\n            return tree;\n        }\n\n        function initializeTree(treeData) {\n            const $tree = $('#familyTree').jstree({ \n                'core': { 'data': treeData }, \n                'plugins': [\"search\"] \n            });\n\n            $('#searchButton').on('click', function () {\n                const searchText = $('#searchBox').val().trim().replace(\/\\s+\/g, \" \");\n                if (!searchText) {\n                    alert(\"\u8acb\u8f38\u5165\u540d\u7a31\u9032\u884c\u641c\u5c0b\uff01\");\n                    return;\n                }\n                $tree.jstree(true).search(searchText);\n            });\n\n            $('#searchBox').on('keypress', function (event) {\n                if (event.key === 'Enter') $('#searchButton').click();\n            });\n        }\n\n        $(document).ready(function () {\n            fetch(\"\/wp-content\/uploads\/2024\/12\/\u56db\u5abd\u4f7a\u795637\u4e16.csv\")\n                .then(response => {\n                    if (!response.ok) throw new Error(\"\u7121\u6cd5\u52a0\u8f09 CSV \u6587\u4ef6\uff01\");\n                    return response.text();\n                })\n                .then(csvContent => {\n                    const data = parseCSV(csvContent);\n                    const treeData = buildTree(data);\n                    if (treeData.length === 0) throw new Error(\"CSV \u6587\u4ef6\u4e2d\u7121\u6709\u6548\u6578\u64da\uff01\");\n                    initializeTree(treeData);\n                })\n                .catch(err => {\n                    console.error(err);\n                    alert(`\u932f\u8aa4\uff1a${err.message}`);\n                });\n        });\n    <\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Family Tree with Search \u641c&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/chenclan.com.tw\/?page_id=645\">\u95b1\u8b80\u5168\u6587<span class=\"screen-reader-text\">\u56db\u623f\u5abd\u4f7a\u7956(37\u4e16)\u7956\u8b5c\u6a39\u72c0\u5716<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":6,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-645","page","type-page","status-publish","hentry","entry"],"_links":{"self":[{"href":"https:\/\/chenclan.com.tw\/index.php?rest_route=\/wp\/v2\/pages\/645","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chenclan.com.tw\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/chenclan.com.tw\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/chenclan.com.tw\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/chenclan.com.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=645"}],"version-history":[{"count":8,"href":"https:\/\/chenclan.com.tw\/index.php?rest_route=\/wp\/v2\/pages\/645\/revisions"}],"predecessor-version":[{"id":883,"href":"https:\/\/chenclan.com.tw\/index.php?rest_route=\/wp\/v2\/pages\/645\/revisions\/883"}],"wp:attachment":[{"href":"https:\/\/chenclan.com.tw\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=645"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}