{"id":153,"date":"2025-08-29T10:55:15","date_gmt":"2025-08-29T02:55:15","guid":{"rendered":"https:\/\/www.fbmeta.cf\/?page_id=153"},"modified":"2025-08-29T12:03:46","modified_gmt":"2025-08-29T04:03:46","slug":"%e6%b3%95%e8%80%83%e6%89%93%e5%8d%a1%e7%ab%99","status":"publish","type":"page","link":"https:\/\/www.fbmeta.eu.org\/index.php\/%e6%b3%95%e8%80%83%e6%89%93%e5%8d%a1%e7%ab%99\/","title":{"rendered":"DOG"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>\u6cd5\u8003\u5b66\u4e60\u6253\u5361\u7cfb\u7edf<\/title>\n    <style>\n        * {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n        }\n        \n        body {\n            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            min-height: 100vh;\n            padding: 20px;\n        }\n        \n        .container {\n            max-width: 1200px;\n            margin: 0 auto;\n            background: white;\n            border-radius: 20px;\n            box-shadow: 0 20px 40px rgba(0,0,0,0.1);\n            overflow: hidden;\n        }\n        \n        .header {\n            background: linear-gradient(135deg, #ff6b6b, #ee5a24);\n            color: white;\n            padding: 30px;\n            text-align: center;\n        }\n        \n        .header h1 {\n            font-size: 2.5em;\n            margin-bottom: 10px;\n            text-shadow: 0 2px 4px rgba(0,0,0,0.3);\n        }\n        \n        .user-info {\n            background: #f8f9fa;\n            padding: 20px 30px;\n            border-bottom: 2px solid #e9ecef;\n        }\n        \n        .user-form {\n            display: flex;\n            gap: 15px;\n            align-items: center;\n            flex-wrap: wrap;\n        }\n        \n        .user-form input, .user-form select {\n            padding: 12px 15px;\n            border: 2px solid #ddd;\n            border-radius: 10px;\n            font-size: 16px;\n            transition: border-color 0.3s;\n        }\n        \n        .user-form input:focus, .user-form select:focus {\n            outline: none;\n            border-color: #667eea;\n        }\n        \n        .btn {\n            background: #667eea;\n            color: white;\n            padding: 12px 25px;\n            border: none;\n            border-radius: 10px;\n            cursor: pointer;\n            font-size: 16px;\n            transition: all 0.3s;\n        }\n        \n        .btn:hover {\n            background: #5a67d8;\n            transform: translateY(-2px);\n            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);\n        }\n        \n        .stats {\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n            gap: 20px;\n            padding: 30px;\n            background: #f8f9fa;\n        }\n        \n        .stat-card {\n            background: white;\n            padding: 25px;\n            border-radius: 15px;\n            text-align: center;\n            box-shadow: 0 5px 15px rgba(0,0,0,0.08);\n            transition: transform 0.3s;\n        }\n        \n        .stat-card:hover {\n            transform: translateY(-5px);\n        }\n        \n        .stat-number {\n            font-size: 2.5em;\n            font-weight: bold;\n            color: #667eea;\n            margin-bottom: 10px;\n        }\n        \n        .stat-label {\n            color: #666;\n            font-size: 1.1em;\n        }\n        \n        .courses-grid {\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));\n            gap: 25px;\n            padding: 30px;\n        }\n        \n        .course-card {\n            background: white;\n            border: 2px solid #e9ecef;\n            border-radius: 15px;\n            padding: 25px;\n            transition: all 0.3s;\n        }\n        \n        .course-card:hover {\n            border-color: #667eea;\n            transform: translateY(-3px);\n            box-shadow: 0 10px 25px rgba(102, 126, 234, 0.15);\n        }\n        \n        .course-header {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            margin-bottom: 20px;\n        }\n        \n        .course-title {\n            font-size: 1.4em;\n            font-weight: bold;\n            color: #333;\n        }\n        \n        .course-teacher {\n            color: #666;\n            font-size: 0.9em;\n        }\n        \n        .progress-bar {\n            background: #e9ecef;\n            border-radius: 10px;\n            height: 8px;\n            margin: 15px 0;\n            overflow: hidden;\n        }\n        \n        .progress-fill {\n            background: linear-gradient(90deg, #667eea, #764ba2);\n            height: 100%;\n            border-radius: 10px;\n            transition: width 0.5s ease;\n        }\n        \n        .progress-text {\n            display: flex;\n            justify-content: space-between;\n            font-size: 0.9em;\n            color: #666;\n            margin-bottom: 15px;\n        }\n        \n        .checkin-section {\n            display: flex;\n            gap: 10px;\n            align-items: center;\n        }\n        \n        .hours-input {\n            width: 80px;\n            padding: 8px 12px;\n            border: 2px solid #ddd;\n            border-radius: 8px;\n            text-align: center;\n        }\n        \n        .checkin-btn {\n            background: #28a745;\n            padding: 8px 16px;\n            font-size: 14px;\n        }\n        \n        .checkin-btn:hover {\n            background: #218838;\n        }\n        \n        .checkin-btn:disabled {\n            background: #6c757d;\n            cursor: not-allowed;\n        }\n        \n        .link-section {\n            background: #e3f2fd;\n            padding: 20px 30px;\n            border-top: 2px solid #ddd;\n        }\n        \n        .personal-link {\n            display: flex;\n            gap: 10px;\n            align-items: center;\n            flex-wrap: wrap;\n        }\n        \n        .link-input {\n            flex: 1;\n            min-width: 300px;\n            padding: 12px 15px;\n            border: 2px solid #2196f3;\n            border-radius: 10px;\n            background: white;\n            font-family: monospace;\n        }\n        \n        .copy-btn {\n            background: #2196f3;\n        }\n        \n        .copy-btn:hover {\n            background: #1976d2;\n        }\n        \n        .today-progress {\n            background: linear-gradient(135deg, #ff6b6b, #feca57);\n            color: white;\n            padding: 20px;\n            margin: 20px 30px;\n            border-radius: 15px;\n            text-align: center;\n        }\n        \n        .today-progress h3 {\n            margin-bottom: 10px;\n        }\n        \n        .weekly-target {\n            background: #fff3cd;\n            border: 2px solid #ffeaa7;\n            padding: 15px;\n            margin: 20px 30px;\n            border-radius: 10px;\n            text-align: center;\n        }\n        \n        .achievement-badge {\n            display: inline-block;\n            background: #28a745;\n            color: white;\n            padding: 5px 12px;\n            border-radius: 20px;\n            font-size: 0.8em;\n            margin-left: 10px;\n        }\n        \n        @media (max-width: 768px) {\n            .user-form {\n                flex-direction: column;\n                align-items: stretch;\n            }\n            \n            .stats {\n                grid-template-columns: repeat(2, 1fr);\n            }\n            \n            .courses-grid {\n                grid-template-columns: 1fr;\n            }\n            \n            .personal-link {\n                flex-direction: column;\n            }\n            \n            .link-input {\n                min-width: auto;\n            }\n        }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"container\">\n        <div class=\"header\">\n            <h1>\ud83d\udcda \u6cd5\u8003\u5b66\u4e60\u6253\u5361\u7cfb\u7edf<\/h1>\n            <p>\u575a\u6301\u6bcf\u4e00\u5929\uff0c\u6210\u529f\u5728\u773c\u524d\uff01<\/p>\n        <\/div>\n        \n        <div class=\"user-info\">\n            <div class=\"user-form\">\n                <input type=\"text\" id=\"username\" placeholder=\"\u8f93\u5165\u60a8\u7684\u59d3\u540d\" maxlength=\"20\">\n                <select id=\"studyTarget\">\n                    <option value=\"2\">\u6bcf\u54682\u8bfe\u65f6\uff08\u57fa\u7840\u76ee\u6807\uff09<\/option>\n                    <option value=\"3\">\u6bcf\u54683\u8bfe\u65f6\uff08\u8fdb\u9636\u76ee\u6807\uff09<\/option>\n                    <option value=\"4\">\u6bcf\u54684\u8bfe\u65f6\uff08\u51b2\u523a\u76ee\u6807\uff09<\/option>\n                <\/select>\n                <button class=\"btn\" onclick=\"initUser()\">\u5f00\u59cb\u5b66\u4e60\u4e4b\u65c5<\/button>\n            <\/div>\n        <\/div>\n        \n        <div id=\"mainContent\" style=\"display: none;\">\n            <div class=\"today-progress\" id=\"todayProgress\">\n                <h3>\u4eca\u65e5\u5b66\u4e60\u8fdb\u5ea6<\/h3>\n                <p>\u4eca\u5929\u8fd8\u6ca1\u6709\u6253\u5361\u5b66\u4e60\u54e6\uff01\u52a0\u6cb9\ud83d\udcaa<\/p>\n            <\/div>\n            \n            <div class=\"weekly-target\" id=\"weeklyTarget\">\n                <strong>\ud83d\udcc5 \u672c\u5468\u76ee\u6807\uff1a2\u8bfe\u65f6<\/strong> | \n                <span id=\"weeklyProgress\">\u5df2\u5b8c\u6210\uff1a0\u8bfe\u65f6<\/span>\n            <\/div>\n            \n            <div class=\"stats\">\n                <div class=\"stat-card\">\n                    <div class=\"stat-number\" id=\"totalHours\">0<\/div>\n                    <div class=\"stat-label\">\u603b\u5b66\u4e60\u65f6\u957f<\/div>\n                <\/div>\n                <div class=\"stat-card\">\n                    <div class=\"stat-number\" id=\"studyDays\">0<\/div>\n                    <div class=\"stat-label\">\u5df2\u5b66\u4e60\u5929\u6570<\/div>\n                <\/div>\n                <div class=\"stat-card\">\n                    <div class=\"stat-number\" id=\"completionRate\">0%<\/div>\n                    <div class=\"stat-label\">\u5b8c\u6210\u8fdb\u5ea6<\/div>\n                <\/div>\n                <div class=\"stat-card\">\n                    <div class=\"stat-number\" id=\"avgDaily\">0.0<\/div>\n                    <div class=\"stat-label\">\u65e5\u5747\u5b66\u4e60(\u8bfe\u65f6)<\/div>\n                <\/div>\n            <\/div>\n            \n            <div class=\"courses-grid\" id=\"coursesGrid\">\n                <!-- \u8bfe\u7a0b\u5361\u7247\u5c06\u5728\u8fd9\u91cc\u52a8\u6001\u751f\u6210 -->\n            <\/div>\n            \n            <div class=\"link-section\">\n                <h3 style=\"margin-bottom: 15px;\">\ud83d\udd17 \u60a8\u7684\u4e13\u5c5e\u6253\u5361\u94fe\u63a5<\/h3>\n                <div class=\"personal-link\">\n                    <input type=\"text\" class=\"link-input\" id=\"personalLink\" readonly>\n                    <button class=\"btn copy-btn\" onclick=\"copyLink()\">\u590d\u5236\u94fe\u63a5<\/button>\n                    <button class=\"btn\" onclick=\"shareLink()\">\u5206\u4eab\u94fe\u63a5<\/button>\n                    <button class=\"btn\" onclick=\"exportData()\" style=\"background: #17a2b8;\">\u5bfc\u51fa\u6570\u636e<\/button>\n                    <button class=\"btn\" onclick=\"importData()\" style=\"background: #28a745;\">\u5bfc\u5165\u6570\u636e<\/button>\n                <\/div>\n                <p style=\"margin-top: 10px; color: #666; font-size: 0.9em;\">\n                    \ud83d\udca1 <strong>\u8de8\u8bbe\u5907\u540c\u6b65\u8bf4\u660e\uff1a<\/strong><br>\n                    \ud83d\udd04 \u65b9\u6cd51\uff1a\u590d\u5236\u5b8c\u6574\u94fe\u63a5\u5230\u65b0\u8bbe\u5907\uff08\u81ea\u52a8\u540c\u6b65\uff09<br>\n                    \ud83d\udcc1 \u65b9\u6cd52\uff1a\u4f7f\u7528&#8221;\u5bfc\u51fa\u6570\u636e&#8221;\u6309\u94ae\uff0c\u5728\u65b0\u8bbe\u5907\u4e0a&#8221;\u5bfc\u5165\u6570\u636e&#8221;\n                <\/p>\n                \n                <!-- \u9690\u85cf\u7684\u6587\u4ef6\u8f93\u5165\u6846 -->\n                <input type=\"file\" id=\"importFile\" accept=\".json\" style=\"display: none;\">\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <script>\n        \/\/ \u6cd5\u8003\u8bfe\u7a0b\u6570\u636e\n        const courses = [\n            {id: 'xingfa', name: '\u5211\u6cd5', teacher: '\u9648\u6a59', totalHours: 10},\n            {id: 'minfa', name: '\u6c11\u6cd5', teacher: '\u5f20\u7fd4', totalHours: 12},\n            {id: 'xingsu', name: '\u5211\u8bc9', teacher: '\u5411\u9ad8\u7532', totalHours: 6},\n            {id: 'minsu', name: '\u6c11\u8bc9', teacher: '\u5218\u9e4f\u98de', totalHours: 6},\n            {id: 'shangjing', name: '\u5546\u7ecf\u6cd5', teacher: '\u9122\u68a6\u8431', totalHours: 9},\n            {id: 'xingzheng', name: '\u884c\u653f\u6cd5', teacher: '\u9b4f\u5efa\u65b0', totalHours: 6},\n            {id: 'sanguofa', name: '\u4e09\u56fd\u6cd5', teacher: '\u6bb7\u654f', totalHours: 6},\n            {id: 'lilunfa', name: '\u7406\u8bba\u6cd5', teacher: '\u9ad8\u6656\u4e91', totalHours: 12}\n        ];\n\n        let userData = {\n            username: '',\n            studyTarget: 2,\n            startDate: '2025-09-01',\n            totalStudied: 0,\n            studyDays: 0,\n            courses: {},\n            dailyRecords: {}\n        };\n\n        \/\/ \u9875\u9762\u52a0\u8f7d\u65f6\u521d\u59cb\u5316\n        window.addEventListener('load', function() {\n            const urlParams = new URLSearchParams(window.location.search);\n            const userId = urlParams.get('user');\n            \n            if (userId) {\n                loadUserData(userId);\n            }\n        });\n\n        function initUser() {\n            const username = document.getElementById('username').value.trim();\n            const studyTarget = parseInt(document.getElementById('studyTarget').value);\n            \n            if (!username) {\n                alert('\u8bf7\u8f93\u5165\u60a8\u7684\u59d3\u540d\uff01');\n                return;\n            }\n            \n            \/\/ \u751f\u6210\u7528\u6237ID\n            const userId = btoa(encodeURIComponent(username + Date.now())).replace(\/[\\\/\\+=]\/g, '').substring(0, 12);\n            \n            userData.username = username;\n            userData.studyTarget = studyTarget;\n            userData.userId = userId;\n            \n            \/\/ \u521d\u59cb\u5316\u8bfe\u7a0b\u6570\u636e\n            courses.forEach(course => {\n                userData.courses[course.id] = {\n                    studiedHours: 0,\n                    completed: false\n                };\n            });\n            \n            saveUserData();\n            showMainContent();\n            updatePersonalLink();\n            updateDisplay();\n        }\n\n        function loadUserData(userId) {\n            const urlParams = new URLSearchParams(window.location.search);\n            const compressedData = urlParams.get('data');\n            \n            console.log('\u5c1d\u8bd5\u4eceURL\u52a0\u8f7d\u6570\u636e...', compressedData ? '\u627e\u5230\u6570\u636e' : '\u672a\u627e\u5230\u6570\u636e');\n            \n            \/\/ \u4f18\u5148\u4eceURL\u52a0\u8f7d\u6570\u636e\uff08\u652f\u6301\u8de8\u8bbe\u5907\uff09\n            if (compressedData) {\n                console.log('\u5f00\u59cb\u89e3\u538bURL\u6570\u636e...');\n                const decompressedData = decompressUserData(compressedData);\n                if (decompressedData) {\n                    console.log('URL\u6570\u636e\u89e3\u538b\u6210\u529f\uff0c\u52a0\u8f7d\u7528\u6237\u6570\u636e');\n                    userData = decompressedData;\n                    userData.userId = userId;\n                    \n                    \/\/ \u540c\u65f6\u4fdd\u5b58\u5230\u672c\u5730\u5b58\u50a8\u4f5c\u4e3a\u5907\u4efd\n                    localStorage.setItem('lawStudy_' + userId, JSON.stringify(userData));\n                    \n                    document.getElementById('username').value = userData.username;\n                    document.getElementById('studyTarget').value = userData.studyTarget;\n                    \n                    showMainContent();\n                    updateDisplay();\n                    updatePersonalLink();\n                    \n                    showToast('\ud83d\udd04 \u5df2\u4ece\u94fe\u63a5\u540c\u6b65\u60a8\u7684\u5b66\u4e60\u8bb0\u5f55\uff01', 'success');\n                    return;\n                } else {\n                    console.warn('URL\u6570\u636e\u89e3\u538b\u5931\u8d25');\n                    showToast('\u26a0\ufe0f \u94fe\u63a5\u4e2d\u7684\u6570\u636e\u635f\u574f\uff0c\u5c1d\u8bd5\u4ece\u672c\u5730\u52a0\u8f7d', 'warning');\n                }\n            }\n            \n            \/\/ \u5982\u679cURL\u4e2d\u6ca1\u6709\u6570\u636e\uff0c\u5c1d\u8bd5\u4ece\u672c\u5730\u5b58\u50a8\u52a0\u8f7d\n            console.log('\u5c1d\u8bd5\u4ece\u672c\u5730\u5b58\u50a8\u52a0\u8f7d\u6570\u636e...');\n            const savedData = localStorage.getItem('lawStudy_' + userId);\n            if (savedData) {\n                console.log('\u4ece\u672c\u5730\u5b58\u50a8\u52a0\u8f7d\u6210\u529f');\n                userData = JSON.parse(savedData);\n                userData.userId = userId;\n                \n                document.getElementById('username').value = userData.username;\n                document.getElementById('studyTarget').value = userData.studyTarget;\n                \n                showMainContent();\n                updateDisplay();\n                updatePersonalLink();\n                \n                \/\/ \u5c06\u672c\u5730\u6570\u636e\u540c\u6b65\u5230URL\n                syncToUrl();\n                showToast('\ud83d\udcf1 \u5df2\u52a0\u8f7d\u672c\u5730\u6570\u636e\uff0c\u5efa\u8bae\u590d\u5236\u65b0\u94fe\u63a5\u4ee5\u4fbf\u8de8\u8bbe\u5907\u540c\u6b65', 'info');\n            } else {\n                console.log('\u672a\u627e\u5230\u4efb\u4f55\u4fdd\u5b58\u7684\u6570\u636e');\n                showToast('\ud83c\udd95 \u672a\u627e\u5230\u5386\u53f2\u8bb0\u5f55\uff0c\u8bf7\u91cd\u65b0\u521b\u5efa\u7528\u6237', 'info');\n            }\n        }\n\n        function saveUserData() {\n            if (userData.userId) {\n                \/\/ \u4fdd\u5b58\u5230\u672c\u5730\u5b58\u50a8\uff08\u5907\u4efd\uff09\n                localStorage.setItem('lawStudy_' + userData.userId, JSON.stringify(userData));\n                \n                \/\/ \u540c\u6b65\u5230URL\uff08\u5b9e\u73b0\u8de8\u8bbe\u5907\u540c\u6b65\uff09\n                syncToUrl();\n            }\n        }\n        \n        function syncToUrl() {\n            try {\n                \/\/ \u538b\u7f29\u6570\u636e\n                const compressedData = compressUserData(userData);\n                const newUrl = window.location.pathname + '?user=' + userData.userId + '&data=' + compressedData;\n                \n                \/\/ \u66f4\u65b0URL\u4f46\u4e0d\u5237\u65b0\u9875\u9762\n                window.history.replaceState({}, '', newUrl);\n                updatePersonalLink();\n            } catch (e) {\n                console.warn('\u6570\u636e\u540c\u6b65\u5230URL\u5931\u8d25\uff0c\u4f7f\u7528\u672c\u5730\u5b58\u50a8\u5907\u4efd');\n            }\n        }\n        \n        function compressUserData(data) {\n            \/\/ \u53ea\u4fdd\u7559\u5173\u952e\u6570\u636e\uff0c\u51cf\u5c11URL\u957f\u5ea6\n            const compressed = {\n                u: data.username,\n                t: data.studyTarget,\n                s: data.startDate,\n                ts: data.totalStudied,\n                sd: data.studyDays,\n                c: data.courses,\n                d: data.dailyRecords\n            };\n            return btoa(encodeURIComponent(JSON.stringify(compressed))).replace(\/[\\\/\\+=]\/g, '');\n        }\n        \n        function decompressUserData(compressedData) {\n            try {\n                const jsonStr = decodeURIComponent(atob(compressedData + '==='.slice(0, 4 - compressedData.length % 4)));\n                const compressed = JSON.parse(jsonStr);\n                \n                return {\n                    username: compressed.u,\n                    studyTarget: compressed.t,\n                    startDate: compressed.s,\n                    totalStudied: compressed.ts,\n                    studyDays: compressed.sd,\n                    courses: compressed.c,\n                    dailyRecords: compressed.d\n                };\n            } catch (e) {\n                return null;\n            }\n        }\n\n        function showMainContent() {\n            document.getElementById('mainContent').style.display = 'block';\n            renderCourses();\n        }\n\n        function renderCourses() {\n            const grid = document.getElementById('coursesGrid');\n            grid.innerHTML = '';\n            \n            courses.forEach(course => {\n                const studiedHours = userData.courses[course.id]?.studiedHours || 0;\n                const progress = Math.min((studiedHours \/ course.totalHours) * 100, 100);\n                const isCompleted = studiedHours >= course.totalHours;\n                \n                const courseCard = document.createElement('div');\n                courseCard.className = 'course-card';\n                courseCard.innerHTML = `\n                    <div class=\"course-header\">\n                        <div>\n                            <div class=\"course-title\">${course.name}${isCompleted ? '<span class=\"achievement-badge\">\u2705 \u5df2\u5b8c\u6210<\/span>' : ''}<\/div>\n                            <div class=\"course-teacher\">\u8bb2\u5e08\uff1a${course.teacher}<\/div>\n                        <\/div>\n                    <\/div>\n                    <div class=\"progress-text\">\n                        <span>\u8fdb\u5ea6\uff1a${studiedHours}\/${course.totalHours} \u8bfe\u65f6<\/span>\n                        <span>${progress.toFixed(1)}%<\/span>\n                    <\/div>\n                    <div class=\"progress-bar\">\n                        <div class=\"progress-fill\" style=\"width: ${progress}%\"><\/div>\n                    <\/div>\n                    <div class=\"checkin-section\">\n                        <span>\u4eca\u65e5\u5b66\u4e60\uff1a<\/span>\n                        <input type=\"number\" class=\"hours-input\" id=\"hours_${course.id}\" \n                               min=\"0.5\" max=\"8\" step=\"0.5\" placeholder=\"0.5\">\n                        <span>\u8bfe\u65f6<\/span>\n                        <button class=\"btn checkin-btn\" onclick=\"checkinCourse('${course.id}')\" \n                                ${isCompleted ? 'disabled' : ''}>\n                            ${isCompleted ? '\u5df2\u5b8c\u6210' : '\u6253\u5361'}\n                        <\/button>\n                    <\/div>\n                `;\n                grid.appendChild(courseCard);\n            });\n        }\n\n        function checkinCourse(courseId) {\n            const hoursInput = document.getElementById(`hours_${courseId}`);\n            const hours = parseFloat(hoursInput.value);\n            \n            if (!hours || hours <= 0) {\n                alert('\u8bf7\u8f93\u5165\u6709\u6548\u7684\u5b66\u4e60\u65f6\u957f\uff01');\n                return;\n            }\n            \n            if (hours > 8) {\n                alert('\u5355\u6b21\u5b66\u4e60\u65f6\u957f\u4e0d\u80fd\u8d85\u8fc78\u8bfe\u65f6\uff01');\n                return;\n            }\n            \n            \/\/ \u66f4\u65b0\u6570\u636e\n            if (!userData.courses[courseId]) {\n                userData.courses[courseId] = {studiedHours: 0, completed: false};\n            }\n            \n            userData.courses[courseId].studiedHours += hours;\n            userData.totalStudied += hours;\n            \n            \/\/ \u8bb0\u5f55\u4eca\u65e5\u5b66\u4e60\n            const today = new Date().toISOString().split('T')[0];\n            if (!userData.dailyRecords[today]) {\n                userData.dailyRecords[today] = {};\n                userData.studyDays++;\n            }\n            \n            if (!userData.dailyRecords[today][courseId]) {\n                userData.dailyRecords[today][courseId] = 0;\n            }\n            userData.dailyRecords[today][courseId] += hours;\n            \n            \/\/ \u68c0\u67e5\u662f\u5426\u5b8c\u6210\n            const course = courses.find(c => c.id === courseId);\n            if (userData.courses[courseId].studiedHours >= course.totalHours) {\n                userData.courses[courseId].completed = true;\n                setTimeout(() => {\n                    alert(`\ud83c\udf89 \u606d\u559c\uff01\u60a8\u5df2\u5b8c\u6210\u300a${course.name}\u300b\u7684\u5168\u90e8\u8bfe\u7a0b\uff01`);\n                }, 500);\n            }\n            \n            saveUserData();\n            updateDisplay();\n            renderCourses();\n            \n            \/\/ \u6e05\u7a7a\u8f93\u5165\u6846\n            hoursInput.value = '';\n            \n            \/\/ \u663e\u793a\u6253\u5361\u6210\u529f\u63d0\u793a\n            showCheckinSuccess(hours, course.name);\n        }\n\n        function showCheckinSuccess(hours, courseName) {\n            const toast = document.createElement('div');\n            toast.style.cssText = `\n                position: fixed;\n                top: 20px;\n                right: 20px;\n                background: #28a745;\n                color: white;\n                padding: 15px 20px;\n                border-radius: 10px;\n                box-shadow: 0 5px 15px rgba(0,0,0,0.3);\n                z-index: 1000;\n                animation: slideIn 0.5s ease;\n            `;\n            toast.innerHTML = `\u2705 \u6253\u5361\u6210\u529f\uff01<br>\u300a${courseName}\u300b\u5b66\u4e60\u4e86${hours}\u8bfe\u65f6`;\n            \n            document.body.appendChild(toast);\n            \n            setTimeout(() => {\n                toast.remove();\n            }, 3000);\n        }\n\n        function updateDisplay() {\n            \/\/ \u66f4\u65b0\u7edf\u8ba1\u6570\u636e\n            const totalHours = courses.reduce((sum, course) => sum + course.totalHours, 0);\n            const completionRate = (userData.totalStudied \/ totalHours * 100).toFixed(1);\n            const avgDaily = userData.studyDays > 0 ? (userData.totalStudied \/ userData.studyDays).toFixed(1) : '0.0';\n            \n            document.getElementById('totalHours').textContent = userData.totalStudied.toFixed(1);\n            document.getElementById('studyDays').textContent = userData.studyDays;\n            document.getElementById('completionRate').textContent = completionRate + '%';\n            document.getElementById('avgDaily').textContent = avgDaily;\n            \n            \/\/ \u66f4\u65b0\u4eca\u65e5\u8fdb\u5ea6\n            updateTodayProgress();\n            \n            \/\/ \u66f4\u65b0\u672c\u5468\u8fdb\u5ea6\n            updateWeeklyProgress();\n        }\n\n        function updateTodayProgress() {\n            const today = new Date().toISOString().split('T')[0];\n            const todayRecord = userData.dailyRecords[today];\n            const todayProgressDiv = document.getElementById('todayProgress');\n            \n            if (todayRecord) {\n                const todayHours = Object.values(todayRecord).reduce((sum, hours) => sum + hours, 0);\n                const studiedCourses = Object.keys(todayRecord).map(courseId => {\n                    const course = courses.find(c => c.id === courseId);\n                    return `\u300a${course.name}\u300b${todayRecord[courseId]}\u8bfe\u65f6`;\n                }).join('\u3001');\n                \n                todayProgressDiv.innerHTML = `\n                    <h3>\ud83d\udcd6 \u4eca\u65e5\u5b66\u4e60\u8fdb\u5ea6<\/h3>\n                    <p>\u4eca\u5929\u5df2\u5b66\u4e60 <strong>${todayHours}\u8bfe\u65f6<\/strong><\/p>\n                    <p style=\"font-size: 0.9em; margin-top: 5px;\">${studiedCourses}<\/p>\n                `;\n            }\n        }\n\n        function updateWeeklyProgress() {\n            const today = new Date();\n            const weekStart = new Date(today);\n            weekStart.setDate(today.getDate() - today.getDay() + 1); \/\/ \u672c\u5468\u4e00\n            \n            let weeklyHours = 0;\n            for (let i = 0; i < 7; i++) {\n                const date = new Date(weekStart);\n                date.setDate(weekStart.getDate() + i);\n                const dateStr = date.toISOString().split('T')[0];\n                \n                if (userData.dailyRecords[dateStr]) {\n                    weeklyHours += Object.values(userData.dailyRecords[dateStr])\n                        .reduce((sum, hours) => sum + hours, 0);\n                }\n            }\n            \n            const targetDiv = document.getElementById('weeklyTarget');\n            const progressSpan = document.getElementById('weeklyProgress');\n            const target = userData.studyTarget || 2;\n            const isCompleted = weeklyHours >= target;\n            \n            targetDiv.innerHTML = `\n                <strong>\ud83d\udcc5 \u672c\u5468\u76ee\u6807\uff1a${target}\u8bfe\u65f6<\/strong> | \n                <span style=\"color: ${isCompleted ? '#28a745' : '#666'}\">\n                    \u5df2\u5b8c\u6210\uff1a${weeklyHours.toFixed(1)}\u8bfe\u65f6 \n                    ${isCompleted ? '\ud83c\udf89 \u5df2\u8fbe\u6807!' : ''}\n                <\/span>\n            `;\n        }\n\n        function updatePersonalLink() {\n            if (userData.userId) {\n                const currentUrl = window.location.origin + window.location.pathname;\n                let personalLink = `${currentUrl}?user=${userData.userId}`;\n                \n                \/\/ \u5c1d\u8bd5\u6dfb\u52a0\u538b\u7f29\u6570\u636e\u5230\u94fe\u63a5\n                try {\n                    const compressedData = compressUserData(userData);\n                    const testUrl = personalLink + `&data=${compressedData}`;\n                    \n                    \/\/ \u68c0\u67e5URL\u957f\u5ea6\u9650\u5236\uff08\u5927\u591a\u6570\u6d4f\u89c8\u5668\u652f\u63012000\u5b57\u7b26\u4ee5\u5185\uff09\n                    if (testUrl.length < 2000) {\n                        personalLink = testUrl;\n                    } else {\n                        console.warn('\u6570\u636e\u91cf\u8f83\u5927\uff0c\u5efa\u8bae\u4f7f\u7528\u5bfc\u51fa\/\u5bfc\u5165\u529f\u80fd\u8fdb\u884c\u8de8\u8bbe\u5907\u540c\u6b65');\n                    }\n                } catch (e) {\n                    console.warn('\u65e0\u6cd5\u538b\u7f29\u6570\u636e\u5230URL\uff0c\u8bf7\u4f7f\u7528\u5bfc\u51fa\/\u5bfc\u5165\u529f\u80fd');\n                }\n                \n                document.getElementById('personalLink').value = personalLink;\n            }\n        }\n\n        function exportData() {\n            if (!userData.userId) {\n                alert('\u8bf7\u5148\u521d\u59cb\u5316\u7528\u6237\u4fe1\u606f\uff01');\n                return;\n            }\n            \n            \/\/ \u521b\u5efa\u5bfc\u51fa\u6570\u636e\n            const exportData = {\n                ...userData,\n                exportTime: new Date().toISOString(),\n                version: '1.0'\n            };\n            \n            \/\/ \u521b\u5efa\u4e0b\u8f7d\u94fe\u63a5\n            const dataStr = JSON.stringify(exportData, null, 2);\n            const dataBlob = new Blob([dataStr], {type: 'application\/json'});\n            const url = URL.createObjectURL(dataBlob);\n            \n            \/\/ \u521b\u5efa\u4e0b\u8f7d\u94fe\u63a5\n            const link = document.createElement('a');\n            link.href = url;\n            link.download = `\u6cd5\u8003\u5b66\u4e60\u8bb0\u5f55_${userData.username}_${new Date().toISOString().split('T')[0]}.json`;\n            document.body.appendChild(link);\n            link.click();\n            document.body.removeChild(link);\n            URL.revokeObjectURL(url);\n            \n            \/\/ \u663e\u793a\u6210\u529f\u63d0\u793a\n            showToast('\ud83d\udcc1 \u6570\u636e\u5bfc\u51fa\u6210\u529f\uff01\u8bf7\u4fdd\u5b58\u6587\u4ef6\u7528\u4e8e\u8de8\u8bbe\u5907\u540c\u6b65', 'success');\n        }\n        \n        function importData() {\n            document.getElementById('importFile').click();\n        }\n        \n        \/\/ \u5904\u7406\u6587\u4ef6\u5bfc\u5165\n        document.addEventListener('DOMContentLoaded', function() {\n            document.getElementById('importFile').addEventListener('change', function(e) {\n                const file = e.target.files[0];\n                if (!file) return;\n                \n                const reader = new FileReader();\n                reader.onload = function(e) {\n                    try {\n                        const importedData = JSON.parse(e.target.result);\n                        \n                        \/\/ \u9a8c\u8bc1\u6570\u636e\u683c\u5f0f\n                        if (!importedData.username || !importedData.userId) {\n                            throw new Error('\u6570\u636e\u683c\u5f0f\u4e0d\u6b63\u786e');\n                        }\n                        \n                        \/\/ \u786e\u8ba4\u5bfc\u5165\n                        const confirmImport = confirm(`\u786e\u5b9a\u8981\u5bfc\u5165\u7528\u6237\"${importedData.username}\"\u7684\u5b66\u4e60\u8bb0\u5f55\u5417\uff1f\\n\u8fd9\u5c06\u8986\u76d6\u5f53\u524d\u7684\u6240\u6709\u6570\u636e\uff01`);\n                        \n                        if (confirmImport) {\n                            \/\/ \u5bfc\u5165\u6570\u636e\n                            userData = { ...importedData };\n                            delete userData.exportTime;\n                            delete userData.version;\n                            \n                            \/\/ \u66f4\u65b0\u754c\u9762\n                            document.getElementById('username').value = userData.username;\n                            document.getElementById('studyTarget').value = userData.studyTarget;\n                            \n                            showMainContent();\n                            updateDisplay();\n                            saveUserData();\n                            \n                            showToast('\u2705 \u6570\u636e\u5bfc\u5165\u6210\u529f\uff01\u6b22\u8fce\u56de\u6765\u7ee7\u7eed\u5b66\u4e60\uff01', 'success');\n                        }\n                        \n                    } catch (error) {\n                        alert('\u5bfc\u5165\u5931\u8d25\uff1a\u6587\u4ef6\u683c\u5f0f\u4e0d\u6b63\u786e\u6216\u6570\u636e\u635f\u574f');\n                        console.error('\u5bfc\u5165\u9519\u8bef:', error);\n                    }\n                };\n                reader.readAsText(file);\n                \n                \/\/ \u6e05\u7a7a\u6587\u4ef6\u9009\u62e9\n                e.target.value = '';\n            });\n        });\n        \n        function showToast(message, type = 'info') {\n            const toast = document.createElement('div');\n            const bgColor = type === 'success' ? '#28a745' : type === 'warning' ? '#ffc107' : '#17a2b8';\n            \n            toast.style.cssText = `\n                position: fixed;\n                top: 20px;\n                right: 20px;\n                background: ${bgColor};\n                color: white;\n                padding: 15px 20px;\n                border-radius: 10px;\n                box-shadow: 0 5px 15px rgba(0,0,0,0.3);\n                z-index: 1000;\n                max-width: 300px;\n                animation: slideIn 0.5s ease;\n            `;\n            toast.innerHTML = message;\n            \n            document.body.appendChild(toast);\n            \n            setTimeout(() => {\n                toast.remove();\n            }, 4000);\n        }\n\n        function copyLink() {\n            const linkInput = document.getElementById('personalLink');\n            linkInput.select();\n            document.execCommand('copy');\n            \n            const btn = event.target;\n            const originalText = btn.textContent;\n            btn.textContent = '\u5df2\u590d\u5236\uff01';\n            btn.style.background = '#28a745';\n            \n            setTimeout(() => {\n                btn.textContent = originalText;\n                btn.style.background = '#2196f3';\n            }, 2000);\n        }\n\n        function shareLink() {\n            const link = document.getElementById('personalLink').value;\n            const text = `\u6211\u6b63\u5728\u4f7f\u7528\u6cd5\u8003\u5b66\u4e60\u6253\u5361\u7cfb\u7edf\u575a\u6301\u5b66\u4e60\uff01\u52a0\u5165\u6211\u4e00\u8d77\u5907\u8003\u5427\uff1a${link}`;\n            \n            if (navigator.share) {\n                navigator.share({\n                    title: '\u6cd5\u8003\u5b66\u4e60\u6253\u5361\u7cfb\u7edf',\n                    text: text,\n                    url: link\n                });\n            } else {\n                \/\/ \u590d\u5236\u5230\u526a\u8d34\u677f\n                navigator.clipboard.writeText(text).then(() => {\n                    alert('\u5206\u4eab\u94fe\u63a5\u5df2\u590d\u5236\u5230\u526a\u8d34\u677f\uff01');\n                });\n            }\n        }\n\n        \/\/ \u6dfb\u52a0CSS\u52a8\u753b\n        const style = document.createElement('style');\n        style.textContent = `\n            @keyframes slideIn {\n                from {\n                    transform: translateX(100%);\n                    opacity: 0;\n                }\n                to {\n                    transform: translateX(0);\n                    opacity: 1;\n                }\n            }\n        `;\n        document.head.appendChild(style);\n    <\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>\u6cd5\u8003\u5b66\u4e60\u6253\u5361\u7cfb\u7edf \ud83d\udcda \u6cd5\u8003\u5b66\u4e60\u6253\u5361\u7cfb\u7edf \u575a\u6301\u6bcf\u4e00\u5929\uff0c\u6210\u529f\u5728\u773c\u524d\uff01 \u6bcf\u54682\u8bfe\u65f6\uff08\u57fa\u7840\u76ee\u6807\uff09\u6bcf\u54683\u8bfe\u65f6\uff08\u8fdb\u9636\u76ee\u6807\uff09&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-153","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.fbmeta.eu.org\/index.php\/wp-json\/wp\/v2\/pages\/153","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fbmeta.eu.org\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.fbmeta.eu.org\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.fbmeta.eu.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fbmeta.eu.org\/index.php\/wp-json\/wp\/v2\/comments?post=153"}],"version-history":[{"count":9,"href":"https:\/\/www.fbmeta.eu.org\/index.php\/wp-json\/wp\/v2\/pages\/153\/revisions"}],"predecessor-version":[{"id":163,"href":"https:\/\/www.fbmeta.eu.org\/index.php\/wp-json\/wp\/v2\/pages\/153\/revisions\/163"}],"wp:attachment":[{"href":"https:\/\/www.fbmeta.eu.org\/index.php\/wp-json\/wp\/v2\/media?parent=153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}