From 979e7fd0971817b9ec2b739a64b5cd2f2becf5df Mon Sep 17 00:00:00 2001 From: mac Date: Tue, 28 Jul 2026 19:33:17 +0800 Subject: [PATCH] =?UTF-8?q?v2.2.0=20=E2=80=94=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E8=AF=84=E5=88=86+=E5=BF=83=E6=84=BF=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=88HTML/JS/CSS/Python=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 54 +------ database.py | 79 +--------- static/app.js | 364 ------------------------------------------- static/style.css | 356 ------------------------------------------ templates/index.html | 94 ----------- 5 files changed, 4 insertions(+), 943 deletions(-) diff --git a/app.py b/app.py index 078a9ee..e27d31a 100644 --- a/app.py +++ b/app.py @@ -6,7 +6,7 @@ from datetime import timedelta from functools import wraps from flask import Flask, render_template, request, jsonify, session, redirect, url_for from werkzeug.security import generate_password_hash, check_password_hash -from database import init_db, get_checkin, save_checkin, delete_checkin, get_all_checkins, get_weeks_list, get_daily_backup, get_wishes, save_wish, update_wish, delete_wish, reorder_wishes +from database import init_db, get_checkin, save_checkin, delete_checkin, get_all_checkins, get_weeks_list, get_daily_backup app = Flask(__name__) # 固定密钥确保 gunicorn 多 worker 下 session 可互通 @@ -201,11 +201,9 @@ def compute_stats(): def index(): import json stats = compute_stats() - wishes = [dict(w) for w in get_wishes()] return render_template('index.html', username=session.get('display_name', session.get('username', '')), - initial_stats=json.dumps(stats, ensure_ascii=False), - initial_wishes=json.dumps(wishes, ensure_ascii=False)) + initial_stats=json.dumps(stats, ensure_ascii=False)) # ── API ────────────────────────────────────────────── @@ -282,54 +280,6 @@ def api_user(): }) -# ── 心愿清单 API ────────────────────────────── - -@app.route('/api/wishes', methods=['GET']) -@login_required -def api_get_wishes(): - wishes = [dict(w) for w in get_wishes()] - return jsonify({'ok': True, 'data': wishes}) - - -@app.route('/api/wishes', methods=['POST']) -@login_required -def api_create_wish(): - body = request.get_json(force=True) - name = body.get('name', '').strip() - if not name: - return jsonify({'ok': False, 'error': '名称不能为空'}), 400 - quadrant = body.get('quadrant', '重要不紧急') - deadline = body.get('deadline', '') - wid = save_wish(name, quadrant, deadline) - return jsonify({'ok': True, 'id': wid}) - - -@app.route('/api/wishes/', methods=['PUT']) -@login_required -def api_update_wish(wish_id): - body = request.get_json(force=True) - update_wish(wish_id, **body) - return jsonify({'ok': True}) - - -@app.route('/api/wishes/', methods=['DELETE']) -@login_required -def api_delete_wish(wish_id): - delete_wish(wish_id) - return jsonify({'ok': True}) - - -@app.route('/api/wishes/reorder', methods=['PUT']) -@login_required -def api_reorder_wishes(): - body = request.get_json(force=True) - order = body.get('order', []) - if not isinstance(order, list): - return jsonify({'ok': False, 'error': 'order 必须是列表'}), 400 - reorder_wishes(order) - return jsonify({'ok': True}) - - # ── 日历同步 API ──────────────────────────── CALENDAR_CACHE = os.path.join(os.path.expanduser('~'), '.workbuddy', 'data', 'ziwei-power', 'calendar_cache.json') diff --git a/database.py b/database.py index 6e71b64..d283140 100644 --- a/database.py +++ b/database.py @@ -11,7 +11,7 @@ os.makedirs(DB_DIR, exist_ok=True) DB_PATH = os.path.join(DB_DIR, 'ziwei_power.db') # 当前数据库 schema 版本 —— 改表结构时必须 +1 并补迁移逻辑 -CURRENT_SCHEMA_VERSION = 4 +CURRENT_SCHEMA_VERSION = 2 def get_conn(): @@ -56,26 +56,7 @@ def init_db(): ''') if current < 2: - # v2: 心愿清单 - conn.execute(''' - CREATE TABLE IF NOT EXISTS wishes ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - priority TEXT NOT NULL DEFAULT '中', - deadline TEXT NOT NULL DEFAULT '', - done INTEGER NOT NULL DEFAULT 0, - sort_order INTEGER NOT NULL DEFAULT 0, - created_at TEXT NOT NULL - ) - ''') - - if current < 3: - # v3: 优先级改为四象限 - conn.execute("ALTER TABLE wishes ADD COLUMN quadrant TEXT NOT NULL DEFAULT '重要不紧急'") - conn.execute("UPDATE wishes SET quadrant = CASE priority WHEN '高' THEN '重要紧急' WHEN '中' THEN '重要不紧急' WHEN '低' THEN '不紧急不重要' ELSE '重要不紧急' END WHERE quadrant = '重要不紧急'") - - if current < 4: - # v4: 日打卡 → 周打卡 + # v2: 日打卡 → 周打卡 # 备份旧表 → 聚合 → 新建周表 existing = conn.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='checkins'").fetchone() if existing: @@ -170,62 +151,6 @@ def get_all_checkins(): return results -# ── 心愿清单 CRUD ────────────────────────────────── - -def get_wishes(): - """获取所有心愿,按 sort_order 排序""" - conn = get_conn() - rows = conn.execute('SELECT * FROM wishes ORDER BY sort_order').fetchall() - conn.close() - return [dict(row) for row in rows] - - -def save_wish(name, quadrant, deadline): - """新增一条心愿""" - now = datetime.now().isoformat() - conn = get_conn() - max_order = conn.execute('SELECT COALESCE(MAX(sort_order), -1) + 1 AS n FROM wishes').fetchone()['n'] - conn.execute( - 'INSERT INTO wishes (name, quadrant, deadline, done, sort_order, created_at) VALUES (?, ?, ?, 0, ?, ?)', - (name, quadrant, deadline, max_order, now) - ) - conn.commit() - wish_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0] - conn.close() - return wish_id - - -def update_wish(wish_id, **kwargs): - """更新心愿字段""" - allowed = ['name', 'quadrant', 'deadline', 'done'] - updates = {k: v for k, v in kwargs.items() if k in allowed} - if not updates: - return - conn = get_conn() - sets = ', '.join(f'{k} = ?' for k in updates) - vals = list(updates.values()) + [wish_id] - conn.execute(f'UPDATE wishes SET {sets} WHERE id = ?', vals) - conn.commit() - conn.close() - - -def delete_wish(wish_id): - """删除心愿""" - conn = get_conn() - conn.execute('DELETE FROM wishes WHERE id = ?', (wish_id,)) - conn.commit() - conn.close() - - -def reorder_wishes(order_list): - """批量更新排序:order_list = [id1, id2, ...]""" - conn = get_conn() - for idx, wid in enumerate(order_list): - conn.execute('UPDATE wishes SET sort_order = ? WHERE id = ?', (idx, wid)) - conn.commit() - conn.close() - - def get_weeks_list(): """返回所有已有打卡记录的周号列表""" conn = get_conn() diff --git a/static/app.js b/static/app.js index 52289c1..ec17231 100644 --- a/static/app.js +++ b/static/app.js @@ -9,7 +9,6 @@ var calYear; var calMonth = new Date().getMonth(); // 月份索引 0-11 var activePanel = 'daily'; - var weekOffset = 0; var lastSavedData = null; var lastSavedWeek = null; var selectedWeek = null; @@ -114,9 +113,7 @@ if (nav) nav.classList.add('active'); if (panel) panel.classList.add('active'); - if (name === 'weekly') loadWeekly(); if (name === 'history') loadHistory(); - if (name === 'wishes') loadWishes(); if (name === 'blueprint') loadBlueprint(); }; @@ -712,95 +709,6 @@ }); } - /* ================================================================ - 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 ================================================================ */ @@ -855,278 +763,6 @@ }); }; - /* ================================================================ - 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 — 蓝图六板块 ================================================================ */ diff --git a/static/style.css b/static/style.css index 4c670e9..473435c 100644 --- a/static/style.css +++ b/static/style.css @@ -1070,172 +1070,6 @@ body { .btn-save:active { transform: translateY(0); } -/* ═══════════════════════════════════════════ - Weekly Panel - ═══════════════════════════════════════════ */ - -.week-nav { - display: flex; - align-items: center; - justify-content: center; - gap: 20px; - padding: 8px 0 20px; -} - -.btn-nav { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 8px 16px; - border: 1.5px solid var(--border); - background: var(--card); - border-radius: var(--radius-sm); - font-size: 13px; - font-weight: 500; - cursor: pointer; - color: var(--text); - transition: all 0.2s; - font-family: inherit; -} - -.btn-nav:hover { - border-color: var(--primary); - color: var(--primary); - background: var(--primary-light); -} - -#week-label { - font-size: 14px; - font-weight: 600; - min-width: 200px; - text-align: center; - color: var(--text); -} - -.weekly-overview { - display: flex; - align-items: center; - gap: 40px; - padding: 20px 0; - justify-content: center; -} - -.score-circle { - position: relative; - width: 140px; - height: 140px; - flex-shrink: 0; -} - -.score-svg { - width: 140px; - height: 140px; -} - -.score-svg circle { - transition: stroke-dashoffset 0.8s cubic-bezier(0.4, 0, 0.2, 1); -} - -.score-inner { - position: absolute; - top: 50%; left: 50%; - transform: translate(-50%, -50%); - display: flex; - align-items: baseline; - justify-content: center; -} - -.score-num { - font-size: 40px; - font-weight: 800; - color: var(--primary); - line-height: 1; -} - -.score-unit { - font-size: 15px; - color: var(--text-muted); - margin-left: 2px; - font-weight: 500; -} - -.score-meta { - display: flex; - flex-direction: column; - gap: 8px; -} - -.score-text { - font-size: 15px; - font-weight: 600; - color: var(--text); -} - -.score-stats { - font-size: 13px; - color: var(--text-muted); - line-height: 1.6; -} - -.week-days-grid { - display: grid; - grid-template-columns: repeat(7, 1fr); - gap: 8px; - margin-top: 24px; -} - -.day-cell { - background: var(--card); - border-radius: var(--radius-sm); - padding: 12px 8px; - text-align: center; - box-shadow: var(--shadow); - transition: box-shadow 0.2s; - border-top: 3px solid transparent; -} - -.day-cell:hover { box-shadow: var(--shadow-hover); } - -.day-cell.pass { border-top-color: var(--success); } -.day-cell.fail { border-top-color: var(--warning); } -.day-cell.empty { border-top-color: var(--border); opacity: 0.5; } - -.day-cell .day-label { - font-size: 11px; - color: var(--text-muted); - margin-bottom: 4px; - font-weight: 500; -} - -.day-cell .day-date { - font-size: 12px; - font-weight: 600; - color: var(--text); - margin-bottom: 6px; -} - -.day-cell .day-score { - font-size: 18px; - font-weight: 700; -} - -.day-cell.pass .day-score { color: var(--success); } -.day-cell.fail .day-score { color: var(--warning); } -.day-cell.empty .day-score { color: var(--text-muted); } - -.day-cell .day-badge { - display: inline-block; - padding: 2px 8px; - border-radius: 10px; - font-size: 10px; - font-weight: 600; - margin-top: 4px; -} - -.day-cell.pass .day-badge { background: var(--success-light); color: var(--success); } -.day-cell.fail .day-badge { background: var(--warning-light); color: #D97706; } -.day-cell.empty .day-badge { background: var(--bg); color: var(--text-muted); } - /* ═══════════════════════════════════════════ History Panel ═══════════════════════════════════════════ */ @@ -1468,190 +1302,6 @@ body { justify-content: flex-end; flex-shrink: 0; } -.sync-modal-footer .btn-wish-save { - width: auto; - padding: 8px 24px; -} - -/* ═══════════════════════════════════════════ - Wishes — 四象限 - ═══════════════════════════════════════════ */ - -#panel-wishes.editing .edit-only { display: inline-flex; } -#panel-wishes.editing .wish-del { display: inline-flex; } - -.wish-form { - background: var(--bg); - border-radius: var(--radius-sm); - padding: 10px 12px; - margin-bottom: 12px; - max-width: 480px; -} -.wish-form input[type="text"], -.wish-form input[type="date"], -.wish-form select { - width: 100%; - padding: 8px 10px; - border: 1.5px solid var(--border); - border-radius: var(--radius-sm); - font-size: 13px; - font-family: inherit; - color: var(--text); - margin-bottom: 8px; - box-sizing: border-box; - background: var(--card); -} -.wish-form input:focus, .wish-form select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(74,108,247,0.08); -} -.wish-form-row { display: flex; gap: 8px; } -.wish-form-row select, .wish-form-row input { flex: 1; } -.wish-form-actions { display: flex; gap: 8px; } -.btn-wish-save { - flex: 1; padding: 8px; border: none; background: var(--primary); color: #FFF; - border-radius: var(--radius-sm); font-size: 13px; font-weight: 500; - cursor: pointer; font-family: inherit; -} -.btn-wish-save:hover { background: var(--primary-dark); } -.btn-wish-cancel { - flex: 1; padding: 8px; border: 1.5px solid var(--border); background: var(--card); - color: var(--text-dim); border-radius: var(--radius-sm); font-size: 13px; - cursor: pointer; font-family: inherit; -} - -/* 四象限网格 */ -.quad-grid { - display: grid; - grid-template-columns: 1fr 1fr; - grid-template-rows: 1fr 1fr; - gap: 12px; - min-height: 400px; -} - -.quad-cell { - background: var(--card); - border: 1.5px solid var(--border); - border-radius: var(--radius); - padding: 12px 14px; - display: flex; - flex-direction: column; - min-height: 180px; - transition: border-color 0.2s, box-shadow 0.2s; -} -.quad-cell.drag-over { - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(74,108,247,0.10); - background: var(--primary-light); -} - -.quad-title { - font-size: 13px; - font-weight: 600; - color: var(--text); - margin-bottom: 10px; - padding-bottom: 8px; - border-bottom: 1px solid var(--border); - flex-shrink: 0; -} - -.quad-list { - flex: 1; - display: flex; - flex-direction: column; - gap: 4px; - min-height: 40px; -} - -.wish-item { - display: flex; - align-items: center; - gap: 8px; - padding: 7px 10px; - border-radius: var(--radius-sm); - background: var(--bg); - transition: opacity 0.15s, box-shadow 0.15s; -} -.wish-item:hover { box-shadow: 0 1px 3px rgba(0,0,0,0.06); } -.wish-item.dragging { opacity: 0.3; } -.wish-item.drag-over { - box-shadow: inset 0 0 0 2px var(--primary); - background: var(--card); -} - -.wish-drag-handle { - color: var(--text-muted); cursor: grab; flex-shrink: 0; - display: flex; align-items: center; -} -.wish-drag-handle:active { cursor: grabbing; } - -.wish-check { - width: 15px; height: 15px; accent-color: var(--success); - flex-shrink: 0; cursor: pointer; -} - -.wish-name { - flex: 1; font-size: 13px; color: var(--text); min-width: 0; - overflow: hidden; text-overflow: ellipsis; white-space: nowrap; -} -.wish-item.done .wish-name { text-decoration: line-through; color: var(--text-muted); } - -.wish-deadline { - font-size: 11px; color: var(--text-dim); white-space: nowrap; flex-shrink: 0; -} - -.wish-del { display: none; } -.wish-del .icon-xs { width: 13px; height: 13px; } - -/* 内联编辑 */ -.wish-item.editing { - background: var(--card); - padding: 8px 10px; - flex-wrap: wrap; -} -.wish-edit-form { - width: 100%; - display: flex; - flex-direction: column; - gap: 6px; -} -.wish-edit-form input[type="text"], -.wish-edit-form input[type="date"], -.wish-edit-form select { - width: 100%; - padding: 6px 8px; - border: 1.5px solid var(--border); - border-radius: var(--radius-sm); - font-size: 12px; - font-family: inherit; - color: var(--text); - background: var(--card); - box-sizing: border-box; -} -.wish-edit-form input:focus, -.wish-edit-form select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 2px rgba(74,108,247,0.08); -} -.wish-edit-name { font-weight: 500; } -.wish-edit-row { display: flex; gap: 6px; } -.wish-edit-row select, -.wish-edit-row input { flex: 1; } -.wish-edit-actions { display: flex; gap: 6px; } -.wish-edit-actions .btn-wish-save, -.wish-edit-actions .btn-wish-cancel { - flex: 1; padding: 6px; font-size: 12px; -} - -.wishes-empty { - font-size: 13px; color: var(--text-muted); text-align: center; padding: 32px 0; -} - -@media (max-width: 900px) { - .quad-grid { grid-template-columns: 1fr; grid-template-rows: auto; } -} /* ═══════════════════════════════════════════ SVG icons helpers @@ -1669,8 +1319,6 @@ body { :root { --sidebar-w: 240px; } .main-content { padding: 20px 24px; } .daily-grid { grid-template-columns: 1fr; } - .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; } } @@ -1778,10 +1426,6 @@ body { padding: 32px 0; } -@media (max-width: 900px) { - .quad-grid { grid-template-columns: 1fr; grid-template-rows: auto; } -} - /* 勤学打卡卡片 - 单行样式 */ #study-cards { display: flex; flex-direction: column; gap: 8px; } .study-card { position:relative; display:flex; align-items:center; gap:12px; padding:10px 14px; border:1px solid var(--border); border-radius:var(--radius-sm); background:var(--card); transition:all 0.15s; } diff --git a/templates/index.html b/templates/index.html index ab7f1b8..0ab8038 100644 --- a/templates/index.html +++ b/templates/index.html @@ -6,7 +6,6 @@ 紫微 · 磁场管理 - {% include "icons.html" %} @@ -73,14 +72,6 @@ 打卡 - - - 评分 - - - - 心愿 - 记录 @@ -219,41 +210,6 @@ - -
-
-

每周评分

-
-
- - -- - -
-
-
- - - - -
- -- - -
-
-
- 选择一周查看评分 -
-
-
-
-
-
@@ -262,56 +218,6 @@
- -
-
-

心愿清单

- -
- - - - -
-
-
重要 & 紧急
-
-
-
-
重要 & 不紧急
-
-
-
-
紧急 & 不重要
-
-
-
-
不紧急 & 不重要
-
-
-
- -
-