From 2d6eb4dc35951d7ad7dfe442d158bbe42d28455f Mon Sep 17 00:00:00 2001 From: mac Date: Tue, 2 Jun 2026 23:31:46 +0800 Subject: [PATCH] =?UTF-8?q?v1.0.0=20=E2=80=94=20=E8=AF=84=E5=88=86?= =?UTF-8?q?=E8=A7=84=E5=88=99=E5=A4=A7=E6=94=B9=20&=20UI=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 责善改过:纵向排列、输入框样式对齐立志、扁平化去内层卡片嵌套 - 自动保存:blur 触发替代 input 防抖,静默保存 - 日评分:3项全有 → 60分 + 多出条数×5;缺失 → 条数×5 - 周评分:日峰值累加制,取消百分比上限 - 修复 preset-note 溢出、清理冗余代码 --- app.py | 27 +++++++--------- static/app.js | 83 ++++++++++++++++++++++-------------------------- static/style.css | 42 +++++++++++++++--------- 3 files changed, 77 insertions(+), 75 deletions(-) diff --git a/app.py b/app.py index d3374c3..9074901 100644 --- a/app.py +++ b/app.py @@ -84,26 +84,23 @@ def compute_stats(): evening = data.get('evening', []) study = data.get('study', []) - total_morning += sum(1 for x in morning if isinstance(x, str) and x.strip()) - total_evening += sum(1 for x in evening if ( + morning_count = sum(1 for x in morning if isinstance(x, str) and x.strip()) + evening_count = sum(1 for x in evening if ( isinstance(x, str) and x.strip() or isinstance(x, dict) and (x.get('mistake', '') or '').strip() )) - total_study += sum(1 for x in study if x.get('done')) + study_count = sum(1 for x in study if x.get('done')) - day_score = 0 - has_morning = any(isinstance(x, str) and x.strip() for x in morning) - has_evening = any( - (isinstance(x, str) and x.strip()) or - (isinstance(x, dict) and (x.get('mistake', '') or '').strip()) - for x in evening - ) - has_study = any(x.get('done') for x in study) - if has_morning: day_score += 1 - if has_evening: day_score += 1 - if has_study: day_score += 1 + total_morning += morning_count + total_evening += evening_count + total_study += study_count - calendar[d] = 'pass' if day_score >= 2 else 'fail' + # 新评分:3 项都有 → 达标 60 分 + 额外加分 + all_three = morning_count > 0 and evening_count > 0 and study_count > 0 + if all_three: + extra = (morning_count - 1) + (evening_count - 1) + (study_count - 1) + # day_score = 60 + extra * 5 (不在此处使用,仅用于日历状态) + calendar[d] = 'pass' if all_three else 'fail' return dict( total_days=total_days, total_morning=total_morning, diff --git a/static/app.js b/static/app.js index 9977df5..ee9e7ec 100644 --- a/static/app.js +++ b/static/app.js @@ -9,7 +9,6 @@ var calYear, calMonth; // 日历显示的月份 var activePanel = 'daily'; // 当前面板 var weekOffset = 0; // 每周评分偏移 - var autoSaveTimer = null; // 自动保存防抖 var lastSavedData = null; // 上次保存快照 var lastSavedDate = null; // 上次保存日期 var selectedDate = null; // 日历中选中日期 @@ -399,7 +398,6 @@ /* ================================================================ Load & Auto Save Checkin ================================================================ */ - var lastSavedData = null; // 上次保存的数据快照,避免重复保存 window.loadCheckin = function() { var date = document.getElementById('check-date').value; @@ -426,22 +424,18 @@ }); }; - /** 自动保存(带防抖) */ + /** 自动保存 — 失去焦点/勾选/删除时触发 */ function triggerAutoSave() { - clearTimeout(autoSaveTimer); - autoSaveTimer = setTimeout(function() { - var date = document.getElementById('check-date').value; - if (!date) return; - var data = buildData(); - var dataStr = JSON.stringify(data); - if (dataStr === lastSavedData) return; // 无变化,跳过 - apiSaveCheckin(date, data, function(err){ - if (err) { showToast('自动保存失败', 'error'); return; } - lastSavedData = dataStr; - showToast('已自动保存', 'info'); - loadStats(); - }); - }, 1500); + var date = document.getElementById('check-date').value; + if (!date) return; + var data = buildData(); + var dataStr = JSON.stringify(data); + if (dataStr === lastSavedData) return; + apiSaveCheckin(date, data, function(err){ + if (err) { showToast('保存失败', 'error'); return; } + lastSavedData = dataStr; + loadStats(); + }); } /** 为每日打卡面板绑定自动保存事件 */ @@ -449,12 +443,12 @@ var panel = document.getElementById('panel-daily'); if (!panel) return; - // 输入框 & 文本域:input 事件 - panel.addEventListener('input', function(e) { + // 输入框 & 文本域:失去焦点时保存 + panel.addEventListener('blur', function(e) { if (e.target.matches('input[type="text"], textarea, input[type="date"]')) { triggerAutoSave(); } - }); + }, true); // 复选框:change 事件 panel.addEventListener('change', function(e) { @@ -470,13 +464,6 @@ setTimeout(triggerAutoSave, 100); // 等 DOM 更新后 } }); - - // 预设项目勾选切换 - panel.addEventListener('change', function(e) { - if (e.target.matches('.preset-check input[type="checkbox"]')) { - triggerAutoSave(); - } - }); } /* ================================================================ @@ -522,21 +509,27 @@ if (dd) { totalDays++; - var dayScore = 0; var morning = dd.morning || []; - var hasMorning = morning.some(function(x){ return x && typeof x === 'string' && x.trim(); }); var evening = dd.evening || []; - var hasEvening = evening.some(function(x){ + var study = dd.study || []; + + var morningCount = morning.filter(function(x){ return x && typeof x === 'string' && x.trim(); }).length; + var eveningCount = evening.filter(function(x){ var mst = typeof x === 'string' ? x : (x.mistake || ''); return mst && typeof mst === 'string' && mst.trim(); - }); - var study = dd.study || []; - var hasStudy = study.some(function(x){ return x.done; }); - if (hasMorning) dayScore++; - if (hasEvening) dayScore++; - if (hasStudy) dayScore++; + }).length; + var studyCount = study.filter(function(x){ return x.done; }).length; + + var allThree = morningCount > 0 && eveningCount > 0 && studyCount > 0; + var dayScore, status; + if (allThree) { + dayScore = 60 + (morningCount - 1 + eveningCount - 1 + studyCount - 1) * 5; + status = 'pass'; + } else { + dayScore = (morningCount + eveningCount + studyCount) * 5; + status = 'fail'; + } totalScore += dayScore; - var status = dayScore >= 2 ? 'pass' : 'fail'; dayCells.push({ ds: ds, dayScore: dayScore, status: status, @@ -550,21 +543,21 @@ } } - var score = totalDays > 0 ? Math.round((totalScore / (totalDays * 3)) * 100) : 0; + var score = totalScore; 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); - ring.setAttribute('stroke-dashoffset', C - (C * score / 100)); + ring.setAttribute('stroke-dashoffset', C - (C * totalDays / 7)); } var txt = ''; - if (score >= 90) txt = '卓越!磁场非常强大'; - else if (score >= 70) txt = '良好,继续保持'; - else if (score >= 50) txt = '一般,需要加强'; - else txt = '较弱,急需调整'; + if (totalDays >= 7) txt = '全勤!本周每天都有记录'; + else if (totalDays >= 5) txt = '良好,保持了大部分记录'; + else if (totalDays >= 3) txt = '一般,需要更规律打卡'; + else txt = '本周记录偏少,加油!'; document.getElementById('score-text').textContent = txt; var completedDays = dayCells.filter(function(c){ return c.status === 'pass'; }).length; @@ -577,11 +570,11 @@ var cell = dayCells[g]; var dateParts = cell.ds.split('-'); var shortDate = dateParts[1] + '/' + dateParts[2]; - var badgeText = cell.status === 'pass' ? '完成' : (cell.status === 'fail' ? '未达标' : '未打卡'); + var badgeText = cell.status === 'pass' ? '达标' : (cell.status === 'fail' ? '未达标' : '未打卡'); gridHtml += '
' + '
' + cell.weekday + '
' + '
' + shortDate + '
' + - '
' + cell.dayScore + '/3
' + + '
' + cell.dayScore + '
' + '
' + badgeText + '
' + '
'; } diff --git a/static/style.css b/static/style.css index c0195a2..b1a00a3 100644 --- a/static/style.css +++ b/static/style.css @@ -618,17 +618,14 @@ body { /* 责善改过 横排双输入 */ .evening-row { - border: 1px solid var(--border); - border-radius: var(--radius-sm); - padding: 12px 10px 10px; - margin-bottom: 10px; - background: var(--bg); - transition: border-color 0.2s; + padding: 0 0 12px; + margin-bottom: 12px; + border-bottom: 1px solid var(--border); } -.evening-row:focus-within { - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(74,108,247,0.06); +.evening-row:last-child { + border-bottom: none; + margin-bottom: 0; } .evening-header { @@ -645,10 +642,10 @@ body { } .mistake-row { - display: grid; - grid-template-columns: 1fr 1fr; + display: flex; + flex-direction: column; gap: 8px; - align-items: start; + align-items: stretch; } .mistake-row .col { @@ -664,7 +661,23 @@ body { padding-left: 2px; } -.mistake-row input[type="text"] { width: 100%; } +.mistake-row input[type="text"] { + width: 100%; + padding: 9px 12px; + border: 1.5px solid var(--border); + border-radius: var(--radius-sm); + font-size: 13px; + font-family: inherit; + color: var(--text); + background: var(--bg); + transition: border-color 0.2s, background 0.2s; +} +.mistake-row input[type="text"]:focus { + outline: none; + border-color: var(--primary); + background: var(--card); + box-shadow: 0 0 0 3px rgba(74,108,247,0.08); +} /* 勤学预设项目 */ @@ -705,7 +718,7 @@ body { .preset-note { display: none; - width: 100%; + width: calc(100% - 24px); margin-top: 6px; margin-left: 24px; padding: 6px 10px; @@ -1088,7 +1101,6 @@ body { .weekly-overview { flex-direction: column; gap: 16px; text-align: center; } .week-days-grid { grid-template-columns: repeat(4, 1fr); } .history-grid { grid-template-columns: 1fr; } - .mistake-row { grid-template-columns: 1fr; } } @media (max-width: 640px) {