吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2354|回复: 130
上一主题 下一主题
收起左侧

[其他原创] html智能网页工作日历备忘录(简单、快速、流行元素)

  [复制链接]
跳转到指定楼层
楼主
dada02 发表于 2025-12-10 18:20 回帖奖励
本帖最后由 dada02 于 2025-12-12 09:15 编辑

html智能网页工作日历备忘录

【写在前面:看到网友写的日历备忘录,总感觉差点什么,恰好其他网友有任务发布类需求,就按现代流行元素设计一款,快速记录工作事务、岁月痕迹】









功能介绍

  • 多种配色方案切换
  • 支持任务发布,如区间起始日期
  • 显示月份可选择1-12个月日历,默认显示2个月
  • 每月日历显示进度,任务数量、完成数量、未完成数量,支持一键完成
  • 每月日历左右有月份导航,前一月和下一月
  • 每天日历点击空白增加或标题修改
  • 支持日历快速搜索。
  • 支持到期弹窗提醒
  • 支持定时导出数据
  • 数据存储在浏览器数据库中,容量至少100M以上。

关键代码

        // 打开备忘录编辑模态窗口
        function openMemoModal(memoId = null, date = null) {
            const modal = document.getElementById('memoModal');
            const form = document.getElementById('memoForm');
            const deleteBtn = document.getElementById('deleteMemo');
            const modalTitle = document.querySelector('.modal-title');

            selectedMemoId = memoId;

            form.reset();

            initColorPicker();

            const today = new Date();
            const year = today.getFullYear();
            const month = String(today.getMonth() + 1).padStart(2, '0');
            const day = String(today.getDate()).padStart(2, '0');

            if (date) {
                const dateYear = date.getFullYear();
                const dateMonth = String(date.getMonth() + 1).padStart(2, '0');
                const dateDay = String(date.getDate()).padStart(2, '0');
                document.getElementById('memoDate').value = `${dateYear}-${dateMonth}-${dateDay}`;
            } else {
                document.getElementById('memoDate').value = `${year}-${month}-${day}`;
            }
                        ...
        // 一键完成本月所有备忘录
        function completeAllMemosForMonth(month, year) {
            if (!db) return;

            const monthStart = new Date(year, month, 1);
            const monthEnd = new Date(year, month + 1, 0);

            const monthStartStr = monthStart.toISOString().split('T')[0];
            const monthEndStr = monthEnd.toISOString().split('T')[0];

            if (!confirm(`确定要将${year}年${month+1}月的所有备忘录标记为已完成吗?`)) {
                return;
            }

            const transaction = db.transaction(['memos'], 'readwrite');
            const store = transaction.objectStore('memos');
            const dateIndex = store.index('date');

            const range = IDBKeyRange.bound(monthStartStr, monthEndStr);
            const request = dateIndex.openCursor(range);

            let completedCount = 0;

            request.onsuccess = function(event) {
                const cursor = event.target.result;
                if (cursor) {
                    const memo = cursor.value;
                    if (!memo.completed) {
                        memo.completed = true;
                        memo.updatedAt = new Date().toISOString();

                        const updateRequest = cursor.update(memo);
                        updateRequest.onsuccess = function() {
                            completedCount++;
                            cursor.continue();
                        };
                    } else {
                        cursor.continue();
                    }
                } else {
                    alert(`已成功将 ${completedCount} 个备忘录标记为完成!`);

                    renderMultiMonthCalendar();
                    updateRecentTasks();
                    updateStats();
                    updatePendingBadge();
                    updateReminderBadge();

                    if (document.getElementById('dailyDetailModal').classList.contains('active')) {
                        loadDailyDetailMemos(dailyDetailDate);
                    }
                }
            };
                        ...

附件

解压到文件夹,双击网页文件浏览器打开,网页操作。

更新

12.12
增加农历版本
12.11
增加导出Excel
增加备忘录详情和最近任务的日期显示,如:2025/12/11 - 2025/12/26
优化单月显示宽度和居中
12.10
保存配色方案
优化配色方案

欢迎试用。

智能网页工作日历备忘录-插件联机版.rar

25.54 KB, 下载次数: 288, 下载积分: 吾爱币 -1 CB

5. 增加导出Excel,解压密码:52pojie

智能网页工作日历备忘录-插件本机版.rar

750.35 KB, 下载次数: 387, 下载积分: 吾爱币 -1 CB

5. 增加导出Excel,解压密码:52pojie

智能网页工作日历备忘录-插件本机版.rar

777.45 KB, 下载次数: 0, 下载积分: 吾爱币 -1 CB

6. 增加农历版,解压密码:52pojie

智能网页工作日历备忘录-插件联机版-农历.rar

27.02 KB, 下载次数: 0, 下载积分: 吾爱币 -1 CB

6. 增加农历版,解压密码:52pojie

免费评分

参与人数 33吾爱币 +37 热心值 +26 收起 理由
yzy93 + 1 + 1 谢谢@Thanks!
poplar19 + 1 + 1 谢谢@Thanks!
sindy1983 + 1 + 1 楼主是否可以把便笺和日历这种合并在一起使用
tohyueyun + 1 用心讨论,共获提升!
Gandalf + 1 谢谢@Thanks!
无尘浪子 + 1 谢谢@Thanks!
tunis + 1 + 1 我很赞同!
17031991585 + 1 + 1 我很赞同!
ToDesk01 + 1 + 1 优秀的楼主
top7777 + 1 + 1 谢谢@Thanks!
悦来客栈的老板 + 1 + 1 我很赞同!
ptime + 1 谢谢@Thanks!
鸣蜩十四 + 1 + 1 谢谢@Thanks!
elan + 1 + 1 谢谢@Thanks!
shiys8 + 1 + 1 导出导入能增加。xlsx格式吗
shengruqing + 1 热心回复!
lzshwr + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
fengkuang658 + 1 + 1 谢谢@Thanks!
xieyang + 1 + 1 用心讨论,共获提升!
zr2019 + 1 + 1 谢谢@Thanks!
emake + 1 我很赞同!
jimjinhu + 1 + 1 谢谢@Thanks!
快乐的小驹 + 1 谢谢@Thanks!
mrhs + 1 + 1 谢谢@Thanks!
laozhang4201 + 1 + 1 我很赞同!
trtsky123 + 1 谢谢@Thanks!
hrh123 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
nicen2 + 1 + 1 我很赞同!
xinianin + 1 + 1 看着蛮不错的,正好缺类似的工具。
Sodifficult + 1 谢谢@Thanks!
lllfff + 1 + 1 谢谢@Thanks!
cjcmxc + 1 + 1 我很赞同!
cqfyaaa + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
 楼主| dada02 发表于 2025-12-11 10:42 |楼主
本帖最后由 dada02 于 2025-12-12 06:41 编辑
frayktju 发表于 2025-12-11 10:31
希望可以设置每周第一天为周一而不是周日

目前是通用日历插件,这个后续研究一下
推荐
aila888 发表于 2025-12-11 17:28
这个不错。我优化了一下,1.解决日历单月太大问题,2添加 Firebase 同步功能,需要自己修改代码,如果嫌麻烦就用导出功能去同步
[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>智能网页工作日历备忘录</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>

    <!-- &#128313; Firebase SDK -->
    <script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-app-compat.js"></script>
    <script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-auth-compat.js"></script>
    <script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore-compat.js"></script>

    <!-- 原有 CSS(完整保留) -->
    <style>
        /* 基础样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        :root {
            --primary-color: #4361ee;
            --secondary-color: #3a0ca3;
            --accent-color: #4cc9f0;
            --light-color: #f8f9fa;
            --dark-color: #212529;
            --success-color: #4CAF50;
            --warning-color: #ff9800;
            --danger-color: #f44336;
            --border-radius: 10px;
            --box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
            --transition: all 0.3s ease;
        }
        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            color: var(--dark-color);
            min-height: 100vh;
            padding: 20px;
        }
        .container {
            max-width: 1800px;
            margin: 0 auto;
        }
        /* 头部样式 */
        header {
            text-align: center;
            padding: 25px 0 30px;
            margin-bottom: 25px;
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            border-radius: var(--border-radius);
            box-shadow: var(--box-shadow);
            overflow: visible;
            position: relative;
            z-index: 1;
        }
        header::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(45deg, 
                rgba(255,255,255,0.1) 0%, 
                rgba(255,255,255,0.2) 25%, 
                transparent 50%, 
                rgba(0,0,0,0.1) 100%);
            pointer-events: none;
        }
        h1 {
            font-size: 2.5rem;
            color: white;
            margin-bottom: 10px;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
            position: relative;
            z-index: 2;
            letter-spacing: 0.5px;
        }
        .subtitle {
            font-size: 1.1rem;
            color: rgba(255, 255, 255, 0.9);
            max-width: 800px;
            margin: 0 auto;
            line-height: 1.6;
            position: relative;
            z-index: 2;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
        }
        /* 工具栏 */
        .toolbar {
            display: flex;
            align-items: center;
            gap: 15px;
            margin-bottom: 25px;
            padding: 15px 20px;
            background: white;
            border-radius: var(--border-radius);
            box-shadow: var(--box-shadow);
            flex-wrap: wrap;
        }
        .search-container {
            flex: 1;
            min-width: 200px;
            position: relative;
        }
        .search-input {
            width: 100%;
            padding: 10px 40px 10px 40px;
            border: 2px solid #e9ecef;
            border-radius: 6px;
            font-size: 0.95rem;
            transition: var(--transition);
            background-color: #f8f9fa;
        }
        .search-input:focus {
            outline: none;
            border-color: var(--primary-color);
            background-color: white;
            box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1);
        }
        .search-icon {
            position: absolute;
            left: 12px;
            top: 50%;
            transform: translateY(-50%);
            color: #6c757d;
            font-size: 1rem;
        }
        .clear-search {
            position: absolute;
            right: 12px;
            top: 50%;
            transform: translateY(-50%);
            background: none;
            border: none;
            color: #6c757d;
            cursor: pointer;
            font-size: 1rem;
            padding: 4px;
            border-radius: 50%;
            display: none;
            transition: var(--transition);
        }
        .clear-search:hover {
            background-color: rgba(0, 0, 0, 0.05);
            color: var(--danger-color);
        }
        .toolbar-buttons {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
        }
        .toolbar-btn {
            padding: 10px 16px;
            border: none;
            border-radius: 6px;
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            transition: var(--transition);
            font-size: 0.9rem;
            white-space: nowrap;
        }
        .toolbar-btn-primary {
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            color: white;
        }
        .toolbar-btn-primary:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(67, 97, 238, 0.3);
        }
        .toolbar-btn-secondary {
            background: #6c757d;
            color: white;
        }
        .toolbar-btn-secondary:hover {
            background: #5a6268;
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(108, 117, 125, 0.3);
        }
        .toolbar-btn-success {
            background: var(--success-color);
            color: white;
        }
        .toolbar-btn-success:hover {
            background: #388e3c;
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);
        }
        /* 主题选择器 */
        .theme-selector-container {
            position: absolute;
            top: 25px;
            right: 25px;
            display: flex;
            flex-direction: column;
            align-items: center;
            z-index: 1000;
        }
        .theme-selector-btn {
            width: 45px;
            height: 45px;
            border-radius: 50%;
            background: rgba(255, 255, 255, 0.2);
            backdrop-filter: blur(10px);
            color: white;
            border: 2px solid rgba(255, 255, 255, 0.3);
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.2rem;
            cursor: pointer;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
            transition: var(--transition);
            margin-bottom: 10px;
            z-index: 1001;
        }
        .theme-selector-btn:hover {
            transform: translateY(-3px) scale(1.1);
            background: rgba(255, 255, 255, 0.3);
            box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
        }
        .theme-selector {
            display: none;
            flex-direction: column;
            gap: 8px;
            padding: 15px;
            background: rgba(255, 255, 255, 0.98);
            backdrop-filter: blur(10px);
            border-radius: var(--border-radius);
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
            max-width: 200px;
            max-height: 400px;
            overflow-y: auto;
            margin-top: 5px;
            border: 1px solid rgba(255, 255, 255, 0.2);
            position: absolute;
            top: 100%;
            right: 0;
            z-index: 1002;
        }
        .theme-selector.active {
            display: flex;
        }
        .theme-color {
            width: 100%;
            height: 32px;
            border-radius: 6px;
            cursor: pointer;
            transition: var(--transition);
            display: flex;
            align-items: center;
            padding: 0 12px;
            color: white !important;
            font-weight: 600;
            font-size: 0.9rem;
            margin: 2px 0;
            min-width: 150px;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
        }
        .theme-color:hover {
            transform: translateX(3px);
            box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
        }
        .theme-color.active {
            border: 2px solid white;
            box-shadow: 0 3px 10px rgba(0, 0, 0, 0.15);
        }
        /* 日历导航 */
        .calendar-navigation {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 20px;
            margin-bottom: 30px;
            background: white;
            padding: 15px;
            border-radius: var(--border-radius);
            box-shadow: var(--box-shadow);
        }
        .nav-button {
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            color: white;
            border: none;
            width: 45px;
            height: 45px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            font-size: 1.2rem;
            transition: var(--transition);
            box-shadow: 0 4px 10px rgba(67, 97, 238, 0.3);
        }
        .nav-button:hover {
            transform: translateY(-3px);
            box-shadow: 0 6px 20px rgba(67, 97, 238, 0.4);
        }
        .current-period {
            font-size: 1.3rem;
            font-weight: 700;
            color: var(--primary-color);
            min-width: 280px;
            text-align: center;
            padding: 8px 20px;
            background: rgba(67, 97, 238, 0.05);
            border-radius: 8px;
            border: 2px solid rgba(67, 97, 238, 0.1);
        }
        /* 月份数量选择器 */
        .month-count-selector {
            display: flex;
            align-items: center;
            gap: 8px;
            background: rgba(67, 97, 238, 0.08);
            padding: 6px 12px;
            border-radius: 6px;
            border: 1px solid rgba(67, 97, 238, 0.15);
        }
        .month-count-selector label {
            font-size: 0.9rem;
            color: var(--primary-color);
            font-weight: 600;
            white-space: nowrap;
        }
        .month-count-selector select {
            background: white;
            border: 1px solid rgba(67, 97, 238, 0.3);
            border-radius: 4px;
            padding: 4px 8px;
            font-size: 0.9rem;
            color: var(--dark-color);
            cursor: pointer;
            transition: var(--transition);
        }
        /* 多个月份日历容器 */
        .calendar-container {
            position: relative;
            display: flex;
            align-items: center;
            width: 100%;
        }
        .multi-month-calendar {
            display: grid;
            gap: 25px;
            margin-bottom: 25px;
            width: 100%;
            min-height: 600px;
            grid-template-columns: repeat(auto-fill, minmax(calc(50% - 12.5px), 1fr));
        }
        .multi-month-calendar.grid-1 {
            grid-template-columns: 1fr;
        }
        .multi-month-calendar.grid-2 {
            grid-template-columns: repeat(2, 1fr);
        }
        .calendar-nav-btn {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            color: white;
            border: none;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            font-size: 1.1rem;
            transition: var(--transition);
            box-shadow: 0 4px 10px rgba(67, 97, 238, 0.3);
            z-index: 5;
            opacity: 0.8;
        }
        .calendar-nav-btn:hover {
            opacity: 1;
            transform: translateY(-50%) scale(1.1);
        }
        .calendar-nav-btn.prev-month {
            left: -15px;
        }
        .calendar-nav-btn.next-month {
            right: -15px;
        }
        /* 单个月日历 */
       /* 单个月日历 */
.month-calendar {
    background-color: white;
    border-radius: var(--border-radius);
    padding: 20px;
    box-shadow: var(--box-shadow);
    position: relative;
    min-height: 650px;
    width: 100%;
    overflow: hidden;
    resize: horizontal;
    overflow-x: auto;
    min-width: 400px;
    max-width: 100%;
    margin: 0 auto; /* 居中 */
}

