/* ziwei-power 前端逻辑 — Flomo 风格左右布局 */ (function() { 'use strict'; /* ================================================================ State ================================================================ */ var calendarStatus = {}; // { "2026-W30": "pass", ... } var calYear; var calMonth = new Date().getMonth(); // 月份索引 0-11 var activePanel = 'daily'; var weekOffset = 0; var lastSavedData = null; var lastSavedWeek = null; var selectedWeek = null; /* 勤学预设项目 */ var PRESET_STUDY_ITEMS = [ '晚上 11 点 30 之前睡觉', '早上 6 点 30 之前起床', '起床后做 30 个俯卧撑', '销售客情能力提升', '管理能力提升', '产品规划有进一步的提升', 'AI 能力提升', '知识库能力提升' ]; /* 蓝图六板块 */ var PILLARS = [ {key:'medical_service', name:'医疗服务', emoji:'🥼'}, {key:'pharma_mkt', name:'医药营销', emoji:'💊'}, {key:'payment', name:'医疗支付', emoji:'🛡️'}, {key:'ai', name:'AI 智能', emoji:'🤖'}, {key:'governance', name:'公司治理', emoji:'🏛️'}, {key:'self_cultivation', name:'个人修养', emoji:'🎯'} ]; /* ================================================================ Toast ================================================================ */ var toastTimer = null; function showToast(msg, type) { type = type || 'info'; var el = document.getElementById('toast'); el.textContent = msg; el.className = 'toast ' + type + ' show'; clearTimeout(toastTimer); toastTimer = setTimeout(function(){ el.classList.remove('show'); }, 2500); } /* ================================================================ API ================================================================ */ function apiGetCheckin(week, cb) { fetch('/api/checkin?week=' + encodeURIComponent(week)) .then(function(r){ return r.json(); }) .then(function(res){ if (res.ok) cb(null, res.data); else cb(res.error); }) .catch(function(e){ cb(e.message); }); } function apiSaveCheckin(week, data, cb) { fetch('/api/checkin', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({week: week, data: data}) }) .then(function(r){ return r.json(); }) .then(function(res){ if (res.ok) cb(null); else cb(res.error); }) .catch(function(e){ cb(e.message); }); } function apiDeleteCheckin(date, cb) { fetch('/api/checkin/' + encodeURIComponent(date), {method: 'DELETE'}) .then(function(r){ return r.json(); }) .then(function(res){ if (res.ok) cb(null); else cb(res.error); }) .catch(function(e){ cb(e.message); }); } function apiGetHistory(cb) { fetch('/api/history') .then(function(r){ return r.json(); }) .then(function(res){ if (res.ok) cb(null, res.data); else cb(res.error); }) .catch(function(e){ cb(e.message); }); } function apiGetStats(cb) { fetch('/api/stats') .then(function(r){ return r.json(); }) .then(function(res){ if (res.ok) cb(null, res); else cb(res.error); }) .catch(function(e){ cb(e.message); }); } /* ================================================================ Escaping ================================================================ */ function esc(s) { return String(s).replace(/&/g,'&').replace(/"/g,'"').replace(//g,'>'); } /* ================================================================ Panel Switching ================================================================ */ window.switchPanel = function(name) { activePanel = name; var navs = document.querySelectorAll('.sidebar-nav .nav-item'); var panels = document.querySelectorAll('.main-content .panel'); for (var i=0; i 11) { calMonth = 0; calYear++; } if (calMonth < 0) { calMonth = 11; calYear--; } renderCalendar(); }; /** 渲染年-月-周选择器 */ function renderCalendar() { document.getElementById('cal-year-label').textContent = calYear + '年'; document.getElementById('cal-month-label').textContent = (calMonth + 1) + '月'; // 计算该月包含的周 var firstDay = new Date(calYear, calMonth, 1); var lastDay = new Date(calYear, calMonth + 1, 0); var monday = new Date(firstDay); monday.setDate(monday.getDate() - monday.getDay() + (monday.getDay() === 0 ? -6 : 1)); var weeks = []; while (monday <= lastDay) { weeks.push(fmtWeek(monday)); monday.setDate(monday.getDate() + 7); } // 确保至少有4周显示 while (weeks.length < 4) { var w = fmtWeek(monday); if (weeks.indexOf(w) < 0) weeks.push(w); monday.setDate(monday.getDate() + 7); } var todayWk = fmtWeek(new Date()); var today = new Date(); var wHtml = ''; for (var i2 = 0; i2 < weeks.length; i2++) { var w = weeks[i2]; var cls = 'cal-week-row'; var status = calendarStatus[w]; if (w === todayWk) cls += ' today'; if (w === selectedWeek) cls += ' selected'; // 计算日期范围 var monday = new Date(calYear, calMonth, 1); while (fmtWeek(monday) !== w) monday.setDate(monday.getDate() + 7); var sunday = new Date(monday); sunday.setDate(sunday.getDate() + 6); var dateRange = (monday.getMonth()+1) + '.' + monday.getDate() + ' - ' + sunday.getDate(); var statusIcon = status === 'pass' ? '✓' : (status === 'fail' ? '✗' : '○'); var statusLabel = status === 'pass' ? '达标' : (status === 'fail' ? '未达标' : '未打卡'); wHtml += '
' + '' + statusIcon + '' + '
' + '第' + w.split('-W')[1].replace(/^0/, '') + '周' + '' + dateRange + '' + '
' + '' + statusLabel + '' + '
'; } var we = document.getElementById('cal-weeks'); we.innerHTML = wHtml; we.querySelectorAll('.cal-week-row').forEach(function(row) { cell.addEventListener('click', function() { var wk = this.dataset.week; if (wk) navigateToWeek(wk); }); }); } function navigateToWeek(week) { selectedWeek = week; switchPanel('daily'); document.getElementById('check-date').value = week; loadCheckin(); renderCalendar(); } window.goToCurrentWeek = function() { var now = new Date(); calYear = now.getFullYear(); calMonth = now.getMonth(); renderCalendar(); navigateToWeek(fmtWeek(now)); }; /* ================================================================ Stats — 加载统计数据并更新侧边栏 ================================================================ */ function loadStats() { apiGetStats(function(err, data) { if (!err && data) { document.getElementById('stat-days').textContent = data.total_weeks; document.getElementById('stat-morning').textContent = data.total_morning; document.getElementById('stat-study').textContent = data.total_study; calendarStatus = data.calendar || {}; } renderCalendar(); }); } /* ================================================================ Build / Fill Data ================================================================ */ function buildData() { var morningItems = []; var mEls = document.querySelectorAll('#morning-list .item-row input'); for (var i=0; i' + '' + ''; container.appendChild(div); renumberMorning(); } function renumberMorning() { var rows = document.querySelectorAll('#morning-list .item-row'); for (var i=0; i' + ''; container.appendChild(div); } /* ── 勤学预设项目 ── */ function addPresetItem(name, done, note) { var container = document.getElementById('study-list'); var div = document.createElement('div'); div.className = 'preset-item' + (done ? ' active' : ''); var noteEsc = esc(note || ''); div.innerHTML = '' + ''; container.appendChild(div); } window.togglePresetNote = function(cb) { var item = cb.closest('.preset-item'); if (item) { if (cb.checked) item.classList.add('active'); else { item.classList.remove('active'); item.querySelector('.preset-note').value = ''; } } triggerAutoSave(); }; function initStudyPresets() { document.getElementById('study-list').innerHTML = ''; for (var i=0; i'; return; } var data = res.data || []; if (data.length === 0) { summary.innerHTML = '未查询到任何日程'; return; } // 统计 var totalDays = data.length; var totalEvents = 0; data.forEach(function(d){ totalEvents += d.events.length; }); summary.innerHTML = '同步完成!共 ' + totalDays + ' 周有日程,合计 ' + totalEvents + ' 个会议' + (res.saved_days ? ',已自动填充 ' + res.saved_days + ' 周' : ''); // 渲染结果列表 var html = ''; data.forEach(function(day) { html += '
'; html += '
' + day.date + '
'; day.events.forEach(function(e) { var timeStr = e.time ? ' (' + e.time + ')' : ''; html += '
' + '📌' + '' + esc(e.summary) + '' + esc(timeStr) + '' + '
'; }); html += '
'; }); list.innerHTML = html; // 刷新当前页 loadCheckin(); }) .catch(function(){ loading.style.display = 'none'; resultsEl.style.display = 'block'; summary.innerHTML = '网络错误,请重试'; if (btn) { btn.style.opacity = '1'; btn.disabled = false; } }); }; window.closeSyncModal = function() { var overlay = document.getElementById('sync-modal-overlay'); if (overlay) overlay.style.display = 'none'; }; window.addMorning = function() { var count = document.querySelectorAll('#morning-list .item-row').length; if (count >= 3) { showToast('最多 3 条立志', 'error'); return; } addMorningRow(''); }; window.addEvening = function() { var count = document.querySelectorAll('#evening-list .evening-row').length; if (count >= 5) { showToast('最多 5 条改过', 'error'); return; } addEveningRow('', ''); }; /* 切换卡片编辑模式 */ window.toggleEditMode = function(btn) { var card = btn.closest('.card'); if (!card) return; var editing = card.classList.toggle('editing'); btn.classList.toggle('active', editing); }; /* 切换每周打卡 Tab */ window.switchDailyTab = function(btn) { var tab = btn.dataset.tab; document.querySelectorAll('.daily-tab').forEach(function(t){ t.classList.remove('active'); }); btn.classList.add('active'); document.querySelectorAll('.daily-card').forEach(function(c){ c.classList.remove('active'); }); var card = document.querySelector('.daily-card[data-card="' + tab + '"]'); if (card) card.classList.add('active'); }; /* 头像菜单 */ window.toggleUserMenu = function(e) { e.stopPropagation(); var dd = document.getElementById('user-dropdown'); if (dd) dd.style.display = dd.style.display === 'none' ? 'block' : 'none'; }; document.addEventListener('click', function() { var dd = document.getElementById('user-dropdown'); if (dd) dd.style.display = 'none'; }); /* ================================================================ Load & Auto Save Checkin ================================================================ */ window.loadCheckin = function() { var week = document.getElementById('check-date').value; if (!week) return; var currentData = buildData(); var currentStr = JSON.stringify(currentData); if (lastSavedWeek && lastSavedData !== null && currentStr !== lastSavedData) { var hasContent = currentData.morning.some(function(x){return x && x.trim();}) || currentData.evening.some(function(x){return (x.mistake||'').trim() || (x.improvement||'').trim();}) || currentData.study.some(function(x){return x.done;}); if (hasContent) { apiSaveCheckin(lastSavedWeek, currentData, function(){}); } } lastSavedWeek = week; apiGetCheckin(week, function(err, row){ if (err) { initStudyPresets(); lastSavedData = '{}'; return; } fillForm(row ? row.data : null); lastSavedData = JSON.stringify(buildData()); }); }; /** 自动保存 — 失去焦点/勾选/删除时触发 */ function triggerAutoSave() { var week = document.getElementById('check-date').value; if (!week) return; var data = buildData(); var dataStr = JSON.stringify(data); if (dataStr === lastSavedData) return; apiSaveCheckin(week, data, function(err){ if (err) { showToast('保存失败', 'error'); return; } lastSavedData = dataStr; loadStats(); }); } /** 为每周打卡面板绑定自动保存事件 */ function bindAutoSave() { var panel = document.getElementById('panel-daily'); if (!panel) return; // 输入框 & 文本域 & 下拉选择器:失去焦点时保存 panel.addEventListener('blur', function(e) { if (e.target.matches('input[type="text"], textarea, input[type="week"], select')) { triggerAutoSave(); } }, true); // 选择器:change 事件也保存(及时响应) panel.addEventListener('change', function(e) { if (e.target.matches('select.morning-pillar')) { triggerAutoSave(); } }); // 复选框:change 事件 panel.addEventListener('change', function(e) { if (e.target.matches('input[type="checkbox"]')) { triggerAutoSave(); } }); // 删除行按钮:点击后触发 panel.addEventListener('click', function(e) { var btn = e.target.closest('.btn-del'); if (btn) { setTimeout(triggerAutoSave, 100); // 等 DOM 更新后 } }); } /* ================================================================ Weekly Score ================================================================ */ var WEEKDAYS_CN = ['日','一','二','三','四','五','六']; function getMonday(d) { var day = d.getDay(); var diff = d.getDate() - day + (day === 0 ? -6 : 1); var m = new Date(d); m.setDate(diff); return m; } window.changeWeek = function(dir) { weekOffset += dir; loadWeekly(); }; function loadWeekly() { var today = new Date(); today.setDate(today.getDate() + weekOffset * 7); var wk = fmtWeek(today); document.getElementById('week-label').textContent = wk; apiGetCheckin(wk, function(err, row){ if (err) { showToast('加载失败', 'error'); return; } var dd = row ? row.data : null; if (!dd) { document.getElementById('weekly-score').textContent = '--'; document.getElementById('score-text').textContent = '本周暂无记录'; document.getElementById('score-stats').textContent = ''; document.getElementById('week-days-grid').innerHTML = ''; return; } var morning = dd.morning || []; var evening = dd.evening || []; var study = dd.study || []; var morningCount = morning.filter(function(x){ return x && typeof x === 'string' && x.trim(); }).length; if (!morningCount) { morningCount = morning.filter(function(x){ return x && typeof x === 'object' && (x.text || '').trim(); }).length; } var eveningCount = evening.filter(function(x){ var mst = typeof x === 'string' ? x : (x.mistake || ''); return mst && typeof mst === 'string' && mst.trim(); }).length; var studyCount = study.filter(function(x){ return x.done; }).length; var allThree = morningCount > 0 && eveningCount > 0 && studyCount > 0; var score, status; if (allThree) { score = 60 + (morningCount - 1) * 5 + (eveningCount - 1) * 3 + studyCount * 3; status = 'pass'; } else { score = 0; status = 'fail'; } var grade = score >= 90 ? '优秀' : score >= 75 ? '良好' : score >= 60 ? '达标' : '未达标'; document.getElementById('weekly-score').textContent = score; var ring = document.querySelector('.score-ring'); if (ring) { var R = 50, C = 2 * Math.PI * R; ring.setAttribute('stroke-dasharray', C); var ratio = Math.min(score / 100, 1); ring.setAttribute('stroke-dashoffset', C - (C * ratio)); } var txt = grade + ' · ' + score + ' 分'; document.getElementById('score-text').textContent = txt; document.getElementById('score-stats').textContent = '立志 ' + morningCount + ' · 责善 ' + eveningCount + ' · 勤学 ' + studyCount + '/8'; // 渲染周统计网格(简化版) var gridHtml = '
' + '
' + wk + '
' + '
' + grade + '
' + '
' + score + '
' + '
' + (status === 'pass' ? '达标' : '未达标') + '
' + '
'; document.getElementById('week-days-grid').innerHTML = gridHtml; }); } /* ================================================================ History ================================================================ */ function loadHistory() { apiGetHistory(function(err, rows){ var el = document.getElementById('history-grid'); if (err) { el.innerHTML = '
加载失败
'; return; } if (!rows || rows.length === 0) { el.innerHTML = '
暂无历史记录
'; return; } var html = ''; for (var i=0; i ' + morning.length + ''); if (evening.length) tags.push(' ' + evening.length + ''); if (study.length) tags.push(' ' + study.length + '/8'); html += '
' + '
' + '
' + r.date + '
' + '
' + (tags.join('') || '暂无内容') + '
' + '
' + '' + '
'; } el.innerHTML = html; }); } window.deleteHistory = function(week) { if (!confirm('确定删除 ' + week + ' 的打卡记录吗?此操作不可恢复!')) return; apiDeleteCheckin(week, function(err){ if (err) { showToast('删除失败: ' + err, 'error'); return; } showToast('已删除', 'info'); loadHistory(); loadStats(); }); }; /* ================================================================ Wishes — 心愿清单(四象限) ================================================================ */ var wishes = []; var dragSourceId = null; var dragSourceQuadrant = null; var wishesLoaded = false; var QUADRANTS = ['重要紧急', '重要不紧急', '紧急不重要', '不紧急不重要']; function normalizeQuadrant(w) { if (QUADRANTS.indexOf(w.quadrant) >= 0) return w.quadrant; // 老数据回退: priority → quadrant var map = {'高': '重要紧急', '中': '重要不紧急', '低': '不紧急不重要'}; return map[w.priority] || '重要不紧急'; } function loadWishes() { if (wishesLoaded) { renderWishes(); return; } if (window.__INITIAL_WISHES__) { wishes = window.__INITIAL_WISHES__; // 规范化 quadrant wishes.forEach(function(w){ w.quadrant = normalizeQuadrant(w); }); wishesLoaded = true; renderWishes(); return; } fetch('/api/wishes') .then(function(r){ return r.json(); }) .then(function(res){ if (res.ok) { wishes = res.data; wishesLoaded = true; renderWishes(); } }); } function renderWishes() { var emptyEl = document.getElementById('wishes-empty'); if (!wishes.length) { QUADRANTS.forEach(function(q){ document.getElementById('quad-list-' + q).innerHTML = ''; }); if (emptyEl) emptyEl.style.display = 'block'; return; } if (emptyEl) emptyEl.style.display = 'none'; // 按象限分组渲染 QUADRANTS.forEach(function(quadrant) { var list = document.getElementById('quad-list-' + quadrant); if (!list) return; var items = wishes.filter(function(w){ return normalizeQuadrant(w) === quadrant; }); var html = ''; for (var i = 0; i < items.length; i++) { var w = items[i]; var doneCls = w.done ? ' done' : ''; var deadline = w.deadline ? w.deadline : ''; html += '
' + '' + '' + '' + esc(w.name) + '' + (deadline ? '' + esc(deadline) + '' : '') + '' + '
'; } list.innerHTML = html; }); bindDragEvents(); bindEditClicks(); } /* ── 点击编辑 ── */ function bindEditClicks() { document.querySelectorAll('#panel-wishes .wish-item').forEach(function(item) { // 只在点击名称或日期区域时触发编辑(排除 checkbox / 拖拽手柄 / 删除按钮) item.addEventListener('click', function(e) { if (e.target.closest('.wish-check') || e.target.closest('.wish-drag-handle') || e.target.closest('.wish-del') || e.target.closest('.wish-edit-form')) return; var id = parseInt(this.dataset.id); var w = wishes.find(function(x){ return x.id === id; }); if (w) startEditWish(this, w); }); }); } function startEditWish(el, w) { if (el.querySelector('.wish-edit-form')) return; // 已在编辑中 el.classList.add('editing'); var deadline = w.deadline || ''; var quadOpts = QUADRANTS.map(function(q){ return ''; }).join(''); el.innerHTML = '
' + '' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
'; } window.saveEditWish = function(id, btn) { var form = btn.closest('.wish-edit-form'); var name = form.querySelector('.wish-edit-name').value.trim(); if (!name) { showToast('名称不能为空', 'error'); return; } var quadrant = form.querySelector('.wish-edit-quadrant').value; var deadline = form.querySelector('.wish-edit-deadline').value; fetch('/api/wishes/' + id, { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({name: name, quadrant: quadrant, deadline: deadline}) }).then(function(r){ return r.json(); }) .then(function(res) { if (!res.ok) { showToast(res.error, 'error'); return; } var w = wishes.find(function(x){ return x.id === id; }); if (w) { w.name = name; w.quadrant = quadrant; w.deadline = deadline; } renderWishes(); }); }; /* ── Drag & Drop (跨象限) ── */ function bindDragEvents() { var items = document.querySelectorAll('#panel-wishes .wish-item'); items.forEach(function(item) { item.addEventListener('dragstart', function(e) { dragSourceId = parseInt(this.dataset.id); dragSourceQuadrant = this.dataset.quadrant; this.classList.add('dragging'); e.dataTransfer.effectAllowed = 'move'; }); item.addEventListener('dragend', function() { this.classList.remove('dragging'); dragSourceId = null; dragSourceQuadrant = null; document.querySelectorAll('.quad-cell, .wish-item').forEach(function(el){ el.classList.remove('drag-over'); }); }); item.addEventListener('dragover', function(e) { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; this.classList.add('drag-over'); }); item.addEventListener('dragleave', function() { this.classList.remove('drag-over'); }); item.addEventListener('drop', function(e) { e.preventDefault(); e.stopPropagation(); this.classList.remove('drag-over'); var targetId = parseInt(this.dataset.id); var targetQuadrant = this.dataset.quadrant; if (dragSourceId === targetId) return; var fromIdx = -1, toIdx = -1; for (var j = 0; j < wishes.length; j++) { if (wishes[j].id === dragSourceId) fromIdx = j; if (wishes[j].id === targetId) toIdx = j; } if (fromIdx >= 0 && toIdx >= 0) { var moved = wishes.splice(fromIdx, 1)[0]; wishes.splice(toIdx, 0, moved); // 更新象限 if (dragSourceQuadrant !== targetQuadrant) { moved.quadrant = targetQuadrant; fetch('/api/wishes/' + moved.id, { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({quadrant: targetQuadrant}) }).catch(function(){ showToast('保存失败', 'error'); }); } renderWishes(); saveWishOrder(); } }); }); // 象限空区域接受 drop document.querySelectorAll('.quad-cell').forEach(function(cell) { cell.addEventListener('dragover', function(e) { if (this.querySelector('.wish-item')) return; // 有内容时让 item 处理 e.preventDefault(); this.classList.add('drag-over'); }); cell.addEventListener('dragleave', function() { this.classList.remove('drag-over'); }); cell.addEventListener('drop', function(e) { this.classList.remove('drag-over'); if (this.querySelector('.wish-item')) return; // 已由 item 处理 e.preventDefault(); var q = this.dataset.quadrant; var moved = wishes.find(function(w){ return w.id === dragSourceId; }); if (moved) { moved.quadrant = q; fetch('/api/wishes/' + moved.id, { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({quadrant: q}) }).catch(function(){ showToast('保存失败', 'error'); }); renderWishes(); } }); }); } function saveWishOrder() { var order = wishes.map(function(w){ return w.id; }); fetch('/api/wishes/reorder', { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({order: order}) }); } /* ── CRUD ── */ window.showWishForm = function() { var form = document.getElementById('wish-form'); if (form) form.style.display = 'block'; }; window.hideWishForm = function() { var form = document.getElementById('wish-form'); if (form) form.style.display = 'none'; document.getElementById('wish-name').value = ''; document.getElementById('wish-deadline').value = ''; var sel = document.getElementById('wish-quadrant'); if (sel) sel.value = '重要不紧急'; }; window.addWish = function() { var name = document.getElementById('wish-name').value.trim(); if (!name) { showToast('请输入心愿名称', 'error'); return; } var quadrant = document.getElementById('wish-quadrant').value; var deadline = document.getElementById('wish-deadline').value; fetch('/api/wishes', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({name: name, quadrant: quadrant, deadline: deadline}) }).then(function(r){ return r.json(); }) .then(function(res){ if (!res.ok) { showToast(res.error, 'error'); return; } hideWishForm(); wishes.push({id: res.id, name: name, quadrant: quadrant, deadline: deadline, done: 0}); renderWishes(); }); }; window.toggleWish = function(id, done) { fetch('/api/wishes/' + id, { method: 'PUT', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({done: done ? 1 : 0}) }); var w = wishes.find(function(x){ return x.id === id; }); if (w) w.done = done ? 1 : 0; renderWishes(); }; window.deleteWishItem = function(id) { fetch('/api/wishes/' + id, {method: 'DELETE'}); wishes = wishes.filter(function(w){ return w.id !== id; }); renderWishes(); }; window.toggleWishesEdit = function(btn) { var panel = document.getElementById('panel-wishes'); if (!panel) return; var editing = panel.classList.toggle('editing'); btn.classList.toggle('active', editing); }; window.renderWishes = renderWishes; /* ================================================================ Blueprint — 蓝图六板块 ================================================================ */ var blueprintData = null; var blueprintFilter = 'all'; function loadBlueprint() { apiGetStats(function(err, data) { if (err || !data || !data.pillar_breakdown) return; blueprintData = data.pillar_breakdown; renderBlueprintList(); }); } function renderBlueprintPillars(pb) { var container = document.getElementById('blueprint-pillars'); if (!container) return; var html = ''; PILLARS.forEach(function(p){ html += '
' + '
' + p.emoji + '
' + '
' + p.name + '
' + '
'; }); container.innerHTML = html; } function renderBlueprintList() { var list = document.getElementById('bp-list'); var empty = document.getElementById('bp-list-empty'); if (!list || !blueprintData) return; var items = []; PILLARS.forEach(function(p){ var info = blueprintData[p.name] || {}; if (blueprintFilter === 'all' || blueprintFilter === 'morning') { (info.morning_items || []).forEach(function(mi){ items.push({pillar: p, text: mi.text, type: 'morning'}); }); } if (blueprintFilter === 'all' || blueprintFilter === 'evening') { (info.evening_items || []).forEach(function(ei){ items.push({pillar: p, text: ei.mistake || ei.improvement, improvement: ei.improvement, type: 'evening'}); }); } if (blueprintFilter === 'all' || blueprintFilter === 'study') { (info.study_items || []).forEach(function(si){ items.push({pillar: p, text: si.name, type: 'study', done: si.done, note: si.note}); }); } }); if (items.length === 0) { list.innerHTML = ''; if (empty) empty.style.display = 'block'; return; } if (empty) empty.style.display = 'none'; var typeLabels = {morning: '立志', evening: '责善', study: '勤学'}; var pillarColors = { '医疗服务': '#4A6CF7', '医药营销': '#D97706', '医疗支付': '#059669', 'AI 智能': '#7C3AED', '公司治理': '#DC2626', '个人修养': '#0891B2' }; var html = ''; items.forEach(function(item){ var dot = ''; var extra = ''; if (item.type === 'study' && item.note) extra = '' + esc(item.note) + ''; if (item.type === 'evening' && item.improvement) extra = '→ ' + esc(item.improvement) + ''; html += '
' + dot + '' + item.pillar.name + '' + '' + (typeLabels[item.type] || item.type) + '' + '' + esc(item.text) + '' + extra + '
'; }); list.innerHTML = html; } window.filterBlueprint = function(btn) { blueprintFilter = btn.dataset.filter; document.querySelectorAll('.bp-tab').forEach(function(t){ t.classList.remove('active'); }); btn.classList.add('active'); renderBlueprintList(); }; /* ================================================================ Init ================================================================ */ function init() { var today = new Date(); calYear = today.getFullYear(); var cd = document.getElementById('check-date'); var todayWk = fmtWeek(today); if (cd) cd.value = todayWk; selectedWeek = todayWk; initStudyPresets(); bindAutoSave(); lastSavedWeek = todayWk; // 从页面嵌入数据获取初始统计(0 延迟) if (window.__INITIAL_STATS__) { var s = window.__INITIAL_STATS__; document.getElementById('stat-days').textContent = s.total_weeks; document.getElementById('stat-morning').textContent = s.total_morning; document.getElementById('stat-study').textContent = s.total_study; calendarStatus = s.calendar || {}; } loadCheckin(); loadStats(); renderCalendar(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();