/* &#128313; 1个月模式:限制宽度 + 禁用缩放 + 适当缩小单元格 */
.multi-month-calendar.grid-1 .month-calendar {
    max-width: 900px;      /* 限制最大宽度 */
    resize: none;          /* 禁用拖拽缩放 */
    margin: 0 auto;        /* 水平居中 */
    min-height: 650px;
    padding: 18px;
}

/* 单元格高度调整(1个月时略小) */
.multi-month-calendar.grid-1 .calendar-day {
    min-height: 130px;     /* 原为160px,现在更紧凑 */
}

/* 手机端优化 */
[url=home.php?mod=space&uid=945662]@media[/url] (max-width: 768px) {
    .multi-month-calendar.grid-1 .month-calendar {
        max-width: 100% !important;
        padding: 12px;
        min-height: 550px;
    }
    .multi-month-calendar.grid-1 .calendar-day {
        min-height: 90px;
        padding: 5px;
    }
    .multi-month-calendar.grid-1 .day-memo-item {
        font-size: 0.75rem;
        padding: 2px 4px;
    }
}
        /* 任务统计 */
        .month-stats {
            display: flex;
            align-items: center;
            gap: 12px;
            background: rgba(67, 97, 238, 0.05);
            padding: 8px 12px;
            border-radius: 6px;
            border: 1px solid rgba(67, 97, 238, 0.1);
            font-size: 0.85rem;
            color: #495057;
        }
        .stat-item {
            display: flex;
            align-items: center;
            gap: 4px;
            white-space: nowrap;
        }
        .complete-all-btn {
            background: linear-gradient(135deg, var(--success-color), #2e7d32);
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 0.9rem;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 8px;
            transition: var(--transition);
            box-shadow: 0 3px 8px rgba(76, 175, 80, 0.3);
            white-space: nowrap;
        }
        .complete-all-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(76, 175, 80, 0.4);
        }
        .month-progress {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .progress-circle {
            position: relative;
            width: 40px;
            height: 40px;
        }
        .progress-circle svg {
            width: 100%;
            height: 100%;
            transform: rotate(-90deg);
        }
        .progress-circle-bg {
            fill: none;
            stroke: #e9ecef;
            stroke-width: 4;
        }
        .progress-circle-fill {
            fill: none;
            stroke: var(--primary-color);
            stroke-width: 4;
            stroke-linecap: round;
            transition: stroke-dashoffset 0.8s ease;
        }
        .progress-percent {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 0.8rem;
            font-weight: 600;
            color: var(--primary-color);
        }
        .weekdays {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            text-align: center;
            font-weight: 600;
            color: #495057;
            margin-bottom: 12px;
            padding-bottom: 10px;
            border-bottom: 1px solid #e9ecef;
            font-size: 0.9rem;
        }
        .calendar-grid {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 5px;
            width: 100%;
        }
        /* 日历单元格 */
        .calendar-day {
            aspect-ratio: 1;
            background-color: #f8f9fa;
            border-radius: 8px;
            padding: 8px;
            cursor: pointer;
            transition: var(--transition);
            position: relative;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            min-height: 140px;
            width: 100%;
            box-sizing: border-box;
            border: 1px dashed rgba(0, 0, 0, 0.15);
        }
        .multi-month-calendar.grid-1 .calendar-day {
            min-height: 160px;
        }
        .calendar-day:hover {
            background-color: #e9ecef;
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            z-index: 2;
            border: 1px solid rgba(67, 97, 238, 0.3);
        }
        .calendar-day.today {
            background-color: rgba(67, 97, 238, 0.15);
            border: 2px solid var(--primary-color);
        }
        .calendar-day.other-month {
            opacity: 0.5;
            background-color: #f0f2f5;
            border: 1px dashed rgba(0, 0, 0, 0.1);
        }
        .day-number {
            font-size: 1rem;
            font-weight: 700;
            color: var(--dark-color);
            margin-bottom: 6px;
            align-self: flex-start;
            position: relative;
            z-index: 2;
        }
        .day-memos {
            flex-grow: 1;
            overflow-y: auto;
            font-size: 0.75rem;
            line-height: 1.3;
            max-height: calc(100% - 25px);
            min-height: 90px;
            width: 100%;
        }
        .day-memo-item {
            padding: 4px 6px;
            margin-bottom: 3px;
            border-radius: 4px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            transition: var(--transition);
            background-color: rgba(255, 255, 255, 0.7);
            border-left: 3px solid;
            font-size: 0.75rem;
            height: 18px;
            width: 100%;
            box-sizing: border-box;
        }
        .multi-month-calendar.grid-1 .day-memo-item {
            white-space: normal;
            height: auto;
            min-height: 18px;
            max-height: 54px;
            overflow: hidden;
            text-overflow: ellipsis;
            display: -webkit-box;
            -webkit-line-clamp: 3;
            -webkit-box-orient: vertical;
            line-height: 1.3;
            padding: 3px 6px;
            font-size: 0.8rem;
        }
        .day-memo-item.completed {
            opacity: 0.6;
            text-decoration: line-through;
        }
        .memo-count {
            position: absolute;
            top: 8px;
            right: 8px;
            background-color: var(--danger-color);
            color: white;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 0.65rem;
            font-weight: bold;
            z-index: 3;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
        }
        /* 浮动按钮 */
        .floating-actions {
            position: fixed;
            right: 25px;
            bottom: 25px;
            display: flex;
            flex-direction: column;
            gap: 12px;
            z-index: 999;
        }
        .floating-btn {
            width: 55px;
            height: 55px;
            border-radius: 50%;
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            color: white;
            border: none;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.3rem;
            cursor: pointer;
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
            transition: var(--transition);
            position: relative;
        }
        .floating-btn:hover {
            transform: translateY(-5px) scale(1.1);
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
        }
        .floating-btn .badge {
            position: absolute;
            top: -4px;
            right: -4px;
            background-color: var(--danger-color);
            color: white;
            font-size: 0.65rem;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
        }
        /* 提醒弹窗 */
        .reminder-modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            z-index: 2000;
            align-items: center;
            justify-content: center;
            padding: 15px;
        }
        .reminder-modal.active {
            display: flex;
        }
        .reminder-content {
            background-color: white;
            width: 100%;
            max-width: 500px;
            border-radius: var(--border-radius);
            overflow: hidden;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
            animation: slideIn 0.3s ease;
        }
        @keyframes slideIn {
            from {
                transform: translateY(-50px);
                opacity: 0;
            }
            to {
                transform: translateY(0);
                opacity: 1;
            }
        }
        .reminder-header {
            padding: 20px;
            background: linear-gradient(90deg, var(--danger-color), #d32f2f);
            color: white;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .reminder-title {
            font-size: 1.3rem;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .close-reminder {
            background: none;
            border: none;
            color: white;
            font-size: 1.6rem;
            cursor: pointer;
            transition: var(--transition);
        }
        .close-reminder:hover {
            transform: rotate(90deg);
        }
        .reminder-body {
            padding: 20px;
            max-height: 400px;
            overflow-y: auto;
        }
        .reminder-list {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .reminder-item {
            padding: 15px;
            background-color: #fff8e1;
            border-radius: 8px;
            border-left: 4px solid var(--warning-color);
            transition: var(--transition);
        }
        .reminder-item:hover {
            background-color: #fff3cd;
            cursor: pointer;
        }
        .reminder-item-title {
            font-weight: 600;
            font-size: 1rem;
            margin-bottom: 5px;
            color: var(--dark-color);
        }
        .reminder-item-details {
            display: flex;
            justify-content: space-between;
            align-items: center;
            font-size: 0.9rem;
            color: #6c757d;
        }
        .reminder-actions {
            padding: 15px 20px;
            background-color: #f8f9fa;
            border-top: 2px solid #e9ecef;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        /* 模态窗口 */
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            z-index: 1000;
            align-items: center;
            justify-content: center;
            padding: 15px;
        }
        .modal.active {
            display: flex;
        }
        .modal-content {
            background-color: white;
            width: 100%;
            max-width: 800px;
            max-height: 85vh;
            border-radius: var(--border-radius);
            overflow: hidden;
            display: flex;
            flex-direction: column;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
        }
        .modal-header {
            padding: 20px;
            background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
            color: white;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .modal-title {
            font-size: 1.3rem;
            font-weight: 600;
        }
        .close-modal {
            background: none;
            border: none;
            color: white;
            font-size: 1.6rem;
            cursor: pointer;
            transition: var(--transition);
        }
        .close-modal:hover {
            transform: rotate(90deg);
        }
        .modal-body {
            padding: 20px;
            overflow-y: auto;
            flex-grow: 1;
        }
        /* 选项卡 */
        .tabs {
            display: flex;
            border-bottom: 2px solid #e9ecef;
            margin-bottom: 20px;
            flex-wrap: wrap;
        }
        .tab {
            padding: 12px 18px;
            background: none;
            border: none;
            font-size: 1rem;
            font-weight: 600;
            color: #6c757d;
            cursor: pointer;
            transition: var(--transition);
            position: relative;
        }
        .tab.active {
            color: var(--primary-color);
        }
        .tab.active::after {
            content: '';
            position: absolute;
            bottom: -2px;
            left: 0;
            width: 100%;
            height: 2px;
            background-color: var(--primary-color);
        }
        .tab-content {
            display: none;
        }
        .tab-content.active {
            display: block;
        }
        /* 任务列表 */
        .task-list {
            max-height: 300px;
            overflow-y: auto;
        }
        .task-item {
            padding: 12px;
            background-color: #f8f9fa;
            border-radius: 8px;
            margin-bottom: 12px;
            border-left: 4px solid var(--primary-color);
            transition: var(--transition);
        }
        .task-item:hover {
            background-color: #e9ecef;
        }
        .task-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 8px;
        }
        .task-title {
            font-weight: 600;
            font-size: 1rem;
        }
        .task-color {
            width: 18px;
            height: 18px;
            border-radius: 50%;
        }
        .task-due {
            font-size: 0.85rem;
            color: #6c757d;
            margin-bottom: 8px;
            display: flex;
            align-items: center;
            gap: 5px;
        }
        .task-actions {
            display: flex;
            gap: 8px;
            margin-top: 8px;
        }
        .task-btn {
            padding: 4px 8px;
            border-radius: 4px;
            border: none;
            cursor: pointer;
            font-size: 0.8rem;
            transition: var(--transition);
        }
        .task-btn-complete {
            background-color: rgba(76, 175, 80, 0.1);
            color: var(--success-color);
        }
        .task-btn-complete:hover {
            background-color: var(--success-color);
            color: white;
        }
        .task-btn-edit {
            background-color: rgba(67, 97, 238, 0.1);
            color: var(--primary-color);
        }
        .task-btn-edit:hover {
            background-color: var(--primary-color);
            color: white;
        }
        .task-btn-delete {
            background-color: rgba(244, 67, 54, 0.1);
            color: var(--danger-color);
        }
        .task-btn-delete:hover {
            background-color: var(--danger-color);
            color: white;
        }
        /* 表单 */
        .form-group {
            margin-bottom: 18px;
        }
        .form-row {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
        }
        label {
            display: block;
            margin-bottom: 6px;
            font-weight: 600;
            color: #495057;
            font-size: 0.95rem;
        }
        .form-control {
            width: 100%;
            padding: 10px;
            border: 2px solid #e9ecef;
            border-radius: 6px;
            font-size: 0.95rem;
            transition: var(--transition);
        }
        .form-control:focus {
            outline: none;
            border-color: var(--primary-color);
        }
        textarea.form-control {
            min-height: 100px;
            resize: vertical;
            font-family: 'Segoe UI', sans-serif;
        }
        .color-options {
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
        }
        .color-option {
            width: 32px;
            height: 32px;
            border-radius: 50%;
            cursor: pointer;
            border: 2px solid transparent;
            transition: var(--transition);
        }
        .color-option.selected {
            border-color: var(--dark-color);
            transform: scale(1.1);
        }
        .markdown-preview {
            padding: 12px;
            border-radius: 6px;
            background-color: #f8f9fa;
            border: 2px solid #e9ecef;
            min-height: 120px;
            max-height: 200px;
            overflow-y: auto;
            font-size: 0.9rem;
        }
        .modal-footer {
            padding: 15px 20px;
            background-color: #f8f9fa;
            border-top: 2px solid #e9ecef;
            display: flex;
            justify-content: flex-end;
            gap: 12px;
        }
        /* 按钮 */
        .btn {
            padding: 10px 16px;
            border: none;
            border-radius: 6px;
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            transition: var(--transition);
            font-size: 0.9rem;
        }
        .btn-primary {
            background-color: var(--primary-color);
            color: white;
        }
        .btn-primary:hover {
            background-color: var(--secondary-color);
            transform: translateY(-2px);
        }
        .btn-secondary {
            background-color: #6c757d;
            color: white;
        }
        .btn-secondary:hover {
            background-color: #5a6268;
            transform: translateY(-2px);
        }
        .btn-danger {
            background-color: var(--danger-color);
            color: white;
        }
        .btn-danger:hover {
            background-color: #d32f2f;
            transform: translateY(-2px);
        }
        .btn-success {
            background-color: var(--success-color);
            color: white;
        }
        .btn-success:hover {
            background-color: #388e3c;
            transform: translateY(-2px);
        }
        .btn-full {
            width: 100%;
        }
        /* 空状态 */
        .empty-state {
            text-align: center;
            padding: 20px 15px;
            color: #6c757d;
        }
        .empty-state i {
            font-size: 2rem;
            margin-bottom: 10px;
            color: #dee2e6;
        }
        /* 倒计时 */
        .countdown {
            display: inline-block;
            padding: 2px 6px;
            border-radius: 10px;
            font-size: 0.7rem;
            font-weight: 600;
            margin-left: 5px;
        }
        .countdown.danger {
            background-color: rgba(244, 67, 54, 0.2);
            color: var(--danger-color);
        }
        .countdown.warning {
            background-color: rgba(255, 152, 0, 0.2);
            color: var(--warning-color);
        }
        .countdown.success {
            background-color: rgba(76, 175, 80, 0.2);
            color: var(--success-color);
        }
        /* 滚动条 */
        ::-webkit-scrollbar {
            width: 5px;
        }
        ::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 3px;
        }
        ::-webkit-scrollbar-thumb {
            background: #c1c1c1;
            border-radius: 3px;
        }
        ::-webkit-scrollbar-thumb:hover {
            background: #a8a8a8;
        }
        /* 每日详情快速添加 */
        .quick-add-container {
            margin-bottom: 20px;
            padding: 15px;
            background-color: #f8f9fa;
            border-radius: 8px;
            border: 2px dashed #dee2e6;
        }
        .quick-add-header {
            font-size: 1rem;
            margin-bottom: 12px;
            color: #495057;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .quick-add-form {
            display: grid;
            grid-template-columns: 1fr auto;
            gap: 8px;
        }
        .quick-add-input {
            padding: 10px 12px;
            border: 2px solid #e9ecef;
            border-radius: 6px;
            font-size: 0.95rem;
            transition: var(--transition);
        }
        .quick-add-input:focus {
            outline: none;
            border-color: var(--primary-color);
        }
        .quick-add-button {
            padding: 0 20px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 6px;
            font-weight: 600;
            cursor: pointer;
            transition: var(--transition);
        }
        .quick-add-button:hover {
            background-color: var(--secondary-color);
        }
        /* 备忘录颜色点 */
        .memo-color-dot {
            display: inline-block;
            width: 8px;
            height: 8px;
            border-radius: 50%;
            margin-right: 4px;
        }
        /* 导出按钮容器 */
        .export-buttons-container {
            display: flex;
            gap: 12px;
            align-items: center;
            flex-wrap: wrap;
            margin-top: 20px;
            margin-bottom: 20px;
        }
        /* 响应式设计 */
        @media (max-width: 1200px) {
            .multi-month-calendar {
                grid-template-columns: repeat(2, 1fr) !important;
            }
            .calendar-nav-btn {
                display: none;
            }
        }
        @media (max-width: 768px) {
            h1 {
                font-size: 2rem;
                padding: 0 15px;
            }
            .subtitle {
                font-size: 1rem;
                padding: 0 15px;
            }
            .toolbar {
                flex-direction: column;
                align-items: stretch;
            }
            .search-container {
                width: 100%;
            }
            .toolbar-buttons {
                width: 100%;
                justify-content: stretch;
            }
            .toolbar-btn {
                flex: 1;
                min-width: auto;
            }
            .calendar-navigation {
                flex-direction: column;
                gap: 15px;
                padding: 15px 10px;
            }
            .current-period {
                min-width: auto;
                width: 100%;
                font-size: 1.1rem;
            }
            .month-count-selector {
                width: 100%;
                justify-content: center;
            }
            .nav-button {
                width: 40px;
                height: 40px;
            }
            .multi-month-calendar {
                grid-template-columns: 1fr !important;
                gap: 20px;
            }
            .calendar-nav-btn {
                display: none;
            }
            .month-calendar {
                padding: 15px;
                min-height: 600px;
                resize: none;
                min-width: 100%;
            }
            .form-row {
                grid-template-columns: 1fr;
            }
            .modal-content {
                max-height: 90vh;
            }
            .floating-actions {
                right: 15px;
                bottom: 15px;
            }
            .floating-btn {
                width: 48px;
                height: 48px;
                font-size: 1.1rem;
            }
            .tabs {
                justify-content: center;
            }
            .tab {
                padding: 10px 12px;
                font-size: 0.9rem;
            }
            .theme-selector-container {
                top: 15px;
                right: 15px;
            }
            .theme-selector-btn {
                width: 40px;
                height: 40px;
                font-size: 1rem;
            }
            .calendar-day {
                min-height: 100px;
                padding: 6px;
            }
        }
        @media (max-width: 480px) {
            h1 {
                font-size: 1.5rem;
            }
            .month-title {
                font-size: 1.2rem;
            }
            .month-stats {
                flex-direction: column;
                align-items: flex-start;
                gap: 6px;
            }
            .complete-all-btn {
                padding: 6px 10px;
                font-size: 0.8rem;
            }
            .toolbar-btn {
                padding: 8px 12px;
                font-size: 0.8rem;
            }
            .floating-btn {
                width: 42px;
                height: 42px;
                font-size: 1rem;
            }
        }
        /* 提示信息 */
        .toast {
            position: fixed;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: var(--primary-color);
            color: white;
            padding: 12px 24px;
            border-radius: var(--border-radius);
            box-shadow: var(--box-shadow);
            z-index: 10000;
            display: none;
            align-items: center;
            gap: 10px;
        }
        .toast.show {
            display: flex;
            animation: fadeInUp 0.3s ease;
        }
        @keyframes fadeInUp {
            from {
                opacity: 0;
                transform: translateX(-50%) translateY(20px);
            }
            to {
                opacity: 1;
                transform: translateX(-50%) translateY(0);
            }
        }
        /* 确认对话框 */
        .confirmation-dialog {
            background: white;
            border-radius: var(--border-radius);
            padding: 20px;
            max-width: 400px;
            width: 90%;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
        }
        .confirmation-title {
            font-size: 1.2rem;
            margin-bottom: 10px;
            color: var(--dark-color);
        }
        .confirmation-message {
            margin-bottom: 20px;
            color: #666;
        }
        .confirmation-buttons {
            display: flex;
            gap: 10px;
            justify-content: flex-end;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>&#128197; 智能网页工作日历备忘录</h1>
            <p class="subtitle">同时查看多个月份日历,每天显示备忘录标题列表,支持快速操作和智能任务管理</p>
            <div class="theme-selector-container">
                <button class="theme-selector-btn" id="themeSelectorBtn" title="切换配色方案">
                    <i class="fas fa-palette"></i>
                </button>
                <div class="theme-selector" id="themeSelector">
                    <!-- 主题将通过JS生成 -->
                </div>
            </div>
        </header>
        <!-- 工具栏 -->
        <div class="toolbar">
            <div class="search-container">
                <i class="fas fa-search search-icon"></i>
                <input type="text" class="search-input" id="searchInput" placeholder="搜索备忘录...">
                <button class="clear-search" id="clearSearch" title="清除搜索">
                    <i class="fas fa-times"></i>
                </button>
            </div>
            <!-- 月份数量选择器 -->
            <div class="month-count-selector">
                <label for="monthCountSelect">显示月份:</label>
                <select id="monthCountSelect">
                    <option value="1">1个月</option>
                    <option value="2" selected>2个月</option>
                    <option value="3">3个月</option>
                    <option value="4">4个月</option>
                    <option value="5">5个月</option>
                    <option value="6">6个月</option>
                    <option value="7">7个月</option>
                    <option value="8">8个月</option>
                    <option value="9">9个月</option>
                    <option value="10">10个月</option>
                    <option value="11">11个月</option>
                    <option value="12">12个月</option>
                </select>
            </div>
            <div class="toolbar-buttons">
                <button class="toolbar-btn toolbar-btn-primary" id="toolbarPublish">
                    <i class="fas fa-bullhorn"></i> 任务发布
                </button>
                <button class="toolbar-btn toolbar-btn-success" id="toolbarExport">
                    <i class="fas fa-file-export"></i> 数据导出
                </button>
                <button class="toolbar-btn toolbar-btn-secondary" id="toolbarImport">
                    <i class="fas fa-file-import"></i> 数据导入
                </button>
            </div>
        </div>
        <!-- 日历导航区域 -->
        <div class="calendar-navigation">
            <button class="nav-button" id="prevMonth">
                <i class="fas fa-chevron-left"></i>
            </button>
            <div class="current-period" id="currentPeriod"></div>
            <button class="nav-button" id="nextMonth">
                <i class="fas fa-chevron-right"></i>
            </button>
        </div>
        <!-- 多个月份日历容器 -->
        <div class="calendar-container">
            <button class="calendar-nav-btn prev-month" id="calendarPrevMonth" title="前一个月">
                <i class="fas fa-chevron-left"></i>
            </button>
            <div class="multi-month-calendar grid-2" id="multiMonthCalendar">
                <!-- 日历将通过JS动态生成 -->
            </div>
            <button class="calendar-nav-btn next-month" id="calendarNextMonth" title="后一个月">
                <i class="fas fa-chevron-right"></i>
            </button>
        </div>
    </div>
    <!-- 右侧浮动按钮 -->
    <div class="floating-actions">
        <button class="floating-btn" id="floatingReminder" title="到期提醒">
            <i class="fas fa-bell"></i>
            <span class="badge" id="reminderBadge" style="display: none;"></span>
        </button>
        <button class="floating-btn" id="floatingFunctions" title="功能面板">
            <i class="fas fa-cog"></i>
            <span class="badge" id="pendingBadge"></span>
        </button>
    </div>
    <!-- 到期提醒弹窗 -->
    <div class="reminder-modal" id="reminderModal">
        <div class="reminder-content">
            <div class="reminder-header">
                <div class="reminder-title">
                    <i class="fas fa-bell"></i> 到期提醒
                </div>
                <button class="close-reminder" id="closeReminderModal">&times;</button>
            </div>
            <div class="reminder-body">
                <div id="reminderList">
                    <div class="empty-state">
                        <i class="fas fa-bell-slash"></i>
                        <p>暂无到期提醒</p>
                    </div>
                </div>
            </div>
            <div class="reminder-actions">
                <div class="reminder-settings">
                    <input type="checkbox" id="autoCloseReminder">
                    <label for="autoCloseReminder">10秒后自动关闭</label>
                </div>
                <div class="export-buttons-container">
                    <button class="btn btn-primary" id="markAllAsRead">
                        <i class="fas fa-check-double"></i> 全部标记已读
                    </button>
                    <button class="btn btn-secondary" id="viewRecentTasks">
                        <i class="fas fa-tasks"></i> 查看最近任务
                    </button>
                </div>
            </div>
        </div>
    </div>
    <!-- 备忘录编辑模态窗口 -->
    <div class="modal" id="memoModal">
        <div class="modal-content">
            <div class="modal-header">
                <div class="modal-title">备忘录编辑</div>
                <button class="close-modal" id="closeMemoModal">&times;</button>
            </div>
            <div class="modal-body">
                <form id="memoForm">
                    <div class="form-group">
                        <label for="memoTitle">标题 *</label>
                        <input type="text" class="form-control" id="memoTitle" required>
                    </div>
                    <div class="form-row">
                        <div class="form-group">
                            <label for="memoDate">日期 *</label>
                            <input type="date" class="form-control" id="memoDate" required>
                        </div>
                        <div class="form-group">
                            <label for="memoDueTime">截止时间</label>
                            <input type="datetime-local" class="form-control" id="memoDueTime">
                        </div>
                    </div>
                    <div class="form-group">
                        <label>备忘录颜色</label>
                        <div class="color-options" id="colorOptions">
                            <!-- 颜色选项将通过JS生成 -->
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="memoContent">内容 (支持Markdown语法)</label>
                        <textarea class="form-control" id="memoContent" rows="5" placeholder="输入备忘录内容,支持Markdown语法..."></textarea>
                    </div>
                    <div class="form-group">
                        <label>预览</label>
                        <div class="markdown-preview" id="markdownPreview">
                            预览将在这里显示...
                        </div>
                    </div>
                    <div class="form-group">
                        <label>
                            <input type="checkbox" id="memoCompleted"> 标记为已完成
                        </label>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button class="btn btn-secondary" id="cancelMemo">取消</button>
                <button class="btn btn-danger" id="deleteMemo">删除</button>
                <button class="btn btn-primary" id="saveMemo">保存备忘录</button>
            </div>
        </div>
    </div>
    <!-- 功能面板模态窗口 -->
    <div class="modal" id="functionsModal">
        <div class="modal-content">
            <div class="modal-header">
                <div class="modal-title">功能面板</div>
                <button class="close-modal" id="closeFunctionsModal">&times;</button>
            </div>
            <div class="modal-body">
                <div class="tabs">
                    <button class="tab active" data-tab="taskPublish">任务发布</button>
                    <button class="tab" data-tab="recentTasks">最近任务</button>
                    <button class="tab" data-tab="dataManagement">数据管理</button>
                    <button class="tab" data-tab="exportSettings">定时导出</button>
                    <button class="tab" data-tab="reminderSettings">提醒设置</button>
                    <!-- &#128313; 新增 -->
                    <button class="tab" data-tab="accountSync">账号同步</button>
                </div>
                <!-- 任务发布选项卡 -->
                <div class="tab-content active" id="taskPublishTab">
                    <h3 style="margin-bottom: 15px;"><i class="fas fa-bullhorn"></i> 发布新任务</h3>
                    <div class="form-group">
                        <label for="taskTitle">任务标题 *</label>
                        <input type="text" class="form-control" id="taskTitle" placeholder="请输入任务标题" required>
                    </div>
                    <div class="form-group">
                        <label for="taskDescription">任务描述(支持Markdown)</label>
                        <textarea class="form-control" id="taskDescription" placeholder="请输入任务描述..." rows="4"></textarea>
                    </div>
                    <div class="form-row">
                        <div class="form-group">
                            <label for="taskStartDate">开始日期 *</label>
                            <input type="date" class="form-control" id="taskStartDate" required>
                        </div>
                        <div class="form-group">
                            <label for="taskEndDate">结束日期 *</label>
                            <input type="date" class="form-control" id="taskEndDate" required>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="taskColor">任务颜色</label>
                        <div class="color-options" id="taskColorOptions">
                            <!-- 颜色选项将通过JS生成 -->
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="taskDueTime">每日截止时间</label>
                        <input type="time" class="form-control" id="taskDueTime" value="18:00">
                    </div>
                    <button class="btn btn-success btn-full" id="publishTask">
                        <i class="fas fa-paper-plane"></i> 发布并分配到每天
                    </button>
                    <div class="task-publish-info">
                        <h4><i class="fas fa-info-circle"></i> 功能说明</h4>
                        <p style="margin-top: 8px; line-height: 1.5;">
                            此功能将创建一个新任务,并自动分配到从开始日期到结束日期之间的每一天。
                            每天都会创建一个独立的备忘录,便于跟踪每日进度。
                        </p>
                    </div>
                </div>
                <!-- 最近任务选项卡 -->
                <div class="tab-content" id="recentTasksTab">
                    <h3 style="margin-bottom: 15px;"><i class="fas fa-tasks"></i> 最近任务</h3>
                    <div class="task-list" id="recentTasksList">
                        <div class="empty-state">
                            <i class="fas fa-clipboard-list"></i>
                            <p>暂无任务,点击日历上的日期添加新任务</p>
                        </div>
                    </div>
                </div>
                <!-- 数据管理选项卡 -->
                <div class="tab-content" id="dataManagementTab">
                    <h3 style="margin-bottom: 15px;"><i class="fas fa-database"></i> 数据管理</h3>
                    <p style="margin-bottom: 15px; color: #6c757d; line-height: 1.5;">
                        所有数据存储在您的浏览器本地,建议定期导出备份以防数据丢失。
                    </p>
                    <div class="data-management-buttons">
                        <button class="btn btn-primary" id="exportData">
                            <i class="fas fa-file-export"></i> 导出数据
                        </button>
                        <button class="btn btn-secondary" id="importData">
                            <i class="fas fa-file-import"></i> 导入数据
                        </button>
                        <button class="btn btn-danger" id="clearData">
                            <i class="fas fa-trash-alt"></i> 清空所有数据
                        </button>
                        <button class="btn btn-secondary" id="viewStats">
                            <i class="fas fa-chart-pie"></i> 查看统计
                        </button>
                    </div>
                    <div style="margin-top: 20px; padding: 15px; background-color: #f8f9fa; border-radius: 8px;">
                        <h4><i class="fas fa-info-circle"></i> 统计信息</h4>
                        <div style="margin-top: 10px;">
                            <p>总备忘录数: <span id="totalMemosStat">0</span></p>
                            <p>已完成: <span id="completedMemosStat">0</span></p>
                            <p>未完成: <span id="pendingMemosStat">0</span></p>
                            <p>最早备忘录: <span id="oldestMemoStat">无</span></p>
                            <p>最近更新: <span id="latestUpdateStat">无</span></p>
                        </div>
                    </div>
                </div>
                <!-- 定时导出选项卡 -->
                <div class="tab-content" id="exportSettingsTab">
                    <h3 style="margin-bottom: 15px;"><i class="fas fa-clock"></i> 定时导出设置</h3>
                    <div class="form-group">
                        <label for="exportInterval">导出频率</label>
                        <select class="form-control" id="exportInterval">
                            <option value="never">从不</option>
                            <option value="daily">每天</option>
                            <option value="weekly">每周</option>
                            <option value="monthly">每月</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label for="exportTime">导出时间</label>
                        <input type="time" class="form-control" id="exportTime" value="23:00">
                    </div>
                    <div class="form-group">
                        <label for="lastExport">上次导出时间</label>
                        <input type="text" class="form-control" id="lastExport" value="从未导出" readonly>
                    </div>
                    <div class="export-buttons-container">
                        <button class="btn btn-primary" id="saveExportSettings">
                            <i class="fas fa-save"></i> 保存设置
                        </button>
                        <button class="btn btn-secondary" id="manualExport">
                            <i class="fas fa-file-export"></i> 立即导出
                        </button>
                    </div>
                    <div class="export-info">
                        <h4><i class="fas fa-info-circle"></i> 注意事项</h4>
                        <ul style="margin-top: 8px; padding-left: 18px; line-height: 1.5;">
                            <li>定时导出功能需要保持浏览器页面打开才能正常工作</li>
                            <li>导出的数据包含所有备忘录和设置</li>
                            <li>建议设置自动导出以防数据丢失</li>
                        </ul>
                    </div>
                </div>
                <!-- 提醒设置选项卡 -->
                <div class="tab-content" id="reminderSettingsTab">
                    <h3 style="margin-bottom: 15px;"><i class="fas fa-bell"></i> 提醒设置</h3>
                    <div class="form-group">
                        <label for="reminderCheckInterval">检查频率</label>
                        <select class="form-control" id="reminderCheckInterval">
                            <option value="1">每1分钟</option>
                            <option value="5" selected>每5分钟</option>
                            <option value="10">每10分钟</option>
                            <option value="15">每15分钟</option>
                            <option value="30">每30分钟</option>
                            <option value="60">每小时</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label for="reminderAdvanceTime">提前提醒时间</label>
                        <select class="form-control" id="reminderAdvanceTime">
                            <option value="0">到期时提醒</option>
                            <option value="15">提前15分钟</option>
                            <option value="30" selected>提前30分钟</option>
                            <option value="60">提前1小时</option>
                            <option value="1440">提前1天</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label>
                            <input type="checkbox" id="enableSoundReminder" checked> 启用声音提醒
                        </label>
                    </div>
                    <div class="form-group">
                        <label>
                            <input type="checkbox" id="enableDesktopNotification"> 启用桌面通知(需要浏览器授权)
                        </label>
                    </div>
                    <div class="form-group">
                        <label for="reminderTest">测试提醒</label>
                        <button class="btn btn-warning btn-full" id="testReminder">
                            <i class="fas fa-bell"></i> 发送测试提醒
                        </button>
                    </div>
                    <button class="btn btn-primary" id="saveReminderSettings">
                        <i class="fas fa-save"></i> 保存提醒设置
                    </button>
                    <div class="export-info" style="margin-top: 20px;">
                        <h4><i class="fas fa-info-circle"></i> 提醒说明</h4>
                        <ul style="margin-top: 8px; padding-left: 18px; line-height: 1.5;">
                            <li>系统会定期检查到期备忘录并显示提醒</li>
                            <li>提醒弹窗会在页面右上角显示</li>
                            <li>已完成的备忘录不会触发提醒</li>
                        </ul>
                    </div>
                </div>
                <!-- &#128313; 账号同步面板 -->
                <div class="tab-content" id="accountSyncTab">
                    <h3 style="margin-bottom: 15px;"><i class="fas fa-cloud"></i> 云端同步</h3>
                    <div id="authStatus" style="margin-bottom: 15px; padding: 10px; background: #e9ecef; border-radius: 6px;">
                        未登录
                    </div>
                    <div id="authForm" style="margin-bottom: 15px;">
                        <div class="form-group">
                            <label for="syncEmail">邮箱</label>
                            <input type="email" class="form-control" id="syncEmail" placeholder="your@email.com">
                        </div>
                        <div class="form-group">
                            <label for="syncPassword">密码</label>
                            <input type="password" class="form-control" id="syncPassword" placeholder="至少6位">
                        </div>
                        <button class="btn btn-primary" id="loginBtn" style="margin-right: 10px;">
                            <i class="fas fa-sign-in-alt"></i> 登录
                        </button>
                        <button class="btn btn-secondary" id="registerBtn">
                            <i class="fas fa-user-plus"></i> 注册
                        </button>
                    </div>
                    <div class="export-buttons-container">
                        <button class="btn btn-success" id="syncToCloud" disabled>
                            <i class="fas fa-upload"></i> 上传到云端
                        </button>
                        <button class="btn btn-info" id="syncFromCloud" disabled>
                            <i class="fas fa-download"></i> 从云端下载
                        </button>
                    </div>
                    <div style="margin-top: 15px; padding: 12px; background: #fff8e1; border-radius: 6px; font-size: 0.9rem;">
                        <i class="fas fa-exclamation-circle"></i> 
                        登录后即可在手机、电脑之间同步所有备忘录数据。
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button class="btn btn-secondary" id="closeFunctionsModalBtn">关闭</button>
            </div>
        </div>
    </div>
    <!-- 每日备忘录详情模态窗口 -->
    <div class="modal" id="dailyDetailModal">
        <div class="modal-content">
            <div class="modal-header">
                <div class="modal-title">
                    <i class="fas fa-list"></i> 每日备忘录详情
                    <span style="font-size: 1.1rem; color: white; opacity: 0.9; margin-left: 12px; font-weight: normal;" id="dailyDetailDate"></span>
                </div>
                <button class="close-modal" id="closeDailyDetailModal">&times;</button>
            </div>
            <div class="modal-body">
                <!-- 快速添加备忘录 -->
                <div class="quick-add-container">
                    <div class="quick-add-header">
                        <i class="fas fa-plus-circle"></i> 快速添加备忘录
                    </div>
                    <div class="quick-add-form">
                        <input type="text" class="quick-add-input" id="quickMemoTitle" placeholder="输入备忘录标题..." maxlength="100">
                        <button class="quick-add-button" id="quickAddMemo">添加</button>
                    </div>
                </div>
                <!-- 备忘录列表 -->
                <h3 style="margin-bottom: 12px;"><i class="fas fa-sticky-note"></i> 备忘录列表</h3>
                <div style="max-height: 350px; overflow-y: auto; padding-right: 10px;" id="dailyDetailList">
                    <div class="empty-state">
                        <i class="fas fa-clipboard"></i>
                        <p>今天还没有备忘录,添加一个吧!</p>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button class="btn btn-secondary" id="closeDailyDetailModalBtn">关闭</button>
                <button class="btn btn-primary" id="addNewMemoBtn">
                    <i class="fas fa-plus"></i> 添加详细备忘录
                </button>
            </div>
        </div>
    </div>
    <!-- 导入文件输入 -->
    <input type="file" id="importFileInput" accept=".json" style="display: none;">
    <!-- 确认对话框 -->
    <div class="modal" id="confirmationModal" style="display: none;">
        <div class="confirmation-dialog">
            <div class="confirmation-title" id="confirmationTitle">确认操作</div>
            <div class="confirmation-message" id="confirmationMessage"></div>
            <div class="confirmation-buttons">
                <button class="btn btn-secondary" id="cancelConfirm">取消</button>
                <button class="btn btn-danger" id="confirmAction">确认</button>
            </div>
        </div>
    </div>
    <!-- 提示信息 -->
    <div class="toast" id="toast">
        <i class="fas fa-check-circle"></i>
        <span id="toastMessage">操作成功</span>
    </div>
    <script>
        // ============== &#128313; Firebase 初始化 ==============
        // &#128312; 替换为你的真实配置!
        const firebaseConfig = {
            apiKey: "YOUR_API_KEY",
            authDomain: "calendar-memo-app.firebaseapp.com",
            projectId: "calendar-memo-app",
            storageBucket: "calendar-memo-app.appspot.com",
            messagingSenderId: "YOUR_SENDER_ID",
            appId: "YOUR_APP_ID"
        };

        // 初始化 Firebase(必须放在其他代码之前)
        firebase.initializeApp(firebaseConfig);
        const auth = firebase.auth();
        const db = firebase.firestore();

        // ============== 原有应用配置和状态 ==============
        const AppConfig = {
            DB_NAME: 'CalendarMemoDB',
            DB_VERSION: 4,
            DEFAULT_MONTHS_TO_SHOW: 2,
            DEFAULT_REMINDER_CHECK_INTERVAL: 5,
            DEFAULT_REMINDER_ADVANCE_TIME: 30,
            DEFAULT_EXPORT_TIME: '23:00',
            MARKDOWN_PREVIEW_DEBOUNCE: 300
        };

        const AppState = {
            db: null,
            currentDate: new Date(),
            selectedDate: new Date(),
            selectedMemoId: null,
            currentThemeIndex: 0,
            activeTab: 'taskPublish',
            dailyDetailDate: new Date(),
            monthsToShow: AppConfig.DEFAULT_MONTHS_TO_SHOW,
            reminderTimer: null,
            dueMemosCount: 0,
            isInitialized: false
        };

        const ReminderSettings = {
            checkInterval: AppConfig.DEFAULT_REMINDER_CHECK_INTERVAL,
            advanceTime: AppConfig.DEFAULT_REMINDER_ADVANCE_TIME,
            enableSound: true,
            enableDesktopNotification: false,
            autoClose: true
        };

        const MONTH_NAMES = ["1月", "2月", "3月", "4月", "5月", "6月", 
                           "7月", "8月", "9月", "10月", "11月", "12月"];
        const WEEKDAYS = ["日", "一", "二", "三", "四", "五", "六"];
        const COLOR_THEMES = [
            { name: "深海蓝", primary: "#4361ee", secondary: "#3a0ca3", accent: "#4cc9f0" },
            { name: "森林绿", primary: "#2ecc71", secondary: "#27ae60", accent: "#1abc9c" },
            { name: "日落橙", primary: "#ff9f1c", secondary: "#ff6b6b", accent: "#ffd166" },
            { name: "薰衣草", primary: "#9b5de5", secondary: "#f15bb5", accent: "#00bbf9" },
            { name: "岩浆红", primary: "#ef476f", secondary: "#ffd166", accent: "#06d6a0" },
            { name: "午夜紫", primary: "#7209b7", secondary: "#3a0ca3", accent: "#4361ee" },
            { name: "翡翠绿", primary: "#0fa3b1", secondary: "#5d5d81", accent: "#d9e5d6" },
            { name: "珊瑚粉", primary: "#ff6b6b", secondary: "#ff9f1c", accent: "#ffe66d" },
            { name: "深空蓝", primary: "#1a1a2e", secondary: "#16213e", accent: "#0f3460" },
            { name: "秋叶黄", primary: "#d4a373", secondary: "#ccd5ae", accent: "#e9edc9" },
            { name: "海洋之心", primary: "#00b4d8", secondary: "#0077b6", accent: "#90e0ef" },
            { name: "莫兰迪粉", primary: "#e5989b", secondary: "#b5838d", accent: "#ffb4a2" },
            { name: "极光绿", primary: "#52b788", secondary: "#40916c", accent: "#95d5b2" },
            { name: "星空紫", primary: "#7b2cbf", secondary: "#5a189a", accent: "#9d4edd" },
            { name: "暖阳橙", primary: "#fb8500", secondary: "#ff9e00", accent: "#ffb703" }
        ];

        const MEMO_COLORS = [
            "#4361ee", "#3a0ca3", "#4cc9f0", "#2ecc71", "#ff9f1c",
            "#9b5de5", "#ef476f", "#7209b7", "#0fa3b1", "#ff6b6b",
            "#00b4d8", "#e5989b", "#52b788", "#7b2cbf", "#fb8500"
        ];

        // ============== 工具函数 ==============
        class Utils {
            static formatDate(date) {
                if (!date) return '';
                const d = new Date(date);
                const year = d.getFullYear();
                const month = String(d.getMonth() + 1).padStart(2, '0');
                const day = String(d.getDate()).padStart(2, '0');
                return `${year}-${month}-${day}`;
            }

            static formatDateTime(date) {
                if (!date) return '';
                const d = new Date(date);
                return d.toLocaleString('zh-CN', {
                    year: 'numeric',
                    month: '2-digit',
                    day: '2-digit',
                    hour: '2-digit',
                    minute: '2-digit'
                });
            }

            static getTodayString() {
                return this.formatDate(new Date());
            }

            static isValidDate(dateString) {
                if (!dateString) return false;
                const regex = /^\d{4}-\d{2}-\d{2}$/;
                if (!regex.test(dateString)) return false;
                const date = new Date(dateString);
                return date instanceof Date && !isNaN(date);
            }

            static debounce(func, wait) {
                let timeout;
                return function executedFunction(...args) {
                    const later = () => {
                        clearTimeout(timeout);
                        func(...args);
                    };
                    clearTimeout(timeout);
                    timeout = setTimeout(later, wait);
                };
            }

            static showToast(message, type = 'success') {
                const toast = document.getElementById('toast');
                const messageEl = document.getElementById('toastMessage');
                messageEl.textContent = message;
                toast.className = `toast ${type}`;
                toast.classList.add('show');
                setTimeout(() => {
                    toast.classList.remove('show');
                }, 3000);
            }

            static showConfirmation(title, message, onConfirm) {
                const modal = document.getElementById('confirmationModal');
                const titleEl = document.getElementById('confirmationTitle');
                const messageEl = document.getElementById('confirmationMessage');
                const confirmBtn = document.getElementById('confirmAction');
                const cancelBtn = document.getElementById('cancelConfirm');
                titleEl.textContent = title;
                messageEl.textContent = message;
                modal.style.display = 'flex';
                const handleConfirm = () => {
                    modal.style.display = 'none';
                    onConfirm();
                    confirmBtn.removeEventListener('click', handleConfirm);
                    cancelBtn.removeEventListener('click', handleCancel);
                };
                const handleCancel = () => {
                    modal.style.display = 'none';
                    confirmBtn.removeEventListener('click', handleConfirm);
                    cancelBtn.removeEventListener('click', handleCancel);
                };
                confirmBtn.addEventListener('click', handleConfirm);
                cancelBtn.addEventListener('click', handleCancel);
            }
        }

        // ============== 数据库管理器 ==============
        class DatabaseManager {
            static async init() {
                return new Promise((resolve, reject) => {
                    const request = indexedDB.open(AppConfig.DB_NAME, AppConfig.DB_VERSION);
                    request.onerror = (event) => {
                        console.error("数据库打开失败:", event.target.error);
                        reject(new Error("无法打开数据库,请检查浏览器设置。"));
                    };
                    request.onsuccess = (event) => {
                        AppState.db = event.target.result;
                        console.log("数据库打开成功");
                        resolve();
                    };
                    request.onupgradeneeded = (event) => {
                        const db = event.target.result;
                        const oldVersion = event.oldVersion;
                        if (oldVersion < 1) {
                            const memoStore = db.createObjectStore('memos', { keyPath: 'id', autoIncrement: true });
                            memoStore.createIndex('date', 'date', { unique: false });
                            memoStore.createIndex('completed', 'completed', { unique: false });
                            memoStore.createIndex('dueTime', 'dueTime', { unique: false });
                            const settingsStore = db.createObjectStore('settings', { keyPath: 'key' });
                        }
                        console.log("数据库结构创建/升级成功");
                    };
                });
            }

            static async getAllMemos() {
                return new Promise((resolve, reject) => {
                    if (!AppState.db) {
                        reject(new Error('数据库未初始化'));
                        return;
                    }
                    const transaction = AppState.db.transaction(['memos'], 'readonly');
                    const store = transaction.objectStore('memos');
                    const request = store.getAll();
                    request.onsuccess = () => resolve(request.result);
                    request.onerror = (event) => reject(event.target.error);
                });
            }

            static async saveMemo(memo) {
                return new Promise((resolve, reject) => {
                    if (!AppState.db) {
                        reject(new Error('数据库未初始化'));
                        return;
                    }
                    const transaction = AppState.db.transaction(['memos'], 'readwrite');
                    const store = transaction.objectStore('memos');
                    memo.updatedAt = new Date().toISOString();
                    if (!memo.createdAt) {
                        memo.createdAt = memo.updatedAt;
                    }
                    const request = memo.id ? store.put(memo) : store.add(memo);
                    request.onsuccess = () => resolve(request.result);
                    request.onerror = (event) => reject(event.target.error);
                });
            }

            static async deleteMemo(memoId) {
                return new Promise((resolve, reject) => {
                    if (!AppState.db) {
                        reject(new Error('数据库未初始化'));
                        return;
                    }
                    const transaction = AppState.db.transaction(['memos'], 'readwrite');
                    const store = transaction.objectStore('memos');
                    const request = store.delete(memoId);
                    request.onsuccess = () => resolve();
                    request.onerror = (event) => reject(event.target.error);
                });
            }

            static async getSetting(key) {
                return new Promise((resolve, reject) => {
                    if (!AppState.db) {
                        reject(new Error('数据库未初始化'));
                        return;
                    }
                    const transaction = AppState.db.transaction(['settings'], 'readonly');
                    const store = transaction.objectStore('settings');
                    const request = store.get(key);
                    request.onsuccess = () => resolve(request.result ? request.result.value : null);
                    request.onerror = (event) => reject(event.target.error);
                });
            }

            static async saveSetting(key, value) {
                return new Promise((resolve, reject) => {
                    if (!AppState.db) {
                        reject(new Error('数据库未初始化'));
                        return;
                    }
                    const transaction = AppState.db.transaction(['settings'], 'readwrite');
                    const store = transaction.objectStore('settings');
                    const request = store.put({ key, value });
                    request.onsuccess = () => resolve();
                    request.onerror = (event) => reject(event.target.error);
                });
            }

            static async clearAllData() {
                return new Promise((resolve, reject) => {
                    if (!AppState.db) {
                        reject(new Error('数据库未初始化'));
                        return;
                    }
                    const transaction = AppState.db.transaction(['memos', 'settings'], 'readwrite');
                    const memoStore = transaction.objectStore('memos');
                    const settingsStore = transaction.objectStore('settings');
                    memoStore.clear();
                    settingsStore.clear();
                    transaction.oncomplete = () => resolve();
                    transaction.onerror = (event) => reject(event.target.error);
                });
            }
        }

        // ============== &#128313; 云端同步管理器 ==============
        class CloudSyncManager {
            static getCurrentUser() {
                return auth.currentUser;
            }

            static async login(email, password) {
                try {
                    await auth.signInWithEmailAndPassword(email, password);
                    Utils.showToast('&#9989; 登录成功');
                    await this.syncFromCloud();
                } catch (error) {
                    Utils.showToast('&#10060; 登录失败: ' + error.message, 'error');
                }
            }

            static async register(email, password) {
                try {
                    await auth.createUserWithEmailAndPassword(email, password);
                    Utils.showToast('&#9989; 注册成功,请登录');
                } catch (error) {
                    Utils.showToast('&#10060; 注册失败: ' + error.message, 'error');
                }
            }

            static async syncToCloud() {
                const user = this.getCurrentUser();
                if (!user) return;
                try {
                    const memos = await DatabaseManager.getAllMemos();
                    const batch = db.batch();
                    const userRef = db.collection('users').doc(user.uid);
                    // 清空
                    const oldSnapshot = await userRef.collection('memos').get();
                    oldSnapshot.docs.forEach(doc => batch.delete(doc.ref));
                    // 写入
                    memos.forEach(memo => {
                        batch.set(userRef.collection('memos').doc(memo.id.toString()), memo);
                    });
                    await batch.commit();
                    Utils.showToast('&#9989; 数据已同步到云端');
                } catch (error) {
                    console.error('上传失败:', error);
                    Utils.showToast('&#10060; 同步失败: ' + error.message, 'error');
                }
            }

            static async syncFromCloud() {
                const user = this.getCurrentUser();
                if (!user) return;
                try {
                    const userRef = db.collection('users').doc(user.uid);
                    const snapshot = await userRef.collection('memos').get();
                    const cloudMemos = [];
                    snapshot.forEach(doc => cloudMemos.push(doc.data()));

                    await DatabaseManager.clearAllData();
                    for (const memo of cloudMemos) {
                        if (typeof memo.id === 'string') memo.id = parseInt(memo.id);
                        await DatabaseManager.saveMemo(memo);
                    }
                    Utils.showToast(`&#9989; 同步了 ${cloudMemos.length} 条备忘录`);
                    CalendarManager.renderMultiMonthCalendar();
                    MemoManager.updateRecentTasks();
                    ReminderManager.updateReminderBadge();
                } catch (error) {
                    console.error('下载失败:', error);
                    Utils.showToast('&#10060; 同步失败: ' + error.message, 'error');
                }
            }
        }

        // ============== 日历管理器 ==============
        class CalendarManager {
            static renderMultiMonthCalendar() {
                const container = document.getElementById('multiMonthCalendar');
                const periodDisplay = document.getElementById('currentPeriod');
                container.innerHTML = '';
                container.className = `multi-month-calendar grid-${AppState.monthsToShow <= 2 ? AppState.monthsToShow : 2}`;
                const months = [];
                const startMonth = new Date(AppState.currentDate);
                const endMonth = new Date(AppState.currentDate);
                endMonth.setMonth(endMonth.getMonth() + AppState.monthsToShow - 1);
                for (let i = 0; i < AppState.monthsToShow; i++) {
                    const monthDate = new Date(AppState.currentDate);
                    monthDate.setMonth(AppState.currentDate.getMonth() + i);
                    months.push(monthDate);
                }
                if (AppState.monthsToShow === 1) {
                    periodDisplay.textContent = `${startMonth.getFullYear()}年${startMonth.getMonth() + 1}月`;
                } else {
                    periodDisplay.textContent = 
                        `${startMonth.getFullYear()}年${startMonth.getMonth() + 1}月 - ` +
                        `${endMonth.getFullYear()}年${endMonth.getMonth() + 1}月`;
                }
                months.forEach((monthDate, index) => {
                    const monthCalendar = this.createMonthCalendar(monthDate, index);
                    container.appendChild(monthCalendar);
                    setTimeout(() => this.loadMemosForMonth(monthDate, index), 0);
                });
            }

            static createMonthCalendar(monthDate, index) {
                const monthCalendar = document.createElement('div');
                monthCalendar.className = 'month-calendar';
                if (AppState.monthsToShow > 4) {
                    monthCalendar.classList.add('small');
                }
                monthCalendar.id = `monthCalendar${index}`;
                monthCalendar.dataset.month = monthDate.getMonth();
                monthCalendar.dataset.year = monthDate.getFullYear();
                const monthName = MONTH_NAMES[monthDate.getMonth()];
                monthCalendar.innerHTML = `
                    <div class="month-header">
                        <div class="month-title">
                            ${monthDate.getFullYear()}年 ${monthName}
                        </div>
                        <div class="month-right-area">
                            <div class="month-stats" id="monthStats${index}">
                                <div class="stat-item total">
                                    <i class="fas fa-tasks"></i>
                                    <span class="stat-count-total">0</span>
                                </div>
                                <div class="stat-item completed">
                                    <i class="fas fa-check-circle"></i>
                                    <span class="stat-count-completed">0</span>
                                </div>
                                <div class="stat-item pending">
                                    <i class="fas fa-clock"></i>
                                    <span class="stat-count-pending">0</span>
                                </div>
                            </div>
                            <div class="month-progress">
                                <div class="progress-circle" id="progressCircle${index}">
                                    <svg viewBox="0 0 36 36">
                                        <path class="progress-circle-bg" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831"></path>
                                        <path class="progress-circle-fill" stroke-dasharray="0, 100" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831"></path>
                                    </svg>
                                    <div class="progress-percent">0%</div>
                                </div>
                            </div>
                            <button class="complete-all-btn" data-month-index="${index}">
                                <i class="fas fa-check-double"></i> 一键完成
                            </button>
                        </div>
                    </div>
                    <div class="weekdays">
                        ${WEEKDAYS.map(day => `<div>${day}</div>`).join('')}
                    </div>
                    <div class="calendar-grid" id="calendarGrid${index}">
                        ${this.generateCalendarDays(monthDate)}
                    </div>
                `;
                const completeAllBtn = monthCalendar.querySelector('.complete-all-btn');
                completeAllBtn.addEventListener('click', (e) => {
                    e.stopPropagation();
                    this.completeAllMemosForMonth(monthDate.getMonth(), monthDate.getFullYear());
                });
                return monthCalendar;
            }

            static generateCalendarDays(monthDate) {
                const firstDay = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1);
                const lastDay = new Date(monthDate.getFullYear(), monthDate.getMonth() + 1, 0);
                const firstDayIndex = firstDay.getDay();
                const prevMonthLastDay = new Date(monthDate.getFullYear(), monthDate.getMonth(), 0).getDate();
                const today = new Date();
                const todayString = Utils.formatDate(today);
                let html = '';
                for (let i = firstDayIndex; i > 0; i--) {
                    const dayNum = prevMonthLastDay - i + 1;
                    html += `<div class="calendar-day other-month">${dayNum}</div>`;
                }
                for (let i = 1; i <= lastDay.getDate(); i++) {
                    const dateString = Utils.formatDate(new Date(monthDate.getFullYear(), monthDate.getMonth(), i));
                    const isToday = dateString === todayString;
                    const dayClass = isToday ? 'calendar-day today' : 'calendar-day';
                    html += `
                        <div class="${dayClass}" data-date="${dateString}">
                            <div class="day-number">${i}</div>
                            <div class="day-memos" id="dayMemos-${dateString}"></div>
                        </div>
                    `;
                }
                const totalCells = 42;
                const remainingCells = totalCells - (firstDayIndex + lastDay.getDate());
                for (let i = 1; i <= remainingCells; i++) {
                    html += `<div class="calendar-day other-month">${i}</div>`;
                }
                return html;
            }

            static async loadMemosForMonth(monthDate, monthIndex) {
                try {
                    const allMemos = await DatabaseManager.getAllMemos();
                    const searchTerm = document.getElementById('searchInput').value.trim().toLowerCase();
                    const monthStart = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1);
                    const monthEnd = new Date(monthDate.getFullYear(), monthDate.getMonth() + 1, 0);
                    const monthStartStr = Utils.formatDate(monthStart);
                    const monthEndStr = Utils.formatDate(monthEnd);
                    let totalMemos = 0;
                    let completedMemos = 0;
                    const dayMemosMap = new Map();
                    allMemos.forEach(memo => {
                        if (memo.date >= monthStartStr && memo.date <= monthEndStr) {
                            if (searchTerm && !this.memoMatchesSearch(memo, searchTerm)) {
                                return;
                            }
                            totalMemos++;
                            if (memo.completed) completedMemos++;
                            if (!dayMemosMap.has(memo.date)) {
                                dayMemosMap.set(memo.date, []);
                            }
                            dayMemosMap.get(memo.date).push(memo);
                        }
                    });
                    this.updateMonthStats(monthIndex, totalMemos, completedMemos);
                    dayMemosMap.forEach((memos, date) => {
                        this.renderDayMemos(date, memos);
                    });
                } catch (error) {
                    console.error('加载月份备忘录失败:', error);
                }
            }

            static memoMatchesSearch(memo, searchTerm) {
                if (!searchTerm) return true;
                return (memo.title && memo.title.toLowerCase().includes(searchTerm)) ||
                       (memo.content && memo.content.toLowerCase().includes(searchTerm)) ||
                       (memo.date && memo.date.includes(searchTerm));
            }

            static renderDayMemos(dateString, memos) {
                const dayMemosEl = document.getElementById(`dayMemos-${dateString}`);
                if (!dayMemosEl) return;
                dayMemosEl.innerHTML = '';
                if (memos.length === 0) return;
                const displayMemos = memos.slice(0, 5);
                displayMemos.forEach(memo => {
                    const memoItem = document.createElement('div');
                    memoItem.className = `day-memo-item ${memo.completed ? 'completed' : ''}`;
                    memoItem.title = memo.title;
                    memoItem.dataset.id = memo.id;
                    memoItem.style.borderLeftColor = memo.color || MEMO_COLORS[0];
                    let displayText = memo.title;
                    if (AppState.monthsToShow > 4) {
                        displayText = memo.title.length > 5 ? memo.title.substring(0, 5) + '...' : memo.title;
                    } else if (AppState.monthsToShow > 1) {
                        displayText = memo.title.length > 10 ? memo.title.substring(0, 10) + '...' : memo.title;
                    } else {
                        displayText = memo.title.length > 15 ? memo.title.substring(0, 15) + '...' : memo.title;
                    }
                    memoItem.innerHTML = `
                        <span class="memo-color-dot" style="background-color: ${memo.color || MEMO_COLORS[0]}"></span>
                        ${displayText}
                    `;
                    memoItem.addEventListener('click', (e) => {
                        e.stopPropagation();
                        MemoManager.openMemoModal(memo.id);
                    });
                    dayMemosEl.appendChild(memoItem);
                });
                if (memos.length > 5) {
                    const memoCount = document.createElement('div');
                    memoCount.className = 'memo-count';
                    memoCount.textContent = memos.length > 99 ? '99+' : memos.length;
                    dayMemosEl.parentElement.appendChild(memoCount);
                }
            }

            static updateMonthStats(monthIndex, total, completed) {
                const statsEl = document.getElementById(`monthStats${monthIndex}`);
                if (!statsEl) return;
                const pending = total - completed;
                const progressPercent = total > 0 ? Math.round((completed / total) * 100) : 0;
                statsEl.querySelector('.stat-count-total').textContent = total;
                statsEl.querySelector('.stat-count-completed').textContent = completed;
                statsEl.querySelector('.stat-count-pending').textContent = pending;
                const progressCircle = document.getElementById(`progressCircle${monthIndex}`);
                if (progressCircle) {
                    const fill = progressCircle.querySelector('.progress-circle-fill');
                    const percentText = progressCircle.querySelector('.progress-percent');
                    fill.style.strokeDasharray = `${progressPercent}, 100`;
                    percentText.textContent = `${progressPercent}%`;
                }
            }

            static async completeAllMemosForMonth(month, year) {
                Utils.showConfirmation(
                    '一键完成确认',
                    `确定要将${year}年${month + 1}月的所有备忘录标记为已完成吗?`,
                    async () => {
                        try {
                            const allMemos = await DatabaseManager.getAllMemos();
                            const monthStart = new Date(year, month, 1);
                            const monthEnd = new Date(year, month + 1, 0);
                            const monthStartStr = Utils.formatDate(monthStart);
                            const monthEndStr = Utils.formatDate(monthEnd);
                            let completedCount = 0;
                            const updatePromises = [];
                            allMemos.forEach(memo => {
                                if (memo.date >= monthStartStr && memo.date <= monthEndStr && !memo.completed) {
                                    memo.completed = true;
                                    memo.updatedAt = new Date().toISOString();
                                    updatePromises.push(DatabaseManager.saveMemo(memo));
                                    completedCount++;
                                }
                            });
                            await Promise.all(updatePromises);
                            Utils.showToast(`已成功将 ${completedCount} 个备忘录标记为完成!`);
                            this.renderMultiMonthCalendar();
                            MemoManager.updateRecentTasks();
                            ReminderManager.updateReminderBadge();
                            if (document.getElementById('dailyDetailModal').classList.contains('active')) {
                                DailyDetailManager.loadDailyDetailMemos(AppState.dailyDetailDate);
                            }
                        } catch (error) {
                            console.error('一键完成失败:', error);
                            Utils.showToast('操作失败,请重试', 'error');
                        }
                    }
                );
            }
        }

        // ============== 备忘录管理器 ==============
        class MemoManager {
            static debouncedPreview = null;

            static async openMemoModal(memoId = null, date = null) {
                const modal = document.getElementById('memoModal');
                const deleteBtn = document.getElementById('deleteMemo');
                const modalTitle = document.querySelector('#memoModal .modal-title');
                AppState.selectedMemoId = memoId;
                document.getElementById('memoForm').reset();
                this.initColorPicker();
                const today = Utils.formatDate(new Date());
                if (date) {
                    document.getElementById('memoDate').value = Utils.formatDate(date);
                } else {
                    document.getElementById('memoDate').value = today;
                }
                const tomorrow = new Date();
                tomorrow.setDate(tomorrow.getDate() + 1);
                tomorrow.setHours(18, 0, 0, 0);
                document.getElementById('memoDueTime').value = tomorrow.toISOString().slice(0, 16);
                if (memoId) {
                    modalTitle.textContent = '编辑备忘录';
                    deleteBtn.style.display = 'inline-block';
                    await this.loadMemoData(memoId);
                } else {
                    modalTitle.textContent = '新建备忘录';
                    deleteBtn.style.display = 'none';
                }
                modal.classList.add('active');
                this.updateMarkdownPreview();
                const memoContent = document.getElementById('memoContent');
                memoContent.removeEventListener('input', this.debouncedPreview);
                this.debouncedPreview = Utils.debounce(() => this.updateMarkdownPreview(), AppConfig.MARKDOWN_PREVIEW_DEBOUNCE);
                memoContent.addEventListener('input', this.debouncedPreview);
            }

            static initColorPicker() {
                const colorOptionsEl = document.getElementById('colorOptions');
                colorOptionsEl.innerHTML = '';
                MEMO_COLORS.forEach(color => {
                    const colorOption = document.createElement('div');
                    colorOption.className = 'color-option';
                    colorOption.style.backgroundColor = color;
                    colorOption.dataset.color = color;
                    colorOption.addEventListener('click', function() {
                        document.querySelectorAll('#colorOptions .color-option').forEach(el => {
                            el.classList.remove('selected');
                        });
                        this.classList.add('selected');
                    });
                    colorOptionsEl.appendChild(colorOption);
                });
                colorOptionsEl.firstChild.classList.add('selected');
            }

            static async loadMemoData(memoId) {
                try {
                    const allMemos = await DatabaseManager.getAllMemos();
                    const memo = allMemos.find(m => m.id === memoId);
                    if (memo) {
                        document.getElementById('memoTitle').value = memo.title || '';
                        document.getElementById('memoDate').value = memo.date || '';
                        document.getElementById('memoDueTime').value = memo.dueTime ? 
                            memo.dueTime.slice(0, 16) : '';
                        document.getElementById('memoContent').value = memo.content || '';
                        document.getElementById('memoCompleted').checked = memo.completed || false;
                        if (memo.color) {
                            document.querySelectorAll('#colorOptions .color-option').forEach(el => {
                                el.classList.remove('selected');
                                if (el.dataset.color === memo.color) {
                                    el.classList.add('selected');
                                }
                            });
                        }
                        this.updateMarkdownPreview();
                    }
                } catch (error) {
                    console.error('加载备忘录数据失败:', error);
                    Utils.showToast('加载备忘录失败', 'error');
                }
            }

            static updateMarkdownPreview() {
                const content = document.getElementById('memoContent').value;
                const previewEl = document.getElementById('markdownPreview');
                if (content.trim() === '') {
                    previewEl.innerHTML = '<p style="color: #6c757d; font-style: italic;">预览将在这里显示...</p>';
                    return;
                }
                marked.setOptions({
                    highlight: function(code, lang) {
                        if (lang && hljs.getLanguage(lang)) {
                            return hljs.highlight(code, { language: lang }).value;
                        }
                        return hljs.highlightAuto(code).value;
                    },
                    breaks: true,
                    gfm: true
                });
                try {
                    previewEl.innerHTML = marked.parse(content);
                } catch (error) {
                    previewEl.innerHTML = '<p style="color: #f44336;">Markdown解析错误</p>';
                }
            }

            static async saveMemo() {
                const title = document.getElementById('memoTitle').value.trim();
                const date = document.getElementById('memoDate').value;
                const dueTime = document.getElementById('memoDueTime').value;
                const content = document.getElementById('memoContent').value.trim();
                const completed = document.getElementById('memoCompleted').checked;
                if (!title) {
                    Utils.showToast('请输入备忘录标题', 'error');
                    return;
                }
                if (!date || !Utils.isValidDate(date)) {
                    Utils.showToast('请选择有效的日期', 'error');
                    return;
                }
                const selectedColor = document.querySelector('#colorOptions .color-option.selected').dataset.color;
                const memo = {
                    title,
                    date,
                    dueTime: dueTime ? new Date(dueTime).toISOString() : null,
                    content,
                    color: selectedColor,
                    completed,
                    reminderShown: false
                };
                if (AppState.selectedMemoId) {
                    memo.id = AppState.selectedMemoId;
                }
                try {
                    await DatabaseManager.saveMemo(memo);
                    Utils.showToast('备忘录保存成功');
                    this.closeMemoModal();
                    CalendarManager.renderMultiMonthCalendar();
                    this.updateRecentTasks();
                    ReminderManager.updateReminderBadge();
                    if (document.getElementById('dailyDetailModal').classList.contains('active')) {
                        DailyDetailManager.loadDailyDetailMemos(AppState.dailyDetailDate);
                    }
                } catch (error) {
                    console.error('保存备忘录失败:', error);
                    Utils.showToast('保存失败,请重试', 'error');
                }
            }

            static async deleteMemo() {
                if (!AppState.selectedMemoId) return;
                Utils.showConfirmation(
                    '删除确认',
                    '确定要删除这个备忘录吗?此操作不可撤销。',
                    async () => {
                        try {
                            await DatabaseManager.deleteMemo(AppState.selectedMemoId);
                            Utils.showToast('备忘录删除成功');
                            this.closeMemoModal();
                            CalendarManager.renderMultiMonthCalendar();
                            this.updateRecentTasks();
                            ReminderManager.updateReminderBadge();
                            if (document.getElementById('dailyDetailModal').classList.contains('active')) {
                                DailyDetailManager.loadDailyDetailMemos(AppState.dailyDetailDate);
                            }
                        } catch (error) {
                            console.error('删除备忘录失败:', error);
                            Utils.showToast('删除失败,请重试', 'error');
                        }
                    }
                );
            }

            static closeMemoModal() {
                const modal = document.getElementById('memoModal');
                modal.classList.remove('active');
                AppState.selectedMemoId = null;
            }

            static async updateRecentTasks() {
                try {
                    const allMemos = await DatabaseManager.getAllMemos();
                    const recentTasksEl = document.getElementById('recentTasksList');
                    recentTasksEl.innerHTML = '';
                    const recentMemos = allMemos
                        .sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt))
                        .slice(0, 10);
                    if (recentMemos.length === 0) {
                        recentTasksEl.innerHTML = `
                            <div class="empty-state">
                                <i class="fas fa-clipboard-list"></i>
                                <p>暂无任务,点击日历上的日期添加新任务</p>
                            </div>
                        `;
                        return;
                    }
                    recentMemos.forEach(memo => {
                        const taskItem = this.createTaskItem(memo);
                        recentTasksEl.appendChild(taskItem);
                    });
                    this.bindRecentTaskEvents();
                } catch (error) {
                    console.error('更新最近任务失败:', error);
                }
            }

            static createTaskItem(memo) {
                const taskItem = document.createElement('div');
                taskItem.className = 'task-item';
                taskItem.style.borderLeftColor = memo.color || MEMO_COLORS[0];
                let countdownHtml = '';
                if (memo.dueTime && !memo.completed) {
                    const dueDate = new Date(memo.dueTime);
                    const now = new Date();
                    const timeDiff = dueDate - now;
                    const daysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
                    let countdownClass = 'success';
                    let countdownText = '';
                    if (daysDiff < 0) {
                        countdownClass = 'danger';
                        countdownText = `已过期 ${Math.abs(daysDiff)} 天`;
                    } else if (daysDiff === 0) {
                        countdownClass = 'danger';
                        countdownText = '今天到期';
                    } else if (daysDiff <= 3) {
                        countdownClass = 'warning';
                        countdownText = `${daysDiff} 天后到期`;
                    } else {
                        countdownText = `${daysDiff} 天后到期`;
                    }
                    countdownHtml = `<span class="countdown ${countdownClass}">${countdownText}</span>`;
                }
                const dueDateStr = memo.dueTime ? 
                    new Date(memo.dueTime).toLocaleDateString('zh-CN') : '无截止日期';
                const contentPreview = memo.content ? 
                    memo.content.replace(/[#*`[\]]/g, '').substring(0, 60) + 
                    (memo.content.length > 60 ? '...' : '') : 
                    '无内容';
                taskItem.innerHTML = `
                    <div class="task-header">
                        <div class="task-title">${memo.title || '无标题'}</div>
                        <div class="task-color" style="background-color: ${memo.color || MEMO_COLORS[0]}"></div>
                    </div>
                    <div class="task-due">
                        <i class="far fa-calendar-alt"></i> ${dueDateStr} ${countdownHtml}
                    </div>
                    <div class="task-content">${contentPreview}</div>
                    <div class="task-actions">
                        <button class="task-btn task-btn-complete" data-id="${memo.id}">
                            ${memo.completed ? '<i class="fas fa-undo"></i> 标记为未完成' : '<i class="fas fa-check"></i> 标记为完成'}
                        </button>
                        <button class="task-btn task-btn-edit" data-id="${memo.id}">
                            <i class="fas fa-edit"></i> 编辑
                        </button>
                        <button class="task-btn task-btn-delete" data-id="${memo.id}">
                            <i class="fas fa-trash"></i> 删除
                        </button>
                    </div>
                `;
                return taskItem;
            }

            static bindRecentTaskEvents() {
                const recentTasksEl = document.getElementById('recentTasksList');
                if (!recentTasksEl) return;
                recentTasksEl.addEventListener('click', (e) => {
                    const target = e.target;
                    if (target.classList.contains('task-btn-complete') || 
                        target.closest('.task-btn-complete')) {
                        const btn = target.classList.contains('task-btn-complete') ? 
                            target : target.closest('.task-btn-complete');
                        const memoId = parseInt(btn.dataset.id);
                        if (memoId) {
                            this.toggleMemoCompletion(memoId);
                        }
                        e.stopPropagation();
                    }
                    else if (target.classList.contains('task-btn-edit') || 
                             target.closest('.task-btn-edit')) {
                        const btn = target.classList.contains('task-btn-edit') ? 
                            target : target.closest('.task-btn-edit');
                        const memoId = parseInt(btn.dataset.id);
                        if (memoId) {
                            App.closeFunctionsModal();
                            this.openMemoModal(memoId);
                        }
                        e.stopPropagation();
                    }
                    else if (target.classList.contains('task-btn-delete') || 
                             target.closest('.task-btn-delete')) {
                        const btn = target.classList.contains('task-btn-delete') ? 
                            target : target.closest('.task-btn-delete');
                        const memoId = parseInt(btn.dataset.id);
                        if (memoId) {
                            this.deleteMemoById(memoId);
                        }
                        e.stopPropagation();
                    }
                });
            }

            static async toggleMemoCompletion(memoId) {
                try {
                    const allMemos = await DatabaseManager.getAllMemos();
                    const memo = allMemos.find(m => m.id === memoId);
                    if (memo) {
                        memo.completed = !memo.completed;
                        memo.updatedAt = new Date().toISOString();
                        if (memo.completed) {
                            memo.reminderShown = false;
                            const reminderKey = `reminder_${memo.id}_${new Date().toDateString()}`;
                            localStorage.removeItem(reminderKey);
                        }
                        await DatabaseManager.saveMemo(memo);
                        Utils.showToast(`备忘录已${memo.completed ? '完成' : '恢复为未完成'}`);
                        CalendarManager.renderMultiMonthCalendar();
                        this.updateRecentTasks();
                        ReminderManager.updateReminderBadge();
                        const dailyDetailModal = document.getElementById('dailyDetailModal');
                        if (dailyDetailModal.classList.contains('active')) {
                            DailyDetailManager.loadDailyDetailMemos(AppState.dailyDetailDate);
                        }
                    }
                } catch (error) {
                    console.error('切换备忘录状态失败:', error);
                    Utils.showToast('操作失败,请重试', 'error');
                }
            }

            static async deleteMemoById(memoId) {
                Utils.showConfirmation(
                    '删除确认',
                    '确定要删除这个备忘录吗?此操作不可撤销。',
                    async () => {
                        try {
                            await DatabaseManager.deleteMemo(memoId);
                            Utils.showToast('备忘录删除成功');
                            CalendarManager.renderMultiMonthCalendar();
                            this.updateRecentTasks();
                            ReminderManager.updateReminderBadge();
                            const dailyDetailModal = document.getElementById('dailyDetailModal');
                            if (dailyDetailModal.classList.contains('active')) {
                                DailyDetailManager.loadDailyDetailMemos(AppState.dailyDetailDate);
                            }
                        } catch (error) {
                            console.error('删除备忘录失败:', error);
                            Utils.showToast('删除失败,请重试', 'error');
                        }
                    }
                );
            }
        }

        // ============== 每日详情管理器 ==============
        class DailyDetailManager {
            static openDailyDetailModal(date) {
                const modal = document.getElementById('dailyDetailModal');
                AppState.dailyDetailDate = date;
                const dateDisplay = document.getElementById('dailyDetailDate');
                dateDisplay.textContent = 
                    `${date.getFullYear()}年 ${date.getMonth() + 1}月${date.getDate()}日`;
                document.getElementById('quickMemoTitle').value = '';
                this.loadDailyDetailMemos(date);
                modal.classList.add('active');
                setTimeout(() => {
                    document.getElementById('quickMemoTitle').focus();
                }, 100);
            }

            static async loadDailyDetailMemos(date) {
                try {
                    const allMemos = await DatabaseManager.getAllMemos();
                    const memoListEl = document.getElementById('dailyDetailList');
                    const dateStr = Utils.formatDate(date);
                    memoListEl.innerHTML = '';
                    const dayMemos = allMemos.filter(memo => memo.date === dateStr);
                    if (dayMemos.length === 0) {
                        memoListEl.innerHTML = `
                            <div class="empty-state">
                                <i class="fas fa-clipboard"></i>
                                <p>这一天还没有备忘录,添加一个吧!</p>
                            </div>
                        `;
                        return;
                    }
                    dayMemos.forEach(memo => {
                        const taskItem = MemoManager.createTaskItem(memo);
                        memoListEl.appendChild(taskItem);
                    });
                    this.bindDailyDetailEvents();
                } catch (error) {
                    console.error('加载每日详情失败:', error);
                }
            }

            static bindDailyDetailEvents() {
                const dailyDetailList = document.getElementById('dailyDetailList');
                if (!dailyDetailList) return;
                dailyDetailList.addEventListener('click', (e) => {
                    const target = e.target;
                    if (target.classList.contains('task-btn-complete') || 
                        target.closest('.task-btn-complete')) {
                        const btn = target.classList.contains('task-btn-complete') ? 
                            target : target.closest('.task-btn-complete');
                        const memoId = parseInt(btn.dataset.id);
                        if (memoId) {
                            MemoManager.toggleMemoCompletion(memoId);
                        }
                        e.stopPropagation();
                    }
                    else if (target.classList.contains('task-btn-edit') || 
                             target.closest('.task-btn-edit')) {
                        const btn = target.classList.contains('task-btn-edit') ? 
                            target : target.closest('.task-btn-edit');
                        const memoId = parseInt(btn.dataset.id);
                        if (memoId) {
                            this.closeDailyDetailModal();
                            MemoManager.openMemoModal(memoId);
                        }
                        e.stopPropagation();
                    }
                    else if (target.classList.contains('task-btn-delete') || 
                             target.closest('.task-btn-delete')) {
                        const btn = target.classList.contains('task-btn-delete') ? 
                            target : target.closest('.task-btn-delete');
                        const memoId = parseInt(btn.dataset.id);
                        if (memoId) {
                            MemoManager.deleteMemoById(memoId);
                        }
                        e.stopPropagation();
                    }
                });
            }

            static async quickAddMemo() {
                const title = document.getElementById('quickMemoTitle').value.trim();
                if (!title) {
                    Utils.showToast('请输入备忘录标题', 'error');
                    return;
                }
                const dateStr = Utils.formatDate(AppState.dailyDetailDate);
                const memo = {
                    title: title,
                    date: dateStr,
                    content: '',
                    color: MEMO_COLORS[Math.floor(Math.random() * MEMO_COLORS.length)],
                    completed: false,
                    reminderShown: false
                };
                try {
                    await DatabaseManager.saveMemo(memo);
                    Utils.showToast('快速备忘录添加成功');
                    document.getElementById('quickMemoTitle').value = '';
                    this.loadDailyDetailMemos(AppState.dailyDetailDate);
                    CalendarManager.renderMultiMonthCalendar();
                    ReminderManager.updateReminderBadge();
                } catch (error) {
                    console.error('快速添加备忘录失败:', error);
                    Utils.showToast('添加失败,请重试', 'error');
                }
            }

            static closeDailyDetailModal() {
                const modal = document.getElementById('dailyDetailModal');
                modal.classList.remove('active');
            }
        }

        // ============== 提醒管理器 ==============
        class ReminderManager {
            static init() {
                this.loadReminderSettings();
                this.startReminderChecker();
                this.updateReminderBadge();
            }

            static async loadReminderSettings() {
                try {
                    const checkInterval = await DatabaseManager.getSetting('reminderCheckInterval');
                    const advanceTime = await DatabaseManager.getSetting('reminderAdvanceTime');
                    const enableSound = await DatabaseManager.getSetting('enableSoundReminder');
                    const enableDesktop = await DatabaseManager.getSetting('enableDesktopNotification');
                    if (checkInterval !== null) ReminderSettings.checkInterval = parseInt(checkInterval);
                    if (advanceTime !== null) ReminderSettings.advanceTime = parseInt(advanceTime);
                    if (enableSound !== null) ReminderSettings.enableSound = enableSound === 'true';
                    if (enableDesktop !== null) ReminderSettings.enableDesktopNotification = enableDesktop === 'true';
                    document.getElementById('reminderCheckInterval').value = ReminderSettings.checkInterval;
                    document.getElementById('reminderAdvanceTime').value = ReminderSettings.advanceTime;
                    document.getElementById('enableSoundReminder').checked = ReminderSettings.enableSound;
                    document.getElementById('enableDesktopNotification').checked = ReminderSettings.enableDesktopNotification;
                } catch (error) {
                    console.error('加载提醒设置失败:', error);
                }
            }

            static async saveReminderSettings() {
                try {
                    const checkInterval = parseInt(document.getElementById('reminderCheckInterval').value);
                    const advanceTime = parseInt(document.getElementById('reminderAdvanceTime').value);
                    const enableSound = document.getElementById('enableSoundReminder').checked;
                    const enableDesktop = document.getElementById('enableDesktopNotification').checked;
                    ReminderSettings.checkInterval = checkInterval;
                    ReminderSettings.advanceTime = advanceTime;
                    ReminderSettings.enableSound = enableSound;
                    ReminderSettings.enableDesktopNotification = enableDesktop;
                    await DatabaseManager.saveSetting('reminderCheckInterval', checkInterval.toString());
                    await DatabaseManager.saveSetting('reminderAdvanceTime', advanceTime.toString());
                    await DatabaseManager.saveSetting('enableSoundReminder', enableSound.toString());
                    await DatabaseManager.saveSetting('enableDesktopNotification', enableDesktop.toString());
                    Utils.showToast('提醒设置已保存');
                    this.startReminderChecker();
                } catch (error) {
                    console.error('保存提醒设置失败:', error);
                    Utils.showToast('保存失败,请重试', 'error');
                }
            }

            static startReminderChecker() {
                if (AppState.reminderTimer) {
                    clearInterval(AppState.reminderTimer);
                }
                this.checkDueMemos();
                const interval = ReminderSettings.checkInterval * 60 * 1000;
                AppState.reminderTimer = setInterval(() => {
                    this.checkDueMemos();
                }, interval);
            }

            static async checkDueMemos() {
                try {
                    const allMemos = await DatabaseManager.getAllMemos();
                    const now = new Date();
                    const advanceTime = ReminderSettings.advanceTime * 60 * 1000;
                    const dueMemos = [];
                    const today = new Date().toDateString();
                    allMemos.forEach(memo => {
                        if (memo.dueTime && !memo.completed) {
                            const dueTime = new Date(memo.dueTime);
                            const reminderTime = new Date(dueTime.getTime() - advanceTime);
                            if (now >= reminderTime) {
                                const reminderKey = `reminder_${memo.id}_${today}`;
                                const shownToday = localStorage.getItem(reminderKey);
                                if (!shownToday) {
                                    dueMemos.push({
                                        ...memo,
                                        reminderKey: reminderKey
                                    });
                                    localStorage.setItem(reminderKey, 'true');
                                    memo.reminderShown = true;
                                    DatabaseManager.saveMemo(memo);
                                }
                            }
                        }
                    });
                    if (dueMemos.length > 0) {
                        this.showReminderModal(dueMemos);
                    }
                    this.updateReminderBadge();
                } catch (error) {
                    console.error('检查到期备忘录失败:', error);
                }
            }

            static async updateReminderBadge() {
                try {
                    const allMemos = await DatabaseManager.getAllMemos();
                    const now = new Date();
                    const advanceTime = ReminderSettings.advanceTime * 60 * 1000;
                    const today = new Date().toDateString();
                    let count = 0;
                    allMemos.forEach(memo => {
                        if (memo.dueTime && !memo.completed) {
                            const dueTime = new Date(memo.dueTime);
                            const reminderTime = new Date(dueTime.getTime() - advanceTime);
                            const reminderKey = `reminder_${memo.id}_${today}`;
                            const shownToday = localStorage.getItem(reminderKey);
                            if (now >= reminderTime && !shownToday) {
                                count++;
                            }
                        }
                    });
                    AppState.dueMemosCount = count;
                    const badge = document.getElementById('reminderBadge');
                    const bellButton = document.getElementById('floatingReminder');
                    if (count > 0) {
                        badge.textContent = count > 99 ? '99+' : count;
                        badge.style.display = 'flex';
                        bellButton.classList.add('reminder-pulse');
                    } else {
                        badge.style.display = 'none';
                        bellButton.classList.remove('reminder-pulse');
                    }
                } catch (error) {
                    console.error('更新提醒徽章失败:', error);
                }
            }

            static showReminderModal(dueMemos = null) {
                const modal = document.getElementById('reminderModal');
                if (dueMemos && dueMemos.length > 0) {
                    this.displayReminders(dueMemos);
                } else {
                    this.loadAndDisplayReminders();
                }
                modal.classList.add('active');
                if (ReminderSettings.enableSound) {
                    this.playReminderSound();
                }
                if (ReminderSettings.autoClose) {
                    setTimeout(() => {
                        if (modal.classList.contains('active')) {
                            this.closeReminderModal();
                        }
                    }, 10000);
                }
            }

            static displayReminders(memos) {
                const reminderList = document.getElementById('reminderList');
                reminderList.innerHTML = '';
                if (memos.length === 0) {
                    reminderList.innerHTML = `
                        <div class="empty-state">
                            <i class="fas fa-bell-slash"></i>
                            <p>暂无到期提醒</p>
                        </div>
                    `;
                    return;
                }
                memos.forEach(memo => {
                    const reminderItem = this.createReminderItem(memo);
                    reminderList.appendChild(reminderItem);
                });
            }

            static createReminderItem(memo) {
                const reminderItem = document.createElement('div');
                reminderItem.className = 'reminder-item';
                const dueTime = new Date(memo.dueTime);
                const now = new Date();
                const timeDiff = dueTime - now;
                const hoursDiff = Math.floor(timeDiff / (1000 * 60 * 60));
                const minutesDiff = Math.floor((timeDiff % (1000 * 60 * 60)) / (1000 * 60));
                let statusText = '';
                let statusColor = 'var(--danger-color)';
                if (timeDiff < 0) {
                    statusText = `已过期 ${Math.abs(hoursDiff)}小时${Math.abs(minutesDiff)}分钟`;
                    statusColor = 'var(--danger-color)';
                } else if (timeDiff < 60 * 60 * 1000) {
                    statusText = `${minutesDiff}分钟后到期`;
                    statusColor = 'var(--warning-color)';
                } else {
                    statusText = `${hoursDiff}小时${minutesDiff}分钟后到期`;
                    statusColor = 'var(--primary-color)';
                }
                reminderItem.innerHTML = `
                    <div class="reminder-item-title">${memo.title}</div>
                    <div class="reminder-item-details">
                        <span><i class="far fa-calendar"></i> ${dueTime.toLocaleDateString('zh-CN')} ${dueTime.toLocaleTimeString('zh-CN', {hour: '2-digit', minute:'2-digit'})}</span>
                        <span style="color: ${statusColor}; font-weight: 600;">${statusText}</span>
                    </div>
                `;
                reminderItem.addEventListener('click', () => {
                    MemoManager.openMemoModal(memo.id);
                    this.closeReminderModal();
                });
                return reminderItem;
            }

            static async loadAndDisplayReminders() {
                try {
                    const allMemos = await DatabaseManager.getAllMemos();
                    const now = new Date();
                    const advanceTime = ReminderSettings.advanceTime * 60 * 1000;
                    const today = new Date().toDateString();
                    const dueMemos = [];
                    allMemos.forEach(memo => {
                        if (memo.dueTime && !memo.completed) {
                            const dueTime = new Date(memo.dueTime);
                            const reminderTime = new Date(dueTime.getTime() - advanceTime);
                            const reminderKey = `reminder_${memo.id}_${today}`;
                            const shownToday = localStorage.getItem(reminderKey);
                            if (now >= reminderTime && !shownToday) {
                                dueMemos.push(memo);
                            }
                        }
                    });
                    this.displayReminders(dueMemos);
                } catch (error) {
                    console.error('加载提醒失败:', error);
                }
            }

            static playReminderSound() {
                try {
                    const audioContext = new (window.AudioContext || window.webkitAudioContext)();
                    const oscillator = audioContext.createOscillator();
                    const gainNode = audioContext.createGain();
                    oscillator.connect(gainNode);
                    gainNode.connect(audioContext.destination);
                    oscillator.frequency.value = 800;
                    oscillator.type = 'sine';
                    gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
                    gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 1);
                    oscillator.start(audioContext.currentTime);
                    oscillator.stop(audioContext.currentTime + 1);
                } catch (e) {
                    console.log('无法播放提示音:', e);
                }
            }

            static closeReminderModal() {
                const modal = document.getElementById('reminderModal');
                modal.classList.remove('active');
            }

            static markAllRemindersAsRead() {
                const today = new Date().toDateString();
                Object.keys(localStorage).forEach(key => {
                    if (key.includes('reminder_') && key.includes(today)) {
                        localStorage.removeItem(key);
                    }
                });
                DatabaseManager.getAllMemos().then(memos => {
                    memos.forEach(memo => {
                        if (memo.reminderShown) {
                            memo.reminderShown = false;
                            DatabaseManager.saveMemo(memo);
                        }
                    });
                });
                this.closeReminderModal();
                this.updateReminderBadge();
                Utils.showToast('所有提醒已标记为已读');
            }

            static testReminder() {
                const testMemos = [{
                    id: 999,
                    title: '测试提醒',
                    dueTime: new Date().toISOString(),
                    content: '这是一个测试提醒'
                }];
                this.showReminderModal(testMemos);
            }
        }

        // ============== 主题管理器 ==============
        class ThemeManager {
            static init() {
                this.initThemeSelector();
                this.applyTheme(AppState.currentThemeIndex);
            }

            static initThemeSelector() {
                const themeSelector = document.getElementById('themeSelector');
                themeSelector.innerHTML = '';
                COLOR_THEMES.forEach((theme, index) => {
                    const themeColor = document.createElement('div');
                    themeColor.className = `theme-color ${index === AppState.currentThemeIndex ? 'active' : ''}`;
                    themeColor.style.background = `linear-gradient(135deg, ${theme.primary}, ${theme.secondary})`;
                    themeColor.title = theme.name;
                    themeColor.dataset.index = index;
                    themeColor.textContent = theme.name;
                    themeColor.addEventListener('click', () => {
                        AppState.currentThemeIndex = parseInt(themeColor.dataset.index);
                        this.applyTheme(AppState.currentThemeIndex);
                        document.querySelectorAll('.theme-color').forEach(el => el.classList.remove('active'));
                        themeColor.classList.add('active');
                        themeSelector.classList.remove('active');
                    });
                    themeSelector.appendChild(themeColor);
                });
            }

            static applyTheme(themeIndex) {
                const theme = COLOR_THEMES[themeIndex];
                const root = document.documentElement;
                root.style.setProperty('--primary-color', theme.primary);
                root.style.setProperty('--secondary-color', theme.secondary);
                root.style.setProperty('--accent-color', theme.accent);
                document.querySelector('header').style.background = 
                    `linear-gradient(135deg, ${theme.primary}, ${theme.secondary})`;
                document.querySelectorAll('.nav-button, .calendar-nav-btn, .floating-btn, .toolbar-btn-primary').forEach(el => {
                    el.style.background = `linear-gradient(135deg, ${theme.primary}, ${theme.secondary})`;
                });
                document.querySelectorAll('.modal-header').forEach(el => {
                    el.style.background = `linear-gradient(90deg, ${theme.primary}, ${theme.secondary})`;
                });
                document.querySelectorAll('.progress-circle-fill').forEach(el => {
                    el.style.stroke = theme.primary;
                });
                localStorage.setItem('selectedTheme', themeIndex.toString());
            }
        }

        // ============== 数据管理器 ==============
        class DataManager {
            static async exportData() {
                try {
                    const allMemos = await DatabaseManager.getAllMemos();
                    const settings = await this.getAllSettings();
                    const exportData = {
                        memos: allMemos,
                        settings: settings,
                        exportDate: new Date().toISOString(),
                        version: '2.0',
                        appName: '智能网页工作日历备忘录'
                    };
                    const dataStr = JSON.stringify(exportData, null, 2);
                    const dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
                    const exportFileName = `calendar-memo-backup-${Utils.formatDate(new Date())}.json`;
                    const linkElement = document.createElement('a');
                    linkElement.setAttribute('href', dataUri);
                    linkElement.setAttribute('download', exportFileName);
                    linkElement.click();
                    Utils.showToast('数据导出成功!');
                } catch (error) {
                    console.error('导出数据失败:', error);
                    Utils.showToast('导出失败,请重试', 'error');
                }
            }

            static async getAllSettings() {
                try {
                    const transaction = AppState.db.transaction(['settings'], 'readonly');
                    const store = transaction.objectStore('settings');
                    const request = store.getAll();
                    return new Promise((resolve, reject) => {
                        request.onsuccess = () => resolve(request.result);
                        request.onerror = (event) => reject(event.target.error);
                    });
                } catch (error) {
                    console.error('获取设置失败:', error);
                    return [];
                }
            }

            static importData() {
                document.getElementById('importFileInput').click();
            }

            static async handleFileImport(event) {
                const file = event.target.files[0];
                if (!file) return;
                const reader = new FileReader();
                reader.onload = async (e) => {
                    try {
                        const importData = JSON.parse(e.target.result);
                        if (!importData.memos || !Array.isArray(importData.memos)) {
                            throw new Error('文件格式不正确');
                        }
                        Utils.showConfirmation(
                            '导入确认',
                            `即将导入 ${importData.memos.length} 条备忘录。是否继续?`,
                            async () => {
                                try {
                                    await DatabaseManager.clearAllData();
                                    for (const memo of importData.memos) {
                                        await DatabaseManager.saveMemo(memo);
                                    }
                                    if (importData.settings && Array.isArray(importData.settings)) {
                                        for (const setting of importData.settings) {
                                            await DatabaseManager.saveSetting(setting.key, setting.value);
                                        }
                                    }
                                    Utils.showToast('数据导入成功!');
                                    CalendarManager.renderMultiMonthCalendar();
                                    MemoManager.updateRecentTasks();
                                    ReminderManager.loadReminderSettings();
                                    ReminderManager.startReminderChecker();
                                } catch (error) {
                                    console.error('导入数据失败:', error);
                                    Utils.showToast('导入失败,请检查文件格式', 'error');
                                }
                            }
                        );
                    } catch (error) {
                        console.error('解析文件失败:', error);
                        Utils.showToast('文件解析失败,请确保选择的是有效的备份文件', 'error');
                    }
                    event.target.value = '';
                };
                reader.readAsText(file);
            }

            static async clearAllData() {
                Utils.showConfirmation(
                    '清空数据确认',
                    '确定要清空所有数据吗?此操作不可撤销!',
                    async () => {
                        try {
                            await DatabaseManager.clearAllData();
                            Utils.showToast('所有数据已清空!');
                            CalendarManager.renderMultiMonthCalendar();
                            MemoManager.updateRecentTasks();
                            ReminderManager.updateReminderBadge();
                        } catch (error) {
                            console.error('清空数据失败:', error);
                            Utils.showToast('清空数据失败,请重试', 'error');
                        }
                    }
                );
            }
        }

        // ============== 任务发布管理器 ==============
        class TaskPublisher {
            static init() {
                this.initTaskColorPicker();
                this.setDefaultDates();
            }

            static initTaskColorPicker() {
                const colorOptionsEl = document.getElementById('taskColorOptions');
                if (!colorOptionsEl) return;
                colorOptionsEl.innerHTML = '';
                MEMO_COLORS.forEach(color => {
                    const colorOption = document.createElement('div');
                    colorOption.className = 'color-option';
                    colorOption.style.backgroundColor = color;
                    colorOption.dataset.color = color;
                    colorOption.addEventListener('click', function() {
                        document.querySelectorAll('#taskColorOptions .color-option').forEach(el => {
                            el.classList.remove('selected');
                        });
                        this.classList.add('selected');
                    });
                    colorOptionsEl.appendChild(colorOption);
                });
                colorOptionsEl.firstChild.classList.add('selected');
            }

            static setDefaultDates() {
                const today = new Date();
                const tomorrow = new Date();
                tomorrow.setDate(tomorrow.getDate() + 7);
                document.getElementById('taskStartDate').value = Utils.formatDate(today);
                document.getElementById('taskEndDate').value = Utils.formatDate(tomorrow);
            }

            static async publishTask() {
                const title = document.getElementById('taskTitle').value.trim();
                const description = document.getElementById('taskDescription').value.trim();
                const startDate = document.getElementById('taskStartDate').value;
                const endDate = document.getElementById('taskEndDate').value;
                const dueTime = document.getElementById('taskDueTime').value;
                if (!title) {
                    Utils.showToast('请输入任务标题', 'error');
                    return;
                }
                if (!startDate || !endDate || !Utils.isValidDate(startDate) || !Utils.isValidDate(endDate)) {
                    Utils.showToast('请选择有效的开始和结束日期', 'error');
                    return;
                }
                const start = new Date(startDate);
                const end = new Date(endDate);
                if (start > end) {
                    Utils.showToast('开始日期不能晚于结束日期', 'error');
                    return;
                }
                const days = Math.ceil((end - start) / (1000 * 60 * 60 * 24)) + 1;
                if (days > 100) {
                    Utils.showConfirmation(
                        '确认发布',
                        `此任务将分配到 ${days} 天,数量较多,是否继续?`,
                        () => this.createTask(title, description, start, end, dueTime, days)
                    );
                } else {
                    this.createTask(title, description, start, end, dueTime, days);
                }
            }

            static async createTask(title, description, start, end, dueTime, totalDays) {
                const selectedColor = document.querySelector('#taskColorOptions .color-option.selected').dataset.color;
                let createdCount = 0;
                const errors = [];
                for (let currentDate = new Date(start); currentDate <= end; currentDate.setDate(currentDate.getDate() + 1)) {
                    try {
                        const taskDate = Utils.formatDate(currentDate);
                        const dueDateTime = new Date(taskDate + 'T' + dueTime);
                        const memo = {
                            title: `${title} (第${createdCount + 1}天/${totalDays}天)`,
                            date: taskDate,
                            dueTime: dueDateTime.toISOString(),
                            content: description,
                            color: selectedColor,
                            completed: false,
                            reminderShown: false
                        };
                        await DatabaseManager.saveMemo(memo);
                        createdCount++;
                    } catch (error) {
                        errors.push(`第${createdCount + 1}天: ${error.message}`);
                    }
                }
                let message = `任务发布完成!成功创建了 ${createdCount} 个每日任务。`;
                if (errors.length > 0) {
                    message += ` ${errors.length} 个任务创建失败。`;
                    console.error('任务创建错误:', errors);
                }
                Utils.showToast(message);
                document.getElementById('taskTitle').value = '';
                document.getElementById('taskDescription').value = '';
                this.setDefaultDates();
                CalendarManager.renderMultiMonthCalendar();
                MemoManager.updateRecentTasks();
                ReminderManager.updateReminderBadge();
            }
        }

        // ============== &#128313; 扩展 App 类以支持同步 ==============
        class App {
            static async init() {
                try {
                    await DatabaseManager.init();
                    ThemeManager.init();
                    this.initMonthCountSelector();
                    CalendarManager.renderMultiMonthCalendar();
                    this.initEventListeners();
                    ReminderManager.init();
                    AppState.isInitialized = true;
                    console.log('应用初始化完成');
                } catch (error) {
                    console.error('应用初始化失败:', error);
                    Utils.showToast('应用初始化失败,请刷新页面重试', 'error');
                }
            }

            static initMonthCountSelector() {
                const monthCountSelect = document.getElementById('monthCountSelect');
                const savedMonthCount = localStorage.getItem('calendarMonthCount');
                if (savedMonthCount) {
                    AppState.monthsToShow = parseInt(savedMonthCount);
                    monthCountSelect.value = savedMonthCount;
                }
                monthCountSelect.addEventListener('change', function() {
                    AppState.monthsToShow = parseInt(this.value);
                    localStorage.setItem('calendarMonthCount', AppState.monthsToShow);
                    CalendarManager.renderMultiMonthCalendar();
                });
            }

            static initEventListeners() {
                document.getElementById('prevMonth').addEventListener('click', () => {
                    AppState.currentDate.setMonth(AppState.currentDate.getMonth() - 1);
                    CalendarManager.renderMultiMonthCalendar();
                });
                document.getElementById('nextMonth').addEventListener('click', () => {
                    AppState.currentDate.setMonth(AppState.currentDate.getMonth() + 1);
                    CalendarManager.renderMultiMonthCalendar();
                });
                document.getElementById('calendarPrevMonth').addEventListener('click', () => {
                    AppState.currentDate.setMonth(AppState.currentDate.getMonth() - 1);
                    CalendarManager.renderMultiMonthCalendar();
                });
                document.getElementById('calendarNextMonth').addEventListener('click', () => {
                    AppState.currentDate.setMonth(AppState.currentDate.getMonth() + 1);
                    CalendarManager.renderMultiMonthCalendar();
                });

                document.addEventListener('click', (e) => {
                    const calendarDay = e.target.closest('.calendar-day:not(.other-month)');
                    if (calendarDay && calendarDay.dataset.date) {
                        const [year, month, day] = calendarDay.dataset.date.split('-').map(Number);
                        const date = new Date(year, month - 1, day);
                        DailyDetailManager.openDailyDetailModal(date);
                    }
                });

                document.getElementById('saveMemo').addEventListener('click', () => MemoManager.saveMemo());
                document.getElementById('deleteMemo').addEventListener('click', () => MemoManager.deleteMemo());
                document.getElementById('cancelMemo').addEventListener('click', () => MemoManager.closeMemoModal());
                document.getElementById('closeMemoModal').addEventListener('click', () => MemoManager.closeMemoModal());

                document.getElementById('closeDailyDetailModal').addEventListener('click', () => DailyDetailManager.closeDailyDetailModal());
                document.getElementById('closeDailyDetailModalBtn').addEventListener('click', () => DailyDetailManager.closeDailyDetailModal());
                document.getElementById('addNewMemoBtn').addEventListener('click', () => {
                    DailyDetailManager.closeDailyDetailModal();
                    MemoManager.openMemoModal(null, AppState.dailyDetailDate);
                });
                document.getElementById('quickAddMemo').addEventListener('click', () => DailyDetailManager.quickAddMemo());
                document.getElementById('quickMemoTitle').addEventListener('keypress', (e) => {
                    if (e.key === 'Enter') {
                        DailyDetailManager.quickAddMemo();
                    }
                });

                document.getElementById('themeSelectorBtn').addEventListener('click', (e) => {
                    e.stopPropagation();
                    document.getElementById('themeSelector').classList.toggle('active');
                });
                document.addEventListener('click', (e) => {
                    const themeSelector = document.getElementById('themeSelector');
                    const themeSelectorBtn = document.getElementById('themeSelectorBtn');
                    if (!themeSelector.contains(e.target) && !themeSelectorBtn.contains(e.target)) {
                        themeSelector.classList.remove('active');
                    }
                });

                document.getElementById('closeReminderModal').addEventListener('click', () => ReminderManager.closeReminderModal());
                document.getElementById('markAllAsRead').addEventListener('click', () => ReminderManager.markAllRemindersAsRead());
                document.getElementById('viewRecentTasks').addEventListener('click', () => {
                    ReminderManager.closeReminderModal();
                    this.openFunctionsModal('recentTasks');
                });

                document.getElementById('floatingReminder').addEventListener('click', () => ReminderManager.showReminderModal());
                document.getElementById('floatingFunctions').addEventListener('click', () => this.openFunctionsModal('taskPublish'));

                document.getElementById('toolbarPublish').addEventListener('click', () => this.openFunctionsModal('taskPublish'));
                document.getElementById('toolbarExport').addEventListener('click', () => DataManager.exportData());
                document.getElementById('toolbarImport').addEventListener('click', () => DataManager.importData());

                document.getElementById('searchInput').addEventListener('input', Utils.debounce(() => {
                    CalendarManager.renderMultiMonthCalendar();
                }, 300));
                document.getElementById('clearSearch').addEventListener('click', () => {
                    document.getElementById('searchInput').value = '';
                    CalendarManager.renderMultiMonthCalendar();
                });

                document.getElementById('closeFunctionsModal').addEventListener('click', () => this.closeFunctionsModal());
                document.getElementById('closeFunctionsModalBtn').addEventListener('click', () => this.closeFunctionsModal());

                document.querySelectorAll('.tab').forEach(tab => {
                    tab.addEventListener('click', () => {
                        const tabName = tab.dataset.tab;
                        this.setActiveTab(tabName);
                        if (tabName === 'taskPublish') {
                            TaskPublisher.init();
                        } else if (tabName === 'recentTasks') {
                            MemoManager.updateRecentTasks();
                        }
                    });
                });

                document.getElementById('exportData').addEventListener('click', () => DataManager.exportData());
                document.getElementById('importData').addEventListener('click', () => DataManager.importData());
                document.getElementById('clearData').addEventListener('click', () => DataManager.clearAllData());
                document.getElementById('importFileInput').addEventListener('change', (e) => DataManager.handleFileImport(e));

                document.getElementById('publishTask').addEventListener('click', () => TaskPublisher.publishTask());

                document.getElementById('saveReminderSettings').addEventListener('click', () => ReminderManager.saveReminderSettings());
                document.getElementById('testReminder').addEventListener('click', () => ReminderManager.testReminder());

                document.querySelectorAll('.modal').forEach(modal => {
                    modal.addEventListener('click', (e) => {
                        if (e.target === modal) {
                            modal.classList.remove('active');
                        }
                    });
                });

                document.getElementById('cancelConfirm').addEventListener('click', () => {
                    document.getElementById('confirmationModal').style.display = 'none';
                });

                // &#128313; 新增:同步功能事件绑定
                document.getElementById('loginBtn')?.addEventListener('click', async () => {
                    const email = document.getElementById('syncEmail').value.trim();
                    const pass = document.getElementById('syncPassword').value;
                    if (!email || !pass) {
                        Utils.showToast('请输入邮箱和密码', 'error');
                        return;
                    }
                    await CloudSyncManager.login(email, pass);
                    App.updateAuthUI();
                });

                document.getElementById('registerBtn')?.addEventListener('click', async () => {
                    const email = document.getElementById('syncEmail').value.trim();
                    const pass = document.getElementById('syncPassword').value;
                    if (!email || !pass || pass.length < 6) {
                        Utils.showToast('密码至少6位', 'error');
                        return;
                    }
                    await CloudSyncManager.register(email, pass);
                });

                document.getElementById('syncToCloud')?.addEventListener('click', () => CloudSyncManager.syncToCloud());
                document.getElementById('syncFromCloud')?.addEventListener('click', () => CloudSyncManager.syncFromCloud());

                auth.onAuthStateChanged(user => {
                    App.updateAuthUI();
                });
            }

            static openFunctionsModal(tab = 'taskPublish') {
                const modal = document.getElementById('functionsModal');
                this.setActiveTab(tab);
                if (tab === 'taskPublish') {
                    TaskPublisher.init();
                } else if (tab === 'recentTasks') {
                    MemoManager.updateRecentTasks();
                }
                modal.classList.add('active');
            }

            static closeFunctionsModal() {
                document.getElementById('functionsModal').classList.remove('active');
            }

            static setActiveTab(tabName) {
                AppState.activeTab = tabName;
                document.querySelectorAll('.tab').forEach(tab => {
                    tab.classList.toggle('active', tab.dataset.tab === tabName);
                });
                document.querySelectorAll('.tab-content').forEach(content => {
                    content.classList.toggle('active', content.id === `${tabName}Tab`);
                });
            }

            // &#128313; 新增:更新同步 UI
            static updateAuthUI() {
                const user = CloudSyncManager.getCurrentUser();
                const statusEl = document.getElementById('authStatus');
                const btnUpload = document.getElementById('syncToCloud');
                const btnDownload = document.getElementById('syncFromCloud');
                const logoutBtn = document.getElementById('logoutBtn');
                if (logoutBtn) logoutBtn.remove();

                if (user) {
                    const logoutHtml = `<button class="btn btn-secondary" id="logoutBtn" style="margin-left:10px; font-size:0.85rem;">退出</button>`;
                    statusEl.innerHTML = `已登录: ${user.email}` + logoutHtml;
                    btnUpload.disabled = false;
                    btnDownload.disabled = false;
                    document.getElementById('logoutBtn')?.addEventListener('click', () => {
                        auth.signOut();
                    });
                } else {
                    statusEl.textContent = '未登录';
                    btnUpload.disabled = true;
                    btnDownload.disabled = true;
                }
            }
        }

        // ============== 启动应用 ==============
        document.addEventListener('DOMContentLoaded', async () => {
            await App.init();
            // 初始调用 UI 更新
            App.updateAuthUI();
        });
    </script>
</body>
</html>

沙发
cqfyaaa 发表于 2025-12-10 18:26
3#
小酒窝 发表于 2025-12-10 18:43
联机版和插件版有啥不一样?应用场景有啥不同?
4#
pinghost 发表于 2025-12-10 18:51
这个有点厉害,不知道移动端UI怎么样,感谢!
5#
 楼主| dada02 发表于 2025-12-10 18:54 |楼主
小酒窝 发表于 2025-12-10 18:43
联机版和插件版有啥不一样?应用场景有啥不同?

本机版,插件在本地,如字体样式等
联机版,插件联网运行
6#
 楼主| dada02 发表于 2025-12-10 18:54 |楼主
pinghost 发表于 2025-12-10 18:51
这个有点厉害,不知道移动端UI怎么样,感谢!

联机版,手机可以试一下
7#
zt185 发表于 2025-12-10 18:56
办公方便了,就怕忘事很需要备忘录!
8#
rafer1 发表于 2025-12-10 19:00
不错,支持
9#
yh21cn 发表于 2025-12-10 19:05
支持一下,谢谢分享
10#
wakin20 发表于 2025-12-10 19:14
多谢分享,体验一下。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-12-12 09:15

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表