吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2291|回复: 35
收起左侧

[其他原创] 纯离线html:积分小管家:用积分带娃

[复制链接]
跳墙的爷 发表于 2026-6-16 17:22
本帖最后由 跳墙的爷 于 2026-6-17 16:26 编辑

现在学校、小饭桌,都采取积分奖励式带娃,之前dy也看到有大神做了app,不过是私用的。

前两天在公众号看到一个网页版的积分小管家,便用这个模板,用AI优化了一下,纯离线运行,历史数据可以保存,可以清控,设置可以重置、自定义,非常轻便,发到手机上,点开就能用,不到50kb。

搞这东西目的是讲究一个轻量、简单、纯粹、离线,即点即用,大神们可以根据需要优化(现在ai好用)


打包成了apk(29kb),下载后后缀改成apk即可食用 积分小管家_v1.zip (28.52 KB, 下载次数: 40)


image.png image.png image.png image.png


txt改成html就行,要是有大神能封装成一个app就好了,不过估计app安装包可能就不止100km了

源码如下:
[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta name="robots" content="noindex,nofollow"><meta name="generator" content="ShipPage"><link rel="canonical" href="https://shippage.ai/p/jifen">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>积分小管家</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
            min-height: 100vh;
            color: #333;
            padding-bottom: 80px;
        }
        
        /* 顶部导航 */
        .header {
            background: rgba(255, 255, 255, 0.95);
            padding: 15px 20px;
            position: sticky;
            top: 0;
            z-index: 100;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }
        
        /* 周积分网格样式 */
        .day-item {
            cursor: pointer;
            transition: all 0.2s ease;
            background: #f8f9fa;
            border-radius: 10px;
            padding: 10px 5px;
            text-align: center;
        }
        
        .day-item:hover {
            transform: translateY(-2px);
        }
        
        .day-item:active {
            transform: scale(0.95);
        }
        
        .day-item.selected {
            background: rgba(34, 197, 94, 0.1);
        }
        
        .day-points.today-points {
            font-weight: 800;
            font-size: 18px;
        }
        
        .day-points.selected-points {
            font-weight: 600;
            font-size: 16px;
            opacity: 0.8;
        }
        
        .header h1 {
            font-size: 20px;
            font-weight: 700;
            color: #22c55e;
            text-align: center;
        }
        
        /* 积分卡片 */
        .points-card {
            background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
            margin: 20px;
            padding: 24px 20px;
            border-radius: 20px;
            color: white;
            box-shadow: 0 8px 20px rgba(34, 197, 94, 0.4);
            text-align: center;
        }
        
        .points-header {
            display: flex;
            align-items: baseline;
            justify-content: center;
            gap: 12px;
            margin-bottom: 8px;
        }
        
        .points-title {
            font-size: 16px;
            font-weight: 600;
            opacity: 0.85;
            letter-spacing: 2px;
        }
        
        .points-amount {
            font-size: 56px;
            font-weight: 900;
            text-shadow: 0 2px 8px rgba(0,0,0,0.2);
            letter-spacing: 2px;
        }
        
        .points-today {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10px;
            font-size: 14px;
            background: rgba(255,255,255,0.15);
            border-radius: 12px;
            padding: 8px 16px;
            margin: 0 auto;
            width: fit-content;
        }
        
        .today-divider {
            width: 1px;
            height: 18px;
            background: rgba(255, 255, 255, 0.5);
        }
        
        .today-value {
            font-weight: 800;
            font-size: 15px;
        }
        
        .points-actions {
            display: flex;
            gap: 8px;
            margin-top: 12px;
        }
        
        .points-btn {
            flex: 1;
            padding: 10px;
            border: none;
            border-radius: 12px;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s;
        }
        
        .points-btn.primary {
            background: white;
            color: #22c55e;
        }
        
        .points-btn.danger {
            background: rgba(239, 68, 68, 0.9);
            color: white;
        }
        
        .points-btn:active {
            transform: scale(0.95);
        }
        

        /* 功能入口 */
        .features {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 10px;
            padding: 0 20px;
            margin-bottom: 15px;
        }
        
        .feature-item {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 14px;
            padding: 12px 8px;
            text-align: center;
            cursor: pointer;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
            transition: all 0.3s;
        }
        
        .feature-item:active {
            transform: scale(0.95);
        }
        
        .feature-icon {
            font-size: 24px;
            margin-bottom: 6px;
        }
        
        .feature-name {
            font-size: 11px;
            color: #333;
            font-weight: 600;
        }
        
        /* 内容区域 */
        .content-section {
            background: white;
            margin: 0 20px 15px;
            border-radius: 16px;
            padding: 15px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
        }
        
        .section-title {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: space-between;
            gap: 8px;
            margin-bottom: 15px;
        }
        
        .section-title > span {
            font-size: 18px;
            font-weight: 700;
            color: #333;
        }
        
        .section-actions {
            display: flex;
            gap: 8px;
        }
        
        .action-btn {
            padding: 6px 12px;
            border: none;
            border-radius: 8px;
            font-size: 12px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s;
        }
        
        /* 手机端兼容性优化 */
        [url=home.php?mod=space&uid=945662]@media[/url] (max-width: 480px) {
            .action-btn {
                font-size: 11px;
                padding: 5px 10px;
            }
            
            .list-item {
                flex-wrap: wrap;
                gap: 10px;
            }
            
            .list-item .section-actions {
                width: 100%;
                justify-content: flex-end;
                margin-top: 5px;
            }
        }
        
        .action-btn.add {
            background: #22c55e;
            color: white;
        }
        
        .action-btn.edit {
            background: #f59e0b;
            color: white;
        }
        
        .action-btn.delete {
            background: #ef4444;
            color: white;
        }
        
        /* 列表项 */
        .list-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 12px;
            margin-bottom: 10px;
        }
        
        .list-item:last-child {
            margin-bottom: 0;
        }
        
        .item-info {
            flex: 1;
        }
        
        .item-name {
            font-size: 14px;
            font-weight: 600;
            margin-bottom: 4px;
        }
        
        .item-points {
            font-size: 16px;
            font-weight: 700;
        }
        
        .item-points.income {
            color: #10b981;
        }
        
        .item-points.expense {
            color: #ef4444;
        }
        
        .item-actions {
            display: flex;
            gap: 8px;
        }
        
        .item-btn {
            padding: 6px 12px;
            border: none;
            border-radius: 8px;
            font-size: 12px;
            font-weight: 600;
            cursor: pointer;
        }
        
        .item-btn.earn {
            background: #10b981;
            color: white;
        }
        
        .item-btn.deduct {
            background: #ef4444;
            color: white;
        }
        
        .item-btn.exchange {
            background: #667eea;
            color: white;
        }
        
        /* 快速添加行 */
        .quick-add {
            display: flex;
            align-items: center;
            gap: 8px;
            padding: 10px;
            background: #f0fdf4;
            border: 1px dashed #22c55e;
            border-radius: 12px;
            margin-bottom: 12px;
        }
        
        .quick-add input {
            border: 1px solid #e5e7eb;
            border-radius: 8px;
            padding: 8px 10px;
            font-size: 13px;
            outline: none;
        }
        
        .quick-add input:focus {
            border-color: #22c55e;
        }
        
        .quick-add .qa-name {
            flex: 1;
            max-width: 50%;
        }
        
        .quick-add .qa-points {
            width: 80px;
            text-align: center;
        }
        
        .quick-add .qa-btn {
            padding: 8px 16px;
            background: #22c55e;
            color: white;
            border: none;
            border-radius: 8px;
            font-size: 13px;
            font-weight: 600;
            cursor: pointer;
            white-space: nowrap;
            margin-left: auto;
        }
        
        .quick-add .qa-btn:active {
            background: #16a34a;
        }
        
        .quick-add.deduct {
            background: #fef2f2;
            border-color: #fca5a5;
        }
        
        .quick-add.deduct input:focus {
            border-color: #ef4444;
        }
        
        .quick-add.deduct .qa-btn {
            background: #ef4444;
        }
        
        .quick-add.deduct .qa-btn:active {
            background: #dc2626;
        }
        
        .quick-add.exchange {
            background: #f5f3ff;
            border-color: #c4b5fd;
        }
        
        .quick-add.exchange input:focus {
            border-color: #667eea;
        }
        
        .quick-add.exchange .qa-btn {
            background: #667eea;
        }
        
        .quick-add.exchange .qa-btn:active {
            background: #4f46e5;
        }
        
        /* 周积分统计 */
        .week-stats {
            margin-bottom: 20px;
        }
        
        .week-grid {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 8px;
        }
        
        .day-item.today {
            background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
            color: white;
        }
        
        .day-name {
            font-size: 10px;
            margin-bottom: 4px;
            color: #666;
        }
        
        .day-item.today .day-name {
            color: rgba(255, 255, 255, 0.9);
        }
        
        .day-points {
            font-size: 14px;
            font-weight: 700;
        }
        
        .day-item.today .day-points {
            color: white;
        }
        
        /* 历史积分月日历 */
        .month-calendar {
            background: #f8f9fa;
            border-radius: 12px;
            padding: 12px;
            margin-bottom: 12px;
        }
        
        .month-header {
            display: flex;
            align-items: center;
            margin-bottom: 10px;
        }
        
        .month-title {
            font-size: 14px;
            font-weight: 700;
        }
        
        .month-weekdays {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 4px;
            margin-bottom: 4px;
        }
        
        .month-weekday {
            text-align: center;
            font-size: 10px;
            color: #999;
            padding: 2px 0;
        }
        
        .month-days {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 4px;
        }
        
        .month-day {
            text-align: center;
            padding: 6px 2px;
            background: white;
            border-radius: 6px;
            min-height: 38px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
        }
        
        .month-day.empty {
            background: transparent;
        }
        
        .month-day.today {
            background: rgba(34, 197, 94, 0.15);
        }
        
        .month-day.today .month-day-num {
            font-weight: 700;
            color: #22c55e;
        }
        
        .month-day-num {
            font-size: 11px;
            color: #333;
            line-height: 1;
        }
        
        .month-day-pts {
            font-size: 10px;
            font-weight: 600;
            color: #22c55e;
            line-height: 1;
            margin-top: 1px;
        }
        
        /* 年历卡片 */
        .year-calendar {
            display: grid;
            grid-template-columns: repeat(6, 1fr);
            gap: 8px;
        }
        
        .year-month-card {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 10px 6px;
            text-align: center;
        }
        
        .year-month-card.current {
            background: rgba(34, 197, 94, 0.1);
            border: 1.5px solid #22c55e;
        }
        
        .year-month-name {
            font-size: 11px;
            color: #666;
            margin-bottom: 4px;
        }
        
        .year-month-total {
            font-size: 16px;
            font-weight: 700;
            color: #22c55e;
        }
        
        /* 积分记录列表 */
        .record-list {
            max-height: 400px;
            overflow-y: auto;
        }
        
        .record-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 15px 0;
            border-bottom: 1px solid #f0f0f0;
        }
        
        .record-item:last-child {
            border-bottom: none;
        }
        
        .record-info {
            flex: 1;
        }
        
        .record-title {
            font-size: 14px;
            font-weight: 600;
            margin-bottom: 4px;
        }
        
        .record-time {
            font-size: 12px;
            color: #999;
        }
        
        .record-amount {
            font-size: 16px;
            font-weight: 700;
            padding-left: 10px;
            padding-right: 15px;
            margin: 5px 0;
        }
        
        .record-amount.income {
            color: #10b981;
        }
        
        .record-amount.expense {
            color: #ef4444;
        }
        
        /* 底部导航菜单 */
        .bottom-nav {
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            background: white;
            display: flex;
            justify-content: space-around;
            padding: 10px 0;
            padding-bottom: calc(10px + env(safe-area-inset-bottom));
            box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
            z-index: 100;
        }
        
        .nav-item {
            text-align: center;
            cursor: pointer;
            flex: 1;
        }
        
        .nav-icon {
            font-size: 22px;
            margin-bottom: 2px;
        }
        
        .nav-text {
            font-size: 11px;
            color: #999;
        }
        
        .nav-item.active .nav-text {
            color: #22c55e;
        }
        
        .nav-item.active .nav-icon {
            color: #22c55e;
        }
        
        /* 弹窗样式 */
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0, 0, 0, 0.5);
            z-index: 1000;
            align-items: center;
            justify-content: center;
        }
        
        .modal.show {
            display: flex;
        }
        
        .modal-content {
            background: white;
            border-radius: 20px;
            padding: 25px;
            width: 90%;
            max-width: 400px;
            animation: modalSlide 0.3s ease;
        }
        
        @keyframes modalSlide {
            from {
                transform: translateY(20px);
                opacity: 0;
            }
            to {
                transform: translateY(0);
                opacity: 1;
            }
        }
        
        .modal-title {
            font-size: 18px;
            font-weight: 700;
            margin-bottom: 20px;
            text-align: center;
        }
        
        .modal-body {
            margin-bottom: 20px;
        }
        
        .form-group {
            margin-bottom: 15px;
        }
        
        .form-label {
            display: block;
            font-size: 14px;
            font-weight: 600;
            margin-bottom: 8px;
            color: #333;
        }
        
        .form-input {
            width: 100%;
            padding: 12px;
            border: 2px solid #e0e0e0;
            border-radius: 10px;
            font-size: 14px;
            transition: all 0.3s;
        }
        
        .form-input:focus {
            outline: none;
            border-color: #22c55e;
        }
        
        .form-input[type="number"] {
            -moz-appearance: textfield;
        }
        
        .form-input[type="number"]::-webkit-outer-spin-button,
        .form-input[type="number"]::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
        
        .modal-footer {
            display: flex;
            gap: 10px;
        }
        
        .modal-btn {
            flex: 1;
            padding: 12px;
            border: none;
            border-radius: 10px;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
        }
        
        .modal-btn.confirm {
            background: #22c55e;
            color: white;
        }
        
        .modal-btn.cancel {
            background: #f0f0f0;
            color: #666;
        }
        
        .modal-btn.danger {
            background: #ef4444;
            color: white;
        }
        
        /* 页面切换 */
        .page {
            display: none;
        }
        
        .page.active {
            display: block;
        }
        
        /* 空状态 */
        .empty-state {
            text-align: center;
            padding: 40px 20px;
            color: #999;
        }
        
        .empty-icon {
            font-size: 48px;
            margin-bottom: 12px;
        }
        
        .empty-text {
            font-size: 14px;
        }
        
        /* 响应式适配 */
        @media (max-width: 420px) {
            .points-amount {
                font-size: 48px;
            }
            
            .features {
                gap: 8px;
            }
            
            .week-grid {
                gap: 4px;
            }
            
            .day-item {
                padding: 8px 3px;
            }
        }
    </style>
</head>
<body>
    <!-- 顶部导航 -->
    <div class="header">
        <h1>积分小管家</h1>
    </div>
    
    <!-- 底部导航菜单 -->
    <div class="bottom-nav">
        <div class="nav-item active">
            <div class="nav-icon">&#127968;</div>
            <div class="nav-text">首页</div>
        </div>
    </div>
    
    <!-- 首页 -->
    <div class="page active" id="home-page">
        <!-- 积分卡片(总积分 + 今日积分合并) -->
        <div class="points-card">
            <div class="points-header">
                <div class="points-title">总积分</div>
                <div class="points-amount" id="total-points">0</div>
            </div>
            <div class="points-today">
                <span>&#128197; 今日积分</span>
                <span class="today-divider"></span>
                <span class="today-value" id="daily-challenge">赚0分 - 扣0分 = 0分</span>
            </div>
        </div>
        
        <!-- 功能入口 -->
        <div class="features">
            <div class="feature-item">
                <div class="feature-icon">&#10133;</div>
                <div class="feature-name">赚取积分</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">&#10134;</div>
                <div class="feature-name">扣取积分</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">&#127978;</div>
                <div class="feature-name">奖励兑换中心</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">&#128176;</div>
                <div class="feature-name">积分项设置</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">&#9888;&#65039;</div>
                <div class="feature-name">扣分项设置</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">&#127873;</div>
                <div class="feature-name">兑换奖励设置</div>
            </div>
        </div>
        
        <!-- 本周积分 -->
        <div class="content-section">
            <div class="section-title">
                <span id="week-score-text">本周积分</span>
            </div>
            <div class="week-stats">
                <div class="week-grid" id="current-week-grid">
                    <!-- 动态加载 -->
                </div>
            </div>
        </div>
        
        <!-- 快捷工具 -->
        <div class="features">
            <div class="feature-item">
                <div class="feature-icon">&#128202;</div>
                <div class="feature-name">积分记录</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">&#128465;&#65039;</div>
                <div class="feature-name">积分清空</div>
            </div>
            <div class="feature-item">
                <div class="feature-icon">&#128260;</div>
                <div class="feature-name">系统重置</div>
            </div>
        </div>
    </div>
    
    <!-- 赚取积分页面 -->
    <div class="page" id="earn-page">
        <div class="content-section">
            <div class="section-title">
                <span>赚取积分</span>
            </div>
            <div id="earn-list">
                <!-- 动态加载 -->
            </div>
        </div>
    </div>
    
    <!-- 扣取积分页面 -->
    <div class="page" id="deduct-page">
        <div class="content-section">
            <div class="section-title">
                <span>扣取积分</span>
            </div>
            <div id="deduct-list">
                <!-- 动态加载 -->
            </div>
        </div>
    </div>
    
    <!-- 兑换中心页面 -->
    <div class="page" id="exchange-page">
        <div class="content-section">
            <div class="section-title">
                <span>兑换中心</span>
            </div>
            <div id="exchange-list">
                <!-- 动态加载 -->
            </div>
        </div>
    </div>
    
    <!-- 赚取积分项管理页面 -->
    <div class="page" id="earn-manage-page">
        <div class="content-section">
            <div class="section-title">
                <span>赚取积分项管理</span>
                <div class="section-actions">
                    <button class="action-btn add">+ 添加</button>
                </div>
            </div>
            <div id="earn-manage-list">
                <!-- 动态加载 -->
            </div>
        </div>
    </div>
    
    <!-- 扣取积分项管理页面 -->
    <div class="page" id="deduct-manage-page">
        <div class="content-section">
            <div class="section-title">
                <span>扣取积分项管理</span>
                <div class="section-actions">
                    <button class="action-btn add">+ 添加</button>
                </div>
            </div>
            <div id="deduct-manage-list">
                <!-- 动态加载 -->
            </div>
        </div>
    </div>
    
    <!-- 兑换奖励管理页面 -->
    <div class="page" id="exchange-manage-page">
        <div class="content-section">
            <div class="section-title">
                <span>兑换奖励管理</span>
                <div class="section-actions">
                    <button class="action-btn add">+ 添加</button>
                </div>
            </div>
            <div id="reward-manage-list">
                <!-- 动态加载 -->
            </div>
        </div>
    </div>
    
    <!-- 积分记录页面 -->
    <div class="page" id="records-page">
        <div class="content-section">
            <div class="section-title">
                <span id="records-week-score-text">本周积分</span>
                <div class="section-actions">
                    <button class="action-btn add">补积分</button>
                </div>
            </div>
            <div class="week-stats">
                <div class="week-grid" id="records-week-grid">
                    <!-- 动态加载 -->
                </div>
            </div>
        </div>
        
        <div class="content-section">
            <div class="section-title">每日积分记录</div>
            <div class="record-list" id="day-records">
                <!-- 动态加载 -->
            </div>
        </div>
        
        <div class="content-section">
            <div class="section-title">历史积分</div>
            <div id="history-weeks">
                <!-- 动态加载 -->
            </div>
        </div>
    </div>
    
    <!-- 添加赚取积分项弹窗 -->
    <div class="modal" id="add-earn-item-modal">
        <div class="modal-content">
            <div class="modal-title" id="earn-item-modal-title">添加赚取积分项</div>
            <div class="modal-body">
                <div class="form-group">
                    <label class="form-label">项目名称</label>
                    <input type="text" class="form-input" id="earn-item-name" placeholder="例如:完成作业">
                </div>
                <div class="form-group">
                    <label class="form-label">积分数量</label>
                    <input type="number" class="form-input" id="earn-item-points" placeholder="例如:10">
                </div>
            </div>
            <div class="modal-footer">
                <button class="modal-btn cancel">取消</button>
                <button class="modal-btn confirm">保存</button>
            </div>
        </div>
    </div>
    
    <!-- 添加扣取积分项弹窗 -->
    <div class="modal" id="add-deduct-item-modal">
        <div class="modal-content">
            <div class="modal-title" id="deduct-item-modal-title">添加扣取积分项</div>
            <div class="modal-body">
                <div class="form-group">
                    <label class="form-label">项目名称</label>
                    <input type="text" class="form-input" id="deduct-item-name" placeholder="例如:未完成作业">
                </div>
                <div class="form-group">
                    <label class="form-label">积分数量</label>
                    <input type="number" class="form-input" id="deduct-item-points" placeholder="例如:10">
                </div>
            </div>
            <div class="modal-footer">
                <button class="modal-btn cancel">取消</button>
                <button class="modal-btn confirm">保存</button>
            </div>
        </div>
    </div>
    
    <!-- 添加兑换奖励弹窗 -->
    <div class="modal" id="add-reward-modal">
        <div class="modal-content">
            <div class="modal-title" id="reward-modal-title">添加兑换奖励</div>
            <div class="modal-body">
                <div class="form-group">
                    <label class="form-label">奖励名称</label>
                    <input type="text" class="form-input" id="reward-name" placeholder="例如:看电视30分钟">
                </div>
                <div class="form-group">
                    <label class="form-label">所需积分</label>
                    <input type="number" class="form-input" id="reward-points" placeholder="例如:50">
                </div>
            </div>
            <div class="modal-footer">
                <button class="modal-btn cancel">取消</button>
                <button class="modal-btn confirm">保存</button>
            </div>
        </div>
    </div>
    
    <!-- 兑换确认弹窗 -->
    <div class="modal" id="exchange-confirm-modal">
        <div class="modal-content">
            <div class="modal-title">确认兑换</div>
            <div class="modal-body">
                <p id="exchange-reward-name">看电视30分钟</p>
                <p style="color: #667eea; font-weight: 700; font-size: 20px; margin-top: 10px;" id="exchange-reward-points">50积分</p>
            </div>
            <div class="modal-footer">
                <button class="modal-btn cancel">取消</button>
                <button class="modal-btn confirm">确认兑换</button>
            </div>
        </div>
    </div>
    
    <!-- 补积分弹窗 -->
    <div class="modal" id="add-points-modal">
        <div class="modal-content">
            <div class="modal-title">补积分</div>
            <div class="modal-body">
                <div class="form-group">
                    <label class="form-label">补积分原因</label>
                    <input type="text" class="form-input" id="add-points-reason" placeholder="例如:忘记记录的作业完成">
                </div>
                <div class="form-group">
                    <label class="form-label">积分数值</label>
                    <input type="number" class="form-input" id="add-points-value" placeholder="例如:10">
                </div>
                <div class="form-group">
                    <label class="form-label">选择日期</label>
                    <input type="date" class="form-input" id="add-points-date">
                </div>
            </div>
            <div class="modal-footer">
                <button class="modal-btn cancel">取消</button>
                <button class="modal-btn confirm">确认补积分</button>
            </div>
        </div>
    </div>
    
    <!-- 清空积分确认弹窗 -->
    <div class="modal" id="clear-points-modal">
        <div class="modal-content">
            <div class="modal-title">确认清空积分</div>
            <div class="modal-body">
                <p>确定要清空所有积分吗?此操作不可恢复!</p>
            </div>
            <div class="modal-footer">
                <button class="modal-btn cancel">取消</button>
                <button class="modal-btn danger">确认清空</button>
            </div>
        </div>
    </div>
    
    <!-- 删除确认弹窗 -->
    <div class="modal" id="delete-confirm-modal">
        <div class="modal-content">
            <div class="modal-title">确认删除</div>
            <div class="modal-body">
                <p>确定要删除此项目吗?</p>
            </div>
            <div class="modal-footer">
                <button class="modal-btn cancel">取消</button>
                <button class="modal-btn danger">确认删除</button>
            </div>
        </div>
    </div>

    <script>
        // 数据存储键
        const STORAGE_KEYS = {
            TOTAL_POINTS: 'pointsDriver_totalPoints',
            EARN_ITEMS: 'pointsDriver_earnItems',
            DEDUCT_ITEMS: 'pointsDriver_deductItems',
            REWARDS: 'pointsDriver_rewards',
            RECORDS: 'pointsDriver_records',
            RECORD_ID_COUNTER: 'pointsDriver_recordIdCounter'
        };
        
        // 默认数据
        const DEFAULT_EARN_ITEMS = [
            { id: 1, name: '完成作业', points: 10 },
            { id: 2, name: '阅读30分钟', points: 5 },
            { id: 3, name: '做家务', points: 15 },
            { id: 4, name: '锻炼身体', points: 8 },
            { id: 5, name: '早睡早起', points: 5 }
        ];
        
        const DEFAULT_DEDUCT_ITEMS = [
            { id: 1, name: '未完成作业', points: -10 },
            { id: 2, name: '迟到', points: -5 },
            { id: 3, name: '说脏话', points: -8 },
            { id: 4, name: '不整理房间', points: -5 }
        ];
        
        const DEFAULT_REWARDS = [
            { id: 1, name: '看电视30分钟', points: 50 },
            { id: 2, name: '玩游戏1小时', points: 100 },
            { id: 3, name: '买零食', points: 30 },
            { id: 4, name: '周末外出', points: 200 }
        ];
        
        // 全局数据
        let totalPoints = 0;
        let earnItems = [];
        let deductItems = [];
        let rewards = [];
        let records = [];
        let recordIdCounter = 0;
        
        // 当前操作项
        let currentEditItem = null;
        let currentDeleteItem = null;
        let currentDeleteType = '';
        let currentExchangeReward = null;
        let selectedDate = null;
        let displayYear = null;
        let displayMonth = null;
        
        // 初始化数据
        function initData() {
            totalPoints = parseInt(localStorage.getItem(STORAGE_KEYS.TOTAL_POINTS)) || 0;
            earnItems = JSON.parse(localStorage.getItem(STORAGE_KEYS.EARN_ITEMS)) || JSON.parse(JSON.stringify(DEFAULT_EARN_ITEMS));
            deductItems = JSON.parse(localStorage.getItem(STORAGE_KEYS.DEDUCT_ITEMS)) || JSON.parse(JSON.stringify(DEFAULT_DEDUCT_ITEMS));
            rewards = JSON.parse(localStorage.getItem(STORAGE_KEYS.REWARDS)) || JSON.parse(JSON.stringify(DEFAULT_REWARDS));
            records = JSON.parse(localStorage.getItem(STORAGE_KEYS.RECORDS)) || [];
            recordIdCounter = parseInt(localStorage.getItem(STORAGE_KEYS.RECORD_ID_COUNTER)) || 0;
        }
        
        // 保存数据
        function saveData() {
            localStorage.setItem(STORAGE_KEYS.TOTAL_POINTS, totalPoints);
            localStorage.setItem(STORAGE_KEYS.EARN_ITEMS, JSON.stringify(earnItems));
            localStorage.setItem(STORAGE_KEYS.DEDUCT_ITEMS, JSON.stringify(deductItems));
            localStorage.setItem(STORAGE_KEYS.REWARDS, JSON.stringify(rewards));
            localStorage.setItem(STORAGE_KEYS.RECORDS, JSON.stringify(records));
            localStorage.setItem(STORAGE_KEYS.RECORD_ID_COUNTER, recordIdCounter);
        }
        
        // 更新积分显示
        function updatePointsDisplay() {
            document.getElementById('total-points').textContent = totalPoints.toLocaleString();
        }
        
        // 页面切换
        function switchPage(pageName) {
            // 隐藏所有页面
            document.querySelectorAll('.page').forEach(page => {
                page.classList.remove('active');
            });
            
            // 显示目标页面
            const targetPage = document.getElementById(pageName + '-page');
            if (targetPage) {
                targetPage.classList.add('active');
            }
            
            // 更新底部导航
            document.querySelectorAll('.nav-item').forEach(item => {
                item.classList.remove('active');
            });
            
            // 根据页面名称激活对应导航
            const navMap = { 'home': 0 };
            
            const navItems = document.querySelectorAll('.nav-item');
            if (navMap[pageName] !== undefined) {
                navItems[navMap[pageName]].classList.add('active');
            }
            
            // 加载页面数据
            if (pageName === 'home') {
                loadHomeData();
            } else if (pageName === 'earn') {
                loadEarnList();
            } else if (pageName === 'deduct') {
                loadDeductList();
            } else if (pageName === 'exchange') {
                loadExchangeList();
            } else if (pageName === 'earn-manage') {
                loadEarnManageList();
            } else if (pageName === 'deduct-manage') {
                loadDeductManageList();
            } else if (pageName === 'exchange-manage') {
                loadRewardManageList();
            } else if (pageName === 'records') {
                loadRecordsData();
            }
        }
        
        // 更新当天积分显示
        function updateTodayPointsDisplay() {
            const today = formatDate(new Date());
            const dayRecords = records.filter(r => r.date === today);
            const earnPoints = dayRecords.filter(r => r.type === 'income').reduce((sum, r) => sum + r.amount, 0);
            const deductPoints = Math.abs(dayRecords.filter(r => r.type === 'expense').reduce((sum, r) => sum + r.amount, 0));
            const netPoints = earnPoints - deductPoints;
            
            document.getElementById('daily-challenge').textContent = `赚${earnPoints}分 - 扣${deductPoints}分 = ${netPoints}分`;
        }
        
        // 加载首页数据
        function loadHomeData() {
            updatePointsDisplay();
            updateTodayPointsDisplay();
            loadCurrentWeekGrid('current-week-grid', 'week-score-text');
        }
        
        // 加载赚取积分列表
        function loadEarnList() {
            const listContainer = document.getElementById('earn-list');
            let html = `
                <div class="quick-add">
                    <input class="qa-name" id="quick-earn-name" placeholder="名称(留空则用日期)">
                    <input class="qa-points" id="quick-earn-points" type="number" placeholder="积分">
                    <button class="qa-btn">赚取</button>
                </div>
            `;
            if (earnItems.length === 0) {
                html += `
                    <div class="empty-state">
                        <div class="empty-icon">&#128176;</div>
                        <div class="empty-text">暂无赚取积分项</div>
                    </div>
                `;
            } else {
                html += earnItems.map(item => `
                    <div class="list-item">
                        <div class="item-info">
                            <div class="item-name">${item.name}</div>
                            <div class="item-points income">+${item.points}积分</div>
                        </div>
                        <button class="item-btn earn">赚取</button>
                    </div>
                `).join('');
            }
            listContainer.innerHTML = html;
        }
        
        // 加载扣取积分列表
        function loadDeductList() {
            const listContainer = document.getElementById('deduct-list');
            let html = `
                <div class="quick-add deduct">
                    <input class="qa-name" id="quick-deduct-name" placeholder="名称(留空则用日期)">
                    <input class="qa-points" id="quick-deduct-points" type="number" placeholder="积分">
                    <button class="qa-btn">扣取</button>
                </div>
            `;
            if (deductItems.length === 0) {
                html += `
                    <div class="empty-state">
                        <div class="empty-icon">&#9888;&#65039;</div>
                        <div class="empty-text">暂无扣取积分项</div>
                    </div>
                `;
            } else {
                html += deductItems.map(item => `
                    <div class="list-item">
                        <div class="item-info">
                            <div class="item-name">${item.name}</div>
                            <div class="item-points expense">${item.points}积分</div>
                        </div>
                        <button class="item-btn deduct">扣取</button>
                    </div>
                `).join('');
            }
            listContainer.innerHTML = html;
        }
        
        // 加载兑换列表
        function loadExchangeList() {
            const listContainer = document.getElementById('exchange-list');
            let html = `
                <div class="quick-add exchange">
                    <input class="qa-name" id="quick-exchange-name" placeholder="名称(留空则用日期)">
                    <input class="qa-points" id="quick-exchange-points" type="number" placeholder="积分">
                    <button class="qa-btn">兑换</button>
                </div>
            `;
            if (rewards.length === 0) {
                html += `
                    <div class="empty-state">
                        <div class="empty-icon">&#127873;</div>
                        <div class="empty-text">暂无兑换奖励</div>
                    </div>
                `;
            } else {
                html += rewards.map(reward => `
                    <div class="list-item">
                        <div class="item-info">
                            <div class="item-name">${reward.name}</div>
                            <div class="item-points">${reward.points}积分</div>
                        </div>
                        <button class="item-btn exchange">兑换</button>
                    </div>
            `).join('');
            }
            listContainer.innerHTML = html;
        }
        
        // 加载赚取积分项管理列表
        function loadEarnManageList() {
            const listContainer = document.getElementById('earn-manage-list');
            if (earnItems.length === 0) {
                listContainer.innerHTML = `
                    <div class="empty-state">
                        <div class="empty-icon">&#128176;</div>
                        <div class="empty-text">暂无赚取积分项</div>
                    </div>
                `;
                return;
            }
            
            listContainer.innerHTML = earnItems.map(item => `
                <div class="list-item">
                    <div class="item-info">
                        <div class="item-name">${item.name}</div>
                        <div class="item-points income">+${item.points}积分</div>
                    </div>
                    <div class="item-actions">
                        <button class="action-btn edit">编辑</button>
                        <button class="action-btn delete">删除</button>
                    </div>
                </div>
            `).join('');
        }
        
        // 加载扣取积分项管理列表
        function loadDeductManageList() {
            const listContainer = document.getElementById('deduct-manage-list');
            if (deductItems.length === 0) {
                listContainer.innerHTML = `
                    <div class="empty-state">
                        <div class="empty-icon">&#9888;&#65039;</div>
                        <div class="empty-text">暂无扣取积分项</div>
                    </div>
                `;
                return;
            }
            
            listContainer.innerHTML = deductItems.map(item => `
                <div class="list-item">
                    <div class="item-info">
                        <div class="item-name">${item.name}</div>
                        <div class="item-points expense">${item.points}积分</div>
                    </div>
                    <div class="item-actions">
                        <button class="action-btn edit">编辑</button>
                        <button class="action-btn delete">删除</button>
                    </div>
                </div>
            `).join('');
        }
        
        // 加载奖励管理列表
        function loadRewardManageList() {
            const listContainer = document.getElementById('reward-manage-list');
            if (rewards.length === 0) {
                listContainer.innerHTML = `
                    <div class="empty-state">
                        <div class="empty-icon">&#127873;</div>
                        <div class="empty-text">暂无兑换奖励</div>
                    </div>
                `;
                return;
            }
            
            listContainer.innerHTML = rewards.map(reward => `
                <div class="list-item">
                    <div class="item-info">
                        <div class="item-name">${reward.name}</div>
                        <div class="item-points">${reward.points}积分</div>
                    </div>
                    <div class="item-actions">
                        <button class="action-btn edit">编辑</button>
                        <button class="action-btn delete">删除</button>
                    </div>
                </div>
            `).join('');
        }
        
        // 加载积分记录数据
        function loadRecordsData() {
            // 如果没有选中日期,默认选中当天
            if (!selectedDate) {
                selectedDate = formatDate(new Date());
            }
            loadCurrentWeekGrid('records-week-grid', 'records-week-score-text');
            loadDayRecords();
            loadHistoryWeeks();
        }
        
        // 加载当前周积分网格
        function loadCurrentWeekGrid(gridId, titleId) {
            const grid = document.getElementById(gridId);
            
            const now = new Date();
            const currentDay = now.getDay();
            const weekStart = new Date(now);
            weekStart.setDate(now.getDate() - (currentDay === 0 ? 6 : currentDay - 1)); // 周一
            
            let weekTotal = 0;
            const dayNames = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
            
            let cellsHtml = '';
            dayNames.forEach((dayName, index) => {
                const date = new Date(weekStart);
                date.setDate(weekStart.getDate() + index);
                const dateStr = formatDate(date);
                
                const dayRecords = records.filter(r => r.date === dateStr);
                const dayTotal = dayRecords.reduce((sum, r) => sum + r.amount, 0);
                weekTotal += dayTotal;
                
                const isToday = date.toDateString() === now.toDateString();
                const isSelected = selectedDate === dateStr;
                
                let pointsClass = '';
                if (isToday) {
                    pointsClass = 'today-points';
                } else if (isSelected) {
                    pointsClass = 'selected-points';
                }
                
                cellsHtml += `
                    <div class="day-item ${isToday ? 'today' : ''} ${isSelected ? 'selected' : ''}">
                        <div class="day-name">${dayName}</div>
                        <div class="day-points ${pointsClass}">${dayTotal > 0 ? '+' : ''}${dayTotal}</div>
                    </div>
                `;
            });
            grid.innerHTML = cellsHtml;
            
            // 更新本周积分标题
            const scoreEl = document.getElementById(titleId);
            if (scoreEl) {
                const sign = weekTotal >= 0 ? '+' : '';
                scoreEl.textContent = `本周积分 (${sign}${weekTotal})`;
            }
        }
        
        // 切换到记录页面并显示当天详情
        function switchToDayRecords(dateStr) {
            selectedDate = dateStr;
            switchPage('records');
            loadDayRecords();
            // 重新加载周积分网格,以更新选中状态
            loadCurrentWeekGrid('records-week-grid', 'records-week-score-text');
        }
        
        // 加载每日积分记录
        function loadDayRecords() {
            const container = document.getElementById('day-records');
            
            if (selectedDate) {
                const dayRecords = records.filter(r => r.date === selectedDate);
                if (dayRecords.length === 0) {
                    container.innerHTML = `
                        <div class="empty-state">
                            <div class="empty-icon">&#128202;</div>
                            <div class="empty-text">该日期暂无积分记录</div>
                        </div>
                    `;
                } else {
                    container.innerHTML = dayRecords.map(record => `
                        <div class="record-item">
                            <div class="record-info">
                                <div class="record-title">${record.title}</div>
                                <div class="record-time">${record.time}</div>
                            </div>
                            <div class="record-amount ${record.type}">${record.type === 'income' ? '+' : ''}${record.amount}</div>
                            <button class="action-btn delete" style="font-size:10px;padding:3px 8px;flex-shrink:0;">撤销</button>
                        </div>
                    `).join('');
                }
            } else {
                container.innerHTML = `
                    <div class="empty-state">
                        <div class="empty-icon">&#128197;</div>
                        <div class="empty-text">点击上方某天查看详细记录</div>
                    </div>
                `;
            }
        }
        
        // 加载历史积分(月日历 + 年历)
        function loadHistoryWeeks() {
            const container = document.getElementById('history-weeks');
            const now = new Date();
            const curYear = now.getFullYear();
            const curMonth = now.getMonth();
            const weekdayNames = ['一', '二', '三', '四', '五', '六', '日'];
            const monthNames = ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'];
            
            // 确定显示的月份
            if (displayYear === null) displayYear = curYear;
            if (displayMonth === null) displayMonth = curMonth;
            const dYear = displayYear;
            const dMonth = displayMonth;
            
            // 年度总积分
            const yearStart = formatDate(new Date(dYear, 0, 1));
            const yearEnd = formatDate(new Date(dYear, 11, 31));
            const yearRecords = records.filter(r => r.date >= yearStart && r.date <= yearEnd);
            const yearTotal = yearRecords.reduce((sum, r) => sum + r.amount, 0);
            const ySign = yearTotal > 0 ? '+' : '';
            
            // 当月月历
            const daysInMonth = new Date(dYear, dMonth + 1, 0).getDate();
            const monthStart = formatDate(new Date(dYear, dMonth, 1));
            const monthEnd = formatDate(new Date(dYear, dMonth, daysInMonth));
            const monthRecords = records.filter(r => r.date >= monthStart && r.date <= monthEnd);
            const monthTotal = monthRecords.reduce((sum, r) => sum + r.amount, 0);
            const totalSign = monthTotal > 0 ? '+' : '';
            const firstDay = new Date(dYear, dMonth, 1).getDay();
            const startPadding = firstDay === 0 ? 6 : firstDay - 1;
            
            let html = `<div class="month-calendar">
                <div class="month-header">
                    <div class="month-title">${dYear}年${dMonth + 1}月 (${totalSign}${monthTotal})</div>
                </div>
                <div class="month-weekdays">${weekdayNames.map(w => `<div class="month-weekday">${w}</div>`).join('')}</div>
                <div class="month-days">`;
            
            for (let p = 0; p < startPadding; p++) {
                html += `<div class="month-day empty"></div>`;
            }
            
            for (let d = 1; d <= daysInMonth; d++) {
                const dateStr = formatDate(new Date(dYear, dMonth, d));
                const dayRecords = records.filter(r => r.date === dateStr);
                const dayTotal = dayRecords.reduce((sum, r) => sum + r.amount, 0);
                const ptsStr = dayTotal !== 0 ? ((dayTotal > 0 ? '+' : '') + dayTotal) : '';
                const isToday = dateStr === formatDate(now) ? ' today' : '';
                html += `<div class="month-day${isToday}">
                    <div class="month-day-num">${d}</div>
                    <div class="month-day-pts">${ptsStr}</div>
                </div>`;
            }
            
            html += `</div></div>`;
            
            // 年历
            html += `<div class="section-title">${dYear}年总积分 (${ySign}${yearTotal})</div>`;
            
            // 年历 6×2 宫格
            html += `<div class="year-calendar">`;
            for (let m = 0; m < 12; m++) {
                const mStart = formatDate(new Date(dYear, m, 1));
                const mEnd = formatDate(new Date(dYear, m, new Date(dYear, m + 1, 0).getDate()));
                const mRecords = records.filter(r => r.date >= mStart && r.date <= mEnd);
                const mTotal = mRecords.reduce((sum, r) => sum + r.amount, 0);
                const mSign = mTotal > 0 ? '+' : '';
                const isCur = (dYear === curYear && m === curMonth) ? ' current' : '';
                html += `<div class="year-month-card${isCur}">
                    <div class="year-month-name">${monthNames[m]}</div>
                    <div class="year-month-total">${mSign}${mTotal}</div>
                </div>`;
            }
            html += `</div>`;
            
            container.innerHTML = html;
        }
        
        // 点击年历卡片切换月日历
        function switchMonthCalendar(month) {
            displayYear = displayYear !== null ? displayYear : new Date().getFullYear();
            displayMonth = month;
            loadHistoryWeeks();
        }
        
        // 格式化日期
        function formatDate(date) {
            const year = date.getFullYear();
            const month = String(date.getMonth() + 1).padStart(2, '0');
            const day = String(date.getDate()).padStart(2, '0');
            return `${year}-${month}-${day}`;
        }
        
        // 赚取积分
        // 快速赚取积分(自定义填入)
        function quickEarn() {
            const nameEl = document.getElementById('quick-earn-name');
            const pointsEl = document.getElementById('quick-earn-points');
            const name = nameEl.value.trim() || formatDate(new Date());
            const points = parseInt(pointsEl.value);
            if (!points || points <= 0) { showAlert('请输入有效积分'); return; }
            totalPoints += points;
            addRecord(name, points, 'income');
            nameEl.value = '';
            pointsEl.value = '';
            updatePointsDisplay();
            updateTodayPointsDisplay();
            saveData();
            showAlert(`赚取 +${points} 积分`);
        }
        
        // 快速扣取积分(自定义填入)
        function quickDeduct() {
            const nameEl = document.getElementById('quick-deduct-name');
            const pointsEl = document.getElementById('quick-deduct-points');
            const name = nameEl.value.trim() || formatDate(new Date());
            const points = parseInt(pointsEl.value);
            if (!points || points <= 0) { showAlert('请输入有效积分'); return; }
            totalPoints -= points;
            addRecord(name, -points, 'expense');
            nameEl.value = '';
            pointsEl.value = '';
            updatePointsDisplay();
            updateTodayPointsDisplay();
            saveData();
            showAlert(`扣取 -${points} 积分`);
        }
        
        // 快速兑换(自定义填入)
        function quickExchange() {
            const nameEl = document.getElementById('quick-exchange-name');
            const pointsEl = document.getElementById('quick-exchange-points');
            const name = nameEl.value.trim() || formatDate(new Date());
            const points = parseInt(pointsEl.value);
            if (!points || points <= 0) { showAlert('请输入有效积分'); return; }
            if (totalPoints < points) { showAlert('积分不足'); return; }
            totalPoints -= points;
            addRecord(name, -points, 'expense');
            nameEl.value = '';
            pointsEl.value = '';
            updatePointsDisplay();
            updateTodayPointsDisplay();
            saveData();
            showAlert(`兑换成功!消耗 ${points} 积分`);
        }
        
        function earnPoints(itemId) {
            const item = earnItems.find(i => i.id === itemId);
            if (item) {
                totalPoints += item.points;
                addRecord(item.name, item.points, 'income');
                updatePointsDisplay();
                updateTodayPointsDisplay();
                saveData();
                showAlert(`成功赚取${item.points}积分!`);
            }
        }
        
        // 显示自定义提示弹窗
        function showAlert(message) {
            const modal = document.createElement('div');
            modal.className = 'modal show';
            modal.innerHTML = `
                <div class="modal-content">
                    <div class="modal-title">提示</div>
                    <div class="modal-body">
                        <p>${message}</p>
                    </div>
                    <div class="modal-footer">
                        <button class="modal-btn confirm">确定</button>
                    </div>
                </div>
            `;
            document.body.appendChild(modal);
            
            // 点击弹窗外部关闭
            modal.addEventListener('click', function(e) {
                if (e.target === this) {
                    this.remove();
                }
            });
        }
        
        // 扣取积分
        function deductPoints(itemId) {
            const item = deductItems.find(i => i.id === itemId);
            if (item) {
                totalPoints += item.points;
                addRecord(item.name, item.points, 'expense');
                updatePointsDisplay();
                updateTodayPointsDisplay();
                saveData();
                showAlert(`成功扣取${Math.abs(item.points)}积分!`);
            }
        }
        
        // 添加积分记录
        function addRecord(title, amount, type, date = null, timeStr = null) {
            const now = new Date();
            const recordDate = date ? new Date(date) : now;
            recordIdCounter++;
            records.unshift({
                id: recordIdCounter,
                title: title,
                amount: amount,
                type: type,
                date: formatDate(recordDate),
                time: timeStr || now.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
            });
        }
        

        
        // 显示添加赚取积分项弹窗
        function showAddEarnItemModal() {
            currentEditItem = null;
            document.getElementById('earn-item-modal-title').textContent = '添加赚取积分项';
            document.getElementById('earn-item-name').value = '';
            document.getElementById('earn-item-points').value = '';
            document.getElementById('add-earn-item-modal').classList.add('show');
        }
        
        // 编辑赚取积分项
        function editEarnItem(itemId) {
            const item = earnItems.find(i => i.id === itemId);
            if (item) {
                currentEditItem = item;
                document.getElementById('earn-item-modal-title').textContent = '编辑赚取积分项';
                document.getElementById('earn-item-name').value = item.name;
                document.getElementById('earn-item-points').value = item.points;
                document.getElementById('add-earn-item-modal').classList.add('show');
            }
        }
        
        // 保存赚取积分项
        function saveEarnItem() {
            const name = document.getElementById('earn-item-name').value.trim();
            const points = parseInt(document.getElementById('earn-item-points').value);
            
            if (!name || isNaN(points)) {
                showAlert('请填写完整信息');
                return;
            }
            
            if (currentEditItem) {
                // 编辑
                currentEditItem.name = name;
                currentEditItem.points = points;
            } else {
                // 添加
                const newId = earnItems.length > 0 ? Math.max(...earnItems.map(i => i.id)) + 1 : 1;
                earnItems.push({ id: newId, name: name, points: points });
            }
            
            saveData();
            loadEarnManageList();
            closeModal('add-earn-item-modal');
        }
        
        // 删除赚取积分项
        function deleteEarnItem(itemId) {
            currentDeleteItem = itemId;
            currentDeleteType = 'earn';
            document.getElementById('delete-confirm-modal').classList.add('show');
        }
        
        // 显示添加扣取积分项弹窗
        function showAddDeductItemModal() {
            currentEditItem = null;
            document.getElementById('deduct-item-modal-title').textContent = '添加扣取积分项';
            document.getElementById('deduct-item-name').value = '';
            document.getElementById('deduct-item-points').value = '';
            document.getElementById('add-deduct-item-modal').classList.add('show');
        }
        
        // 编辑扣取积分项
        function editDeductItem(itemId) {
            const item = deductItems.find(i => i.id === itemId);
            if (item) {
                currentEditItem = item;
                document.getElementById('deduct-item-modal-title').textContent = '编辑扣取积分项';
                document.getElementById('deduct-item-name').value = item.name;
                document.getElementById('deduct-item-points').value = Math.abs(item.points);
                document.getElementById('add-deduct-item-modal').classList.add('show');
            }
        }
        
        // 保存扣取积分项
        function saveDeductItem() {
            const name = document.getElementById('deduct-item-name').value.trim();
            const points = parseInt(document.getElementById('deduct-item-points').value);
            
            if (!name || isNaN(points)) {
                showAlert('请填写完整信息');
                return;
            }
            
            if (currentEditItem) {
                // 编辑
                currentEditItem.name = name;
                currentEditItem.points = -points;
            } else {
                // 添加
                const newId = deductItems.length > 0 ? Math.max(...deductItems.map(i => i.id)) + 1 : 1;
                deductItems.push({ id: newId, name: name, points: -points });
            }
            
            saveData();
            loadDeductManageList();
            closeModal('add-deduct-item-modal');
        }
        
        // 删除扣取积分项
        function deleteDeductItem(itemId) {
            currentDeleteItem = itemId;
            currentDeleteType = 'deduct';
            document.getElementById('delete-confirm-modal').classList.add('show');
        }
        
        // 显示添加奖励弹窗
        function showAddRewardModal() {
            currentEditItem = null;
            document.getElementById('reward-modal-title').textContent = '添加兑换奖励';
            document.getElementById('reward-name').value = '';
            document.getElementById('reward-points').value = '';
            document.getElementById('add-reward-modal').classList.add('show');
        }
        
        // 编辑奖励
        function editReward(rewardId) {
            const reward = rewards.find(r => r.id === rewardId);
            if (reward) {
                currentEditItem = reward;
                document.getElementById('reward-modal-title').textContent = '编辑兑换奖励';
                document.getElementById('reward-name').value = reward.name;
                document.getElementById('reward-points').value = reward.points;
                document.getElementById('add-reward-modal').classList.add('show');
            }
        }
        
        // 保存奖励
        function saveReward() {
            const name = document.getElementById('reward-name').value.trim();
            const points = parseInt(document.getElementById('reward-points').value);
            
            if (!name || isNaN(points)) {
                showAlert('请填写完整信息');
                return;
            }
            
            if (currentEditItem) {
                // 编辑
                currentEditItem.name = name;
                currentEditItem.points = points;
            } else {
                // 添加
                const newId = rewards.length > 0 ? Math.max(...rewards.map(r => r.id)) + 1 : 1;
                rewards.push({ id: newId, name: name, points: points });
            }
            
            saveData();
            loadRewardManageList();
            closeModal('add-reward-modal');
        }
        
        // 删除奖励
        function deleteReward(rewardId) {
            currentDeleteItem = rewardId;
            currentDeleteType = 'reward';
            document.getElementById('delete-confirm-modal').classList.add('show');
        }
        
        // 显示兑换弹窗
        function showExchangeModal(rewardId) {
            const reward = rewards.find(r => r.id === rewardId);
            if (reward) {
                currentExchangeReward = reward;
                document.getElementById('exchange-reward-name').textContent = reward.name;
                document.getElementById('exchange-reward-points').textContent = reward.points + '积分';
                document.getElementById('exchange-confirm-modal').classList.add('show');
            }
        }
        
        // 确认兑换
        function confirmExchange() {
            if (currentExchangeReward && totalPoints >= currentExchangeReward.points) {
                totalPoints -= currentExchangeReward.points;
                addRecord('兑换:' + currentExchangeReward.name, -currentExchangeReward.points, 'expense');
                updatePointsDisplay();
                updateTodayPointsDisplay();
                saveData();
                closeModal('exchange-confirm-modal');
                showAlert('兑换成功!');
            } else {
                closeModal('exchange-confirm-modal');
                showAlert('积分不足!');
            }
        }
        
        // 显示补积分弹窗
        function showAddPointsModal() {
            // 设置默认日期为今天
            const today = new Date();
            const formattedDate = today.toISOString().split('T')[0];
            document.getElementById('add-points-date').value = formattedDate;
            document.getElementById('add-points-reason').value = '';
            document.getElementById('add-points-value').value = '';
            document.getElementById('add-points-modal').classList.add('show');
        }
        
        // 补积分
        function addPoints() {
            const reason = document.getElementById('add-points-reason').value.trim();
            const value = parseInt(document.getElementById('add-points-value').value);
            const dateStr = document.getElementById('add-points-date').value;
            
            if (!reason || isNaN(value) || !dateStr) {
                showAlert('请填写完整信息');
                return;
            }
            
            // 添加积分记录
            totalPoints += value;
            const recordTime = new Date(dateStr + 'T12:00:00').toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
            addRecord('补积分:' + reason, value, 'income', dateStr, recordTime);
            updatePointsDisplay();
            updateTodayPointsDisplay();
            saveData();
            
            // 关闭弹窗
            closeModal('add-points-modal');
            
            // 重新加载记录数据
            loadRecordsData();
            
            showAlert('补积分成功!');
        }
        
        // 显示清空积分弹窗
        function showClearPointsModal() {
            document.getElementById('clear-points-modal').classList.add('show');
        }
        
        // 确认清空积分
        function confirmClearPoints() {
            totalPoints = 0;
            records = [];
            recordIdCounter = 0;
            updatePointsDisplay();
            updateTodayPointsDisplay();
            saveData();
            closeModal('clear-points-modal');
            loadCurrentPageData();
            showAlert('积分已清空!');
        }
        
        // 系统重置
        function systemReset() {
            if (!confirm('确定要系统重置吗?\n\n将清空所有积分、记录,恢复默认设置项。\n此操作不可恢复!')) return;
            totalPoints = 0;
            records = [];
            recordIdCounter = 0;
            earnItems = JSON.parse(JSON.stringify(DEFAULT_EARN_ITEMS));
            deductItems = JSON.parse(JSON.stringify(DEFAULT_DEDUCT_ITEMS));
            rewards = JSON.parse(JSON.stringify(DEFAULT_REWARDS));
            saveData();
            updatePointsDisplay();
            updateTodayPointsDisplay();
            closeModal('clear-points-modal');
            loadCurrentPageData();
            showAlert('系统已重置为默认状态');
        }
        
        // 确认删除
        function confirmDelete() {
            if (currentDeleteType === 'earn') {
                earnItems = earnItems.filter(i => i.id !== currentDeleteItem);
                loadEarnManageList();
            } else if (currentDeleteType === 'deduct') {
                deductItems = deductItems.filter(i => i.id !== currentDeleteItem);
                loadDeductManageList();
            } else if (currentDeleteType === 'reward') {
                rewards = rewards.filter(r => r.id !== currentDeleteItem);
                loadRewardManageList();
            }
            
            saveData();
            closeModal('delete-confirm-modal');
        }
        
        // 撤销记录
        function undoRecord(recordId) {
            const idx = records.findIndex(r => r.id === recordId);
            if (idx !== -1) {
                totalPoints -= records[idx].amount;
                records.splice(idx, 1);
                updatePointsDisplay();
                updateTodayPointsDisplay();
                saveData();
                loadDayRecords();
                if (document.getElementById('records-page').classList.contains('active')) {
                    loadCurrentWeekGrid('records-week-grid', 'records-week-score-text');
                    loadHistoryWeeks();
                }
            }
        }
        
        // 关闭弹窗
        function closeModal(modalId) {
            document.getElementById(modalId).classList.remove('show');
        }
        
        // 重载当前活动页面数据
        function loadCurrentPageData() {
            if (document.getElementById('home-page').classList.contains('active')) {
                loadHomeData();
            } else if (document.getElementById('records-page').classList.contains('active')) {
                loadRecordsData();
            }
        }
        
        // 点击弹窗外部关闭
        document.querySelectorAll('.modal').forEach(modal => {
            modal.addEventListener('click', function(e) {
                if (e.target === this) {
                    this.classList.remove('show');
                }
            });
        });
        
        // 初始化
        document.addEventListener('DOMContentLoaded', function() {
            initData();
            loadHomeData();
        });
    </script>


</body>
</html>


积分小管家20260612.txt

74.51 KB, 下载次数: 52, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 4吾爱币 +10 热心值 +3 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
weidechan + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
grrr_zhao + 1 + 1 谢谢@Thanks!
抱薪风雪雾 + 1 + 1 谢谢@Thanks!

查看全部评分

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

墨羽风 发表于 2026-6-16 19:04
用扣子编程ai生成一个网页端零基础不需要搭建网站给你提供网址比你写的会更好
家长端 (/parent/*)
邮箱注册 / 登录,自动生成 6 位家庭码
创建 / 管理好习惯任务(学习、家务、运动、早睡等分类,自定义积分奖励)
审核孩子提交的任务(通过 / 拒绝),通过自动发放积分
添加孩子账户(设置昵称和 PIN 码)
成长数据统计图表(任务完成趋势、积分增长曲线)
孩子端 (/child/*)
通过家庭码 + PIN 码快捷登录
查看可用任务,提交完成打卡
领养虚拟宠物(小猫 / 小狗 / 小兔子),喂食 / 洗澡 / 互动玩耍
宠物升级系统:经验值升级,解锁装扮(皇冠、蝴蝶结、魔法帽等)和小屋背景(花园、海滩、太空等)
积分商城:用积分购买装扮和背景
积分收支明细
周 / 月积分排行榜
skzhaixing 发表于 2026-6-16 20:18
本帖最后由 skzhaixing 于 2026-6-16 21:05 编辑

[HTML] 纯文本查看 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta name="robots" content="noindex,nofollow">
    <meta name="generator" content="ShipPage">
    <link rel="canonical" href="https://shippage.ai/p/jifen">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
    <title>积分小管家 · 未来科技旗舰版</title>
    <style>
        :root {
            --bg-deep: #05060f;
            --bg-card: rgba(14, 16, 28, 0.75);
            --bg-card-hover: rgba(20, 22, 38, 0.85);
            --border-glow: rgba(0, 229, 255, 0.35);
            --cyan: #00e5ff;
            --cyan-glow: #00f0ff;
            --neon-green: #00ff88;
            --magenta: #ff2d95;
            --purple: #b44dff;
            --gold: #ffcc00;
            --text-primary: #e0e6f0;
            --text-secondary: #8899bb;
            --text-dim: #556688;
            --radius-lg: 18px;
            --radius-md: 12px;
            --radius-sm: 8px;
            --font-mono: 'SF Mono', 'Cascadia Code', 'Consolas', 'Monaco', monospace;
        }
        *{margin:0;padding:0;box-sizing:border-box;}
        body{
            font-family: -apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;
            background:var(--bg-deep); min-height:100vh; color:var(--text-primary);
            padding-bottom:85px; overflow-x:hidden; -webkit-tap-highlight-color:transparent;
            -webkit-font-smoothing:antialiased; position:relative;
        }
        #particles-canvas{position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:0;}
        body::before{
            content:''; position:fixed; top:0;left:0;width:100%;height:100%; pointer-events:none;z-index:0;
            background: linear-gradient(rgba(0,229,255,0.025) 1px,transparent 1px),
                        linear-gradient(90deg, rgba(0,229,255,0.025) 1px,transparent 1px);
            background-size:40px 40px; animation:gridShift 12s linear infinite;
        }
        @keyframes gridShift{0%,100%{background-position:0 0,0 0;}50%{background-position:20px 20px,20px 20px;}}
        body::after{
            content:''; position:fixed; top:0;left:0;width:100%;height:100%; pointer-events:none;z-index:1;
            background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,0.015) 2px,rgba(0,0,0,0.015) 4px);
            animation:scanLines 8s linear infinite;
        }
        @keyframes scanLines{0%{background-position:0 0;}100%{background-position:0 100px;}}
        .header{
            background:rgba(10,12,22,0.8); backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
            padding:14px 20px; position:sticky; top:0; z-index:100;
            border-bottom:1px solid rgba(0,229,255,0.2); box-shadow:0 2px 30px rgba(0,0,0,0.5),0 0 60px rgba(0,229,255,0.06);
        }
        .header h1{
            font-size:20px; font-weight:800; letter-spacing:3px; text-align:center;
            background:linear-gradient(135deg,var(--cyan),var(--purple),var(--cyan)); background-size:200% 200%;
            -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent;
            animation:gradientFlow 4s ease infinite; filter:drop-shadow(0 0 12px rgba(0,229,255,0.4));
        }
        @keyframes gradientFlow{0%,100%{background-position:0% 50%;}50%{background-position:100% 100%;}}
        .points-card{
            background:linear-gradient(160deg,rgba(14,18,32,0.85),rgba(10,14,26,0.9),rgba(16,20,36,0.8));
            margin:18px 16px; padding:26px 20px 22px; border-radius:var(--radius-lg); color:white;
            border:1px solid rgba(0,229,255,0.3);
            box-shadow:0 0 30px rgba(0,229,255,0.2),0 0 60px rgba(0,229,255,0.08),inset 0 0 30px rgba(0,229,255,0.03);
            text-align:center; position:relative; overflow:hidden; z-index:2; animation:cardPulse 4s ease-in-out infinite;
        }
        @keyframes cardPulse{0%,100%{box-shadow:0 0 30px rgba(0,229,255,0.2);}50%{box-shadow:0 0 45px rgba(0,229,255,0.4);}}
        .points-card::before{
            content:''; position:absolute; top:8px; left:8px; width:20px; height:20px;
            border-top:2px solid var(--cyan); border-left:2px solid var(--cyan); border-radius:4px 0 0 0; opacity:0.7;
            animation:cornerGlow 2s ease-in-out infinite;
        }
        .points-card::after{
            content:''; position:absolute; bottom:8px; right:8px; width:20px; height:20px;
            border-bottom:2px solid var(--cyan); border-right:2px solid var(--cyan); border-radius:0 0 4px 0; opacity:0.7;
            animation:cornerGlow 2s ease-in-out infinite 0.5s;
        }
        @keyframes cornerGlow{0%,100%{opacity:0.4;}50%{opacity:1;}}
        .points-header{display:flex; flex-direction:column; align-items:center; gap:4px; margin-bottom:6px;}
        .points-title{font-size:13px; font-weight:600; letter-spacing:4px; text-transform:uppercase; color:rgba(0,229,255,0.7); font-family:var(--font-mono);}
        .points-amount{
            font-size:62px; font-weight:900; font-family:var(--font-mono); letter-spacing:3px; color:#fff;
            text-shadow:0 0 20px rgba(0,229,255,0.7),0 0 40px rgba(0,229,255,0.4),0 0 80px rgba(0,229,255,0.25),0 0 120px rgba(180,77,255,0.3);
            animation:numberGlow 3s ease-in-out infinite; line-height:1;
        }
        @keyframes numberGlow{0%,100%{text-shadow:0 0 20px rgba(0,229,255,0.7);}50%{text-shadow:0 0 30px rgba(0,240,255,0.9),0 0 60px rgba(0,229,255,0.55);}}
        .points-today{
            display:flex; align-items:center; justify-content:center; gap:10px; font-size:12px;
            background:rgba(0,229,255,0.08); border:1px solid rgba(0,229,255,0.2); border-radius:20px;
            padding:7px 16px; margin:10px auto 0; width:fit-content; font-family:var(--font-mono);
            color:rgba(200,220,240,0.9);
        }
        .today-divider{width:1px;height:16px;background:rgba(0,229,255,0.4);}
        .today-value{font-weight:700;font-size:13px;color:var(--cyan-glow);text-shadow:0 0 8px rgba(0,229,255,0.5);}
        .features{
            display:grid; grid-template-columns:repeat(3,1fr); gap:10px; padding:0 16px; margin-bottom:14px;
            position:relative; z-index:2;
        }
        .feature-item{
            background:var(--bg-card); backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
            border-radius:var(--radius-md); padding:14px 6px; text-align:center; cursor:pointer;
            border:1px solid rgba(255,255,255,0.06); transition:all 0.3s cubic-bezier(0.4,0,0.2,1);
            position:relative; overflow:hidden; z-index:2;
        }
        .feature-item:active{transform:scale(0.94); border-color:var(--border-glow); box-shadow:0 0 18px rgba(0,229,255,0.3); background:var(--bg-card-hover);}
        .feature-icon{font-size:24px; margin-bottom:6px; filter:drop-shadow(0 0 6px rgba(0,229,255,0.3)); transition:transform 0.3s;}
        .feature-item:active .feature-icon{transform:scale(1.2);}
        .feature-name{font-size:10px; color:var(--text-secondary); font-weight:600; letter-spacing:1px;}
        .content-section{
            background:var(--bg-card); backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);
            margin:0 16px 14px; border-radius:var(--radius-lg); padding:16px;
            border:1px solid rgba(255,255,255,0.07); box-shadow:0 4px 30px rgba(0,0,0,0.3); position:relative; z-index:2;
        }
        .section-title{display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:14px;}
        .section-title>span{font-size:16px; font-weight:700; letter-spacing:1.5px; color:var(--text-primary); font-family:var(--font-mono); text-shadow:0 0 10px rgba(0,229,255,0.3);}
        .action-btn{
            padding:7px 14px; border:1px solid rgba(255,255,255,0.15); border-radius:20px; font-size:11px; font-weight:700;
            cursor:pointer; letter-spacing:1px; backdrop-filter:blur(8px); transition:all 0.3s;
        }
        .action-btn.add{background:rgba(0,229,255,0.15);color:var(--cyan);border-color:rgba(0,229,255,0.4);}
        .action-btn.add:active{background:rgba(0,229,255,0.3);box-shadow:0 0 20px rgba(0,229,255,0.5);transform:scale(0.93);}
        .action-btn.edit{background:rgba(255,204,0,0.1);color:var(--gold);border-color:rgba(255,204,0,0.4);}
        .action-btn.delete{background:rgba(255,45,149,0.12);color:var(--magenta);border-color:rgba(255,45,149,0.4);}
        .list-item{
            display:flex; justify-content:space-between; align-items:center; padding:14px;
            background:rgba(20,24,40,0.5); border-radius:var(--radius-md); margin-bottom:10px;
            border:1px solid rgba(255,255,255,0.04); transition:all 0.3s;
        }
        .item-info{flex:1;} .item-name{font-size:13px;font-weight:600;margin-bottom:3px;} .item-points{font-size:15px;font-weight:700;font-family:var(--font-mono);}
        .item-points.income{color:var(--neon-green);text-shadow:0 0 8px rgba(0,255,136,0.4);}
        .item-points.expense{color:var(--magenta);text-shadow:0 0 8px rgba(255,45,149,0.4);}
        .item-btn{
            padding:7px 14px; border-radius:20px; font-size:11px; font-weight:700; cursor:pointer; letter-spacing:1px;
            backdrop-filter:blur(6px); transition:all 0.3s; border:1px solid transparent;
        }
        .item-btn.earn{background:rgba(0,255,136,0.12);color:var(--neon-green);border-color:rgba(0,255,136,0.4);}
        .item-btn.earn:active{background:rgba(0,255,136,0.3);box-shadow:0 0 18px rgba(0,255,136,0.5);transform:scale(0.92);}
        .item-btn.deduct{background:rgba(255,45,149,0.12);color:var(--magenta);border-color:rgba(255,45,149,0.4);}
        .item-btn.deduct:active{background:rgba(255,45,149,0.3);box-shadow:0 0 18px rgba(255,45,149,0.5);}
        .item-btn.exchange{background:rgba(180,77,255,0.12);color:var(--purple);border-color:rgba(180,77,255,0.4);}
        .week-grid{display:grid; grid-template-columns:repeat(7,1fr); gap:6px;}
        .day-item{
            cursor:pointer; background:rgba(18,22,36,0.6); border-radius:var(--radius-sm); padding:10px 4px;
            text-align:center; border:1px solid rgba(255,255,255,0.04); transition:all 0.3s;
        }
        .day-item.today{background:linear-gradient(160deg,rgba(0,229,255,0.2),rgba(0,180,220,0.25));border-color:rgba(0,229,255,0.5);}
        .day-item.selected{border-color:rgba(180,77,255,0.55);box-shadow:0 0 12px rgba(180,77,255,0.3);}
        .day-name{font-size:9px;color:var(--text-dim);} .day-points{font-size:14px;font-weight:700;font-family:var(--font-mono);}
        .record-list{max-height:380px;overflow-y:auto;}
        .record-item{display:flex; justify-content:space-between; align-items:center; padding:14px 0; border-bottom:1px solid rgba(255,255,255,0.04);}
        .record-title{font-size:13px;font-weight:600;} .record-time{font-size:11px;color:var(--text-dim);}
        .record-amount{font-size:15px;font-weight:700;font-family:var(--font-mono);}
        .record-amount.income{color:var(--neon-green);} .record-amount.expense{color:var(--magenta);}
        .month-calendar{background:rgba(18,22,36,0.5);border-radius:var(--radius-md);padding:12px;margin-bottom:12px;}
        .year-calendar{display:grid; grid-template-columns:repeat(6,1fr); gap:7px;}
        .year-month-card{background:rgba(18,22,36,0.5);border-radius:var(--radius-sm);padding:10px 5px;text-align:center;cursor:pointer;border:1px solid transparent;}
        .year-month-card.current{border-color:var(--cyan);}
        .modal{
            display:none; position:fixed; top:0;left:0;right:0;bottom:0; background:rgba(2,4,10,0.8);
            backdrop-filter:blur(6px); z-index:1000; align-items:center; justify-content:center;
        }
        .modal.show{display:flex; animation:modalFadeIn 0.25s;}
        @keyframes modalFadeIn{from{opacity:0;}to{opacity:1;}}
        .modal-content{
            background:linear-gradient(160deg,rgba(16,20,34,0.95),rgba(12,16,28,0.98)); border-radius:var(--radius-lg);
            padding:24px; width:90%; max-width:400px; border:1px solid rgba(0,229,255,0.3);
            box-shadow:0 0 40px rgba(0,229,255,0.2); animation:modalSlide 0.35s;
        }
        @keyframes modalSlide{from{transform:translateY(30px);opacity:0;}to{transform:translateY(0);opacity:1;}}
        .modal-title{font-size:17px;font-weight:700;margin-bottom:18px;text-align:center;color:var(--cyan);}
        .form-group{margin-bottom:14px;}
        .form-label{display:block; font-size:12px; font-weight:700; margin-bottom:7px; color:var(--text-secondary);}
        .form-input{
            width:100%; padding:11px; background:rgba(10,14,24,0.7); border:1px solid rgba(255,255,255,0.1);
            border-radius:var(--radius-sm); color:var(--text-primary); outline:none; font-family:var(--font-mono);
        }
        .form-input:focus{border-color:var(--cyan);box-shadow:0 0 14px rgba(0,229,255,0.2);}
        .modal-footer{display:flex; gap:10px;}
        .modal-btn{
            flex:1; padding:12px; border-radius:22px; font-weight:700; cursor:pointer; letter-spacing:1px;
            transition:all 0.3s; border:1px solid rgba(255,255,255,0.15);
        }
        .modal-btn.confirm{background:rgba(0,229,255,0.18);color:var(--cyan);border-color:rgba(0,229,255,0.4);}
        .modal-btn.cancel{background:rgba(255,255,255,0.05);color:var(--text-secondary);}
        .modal-btn.danger{background:rgba(255,45,149,0.18);color:var(--magenta);border-color:rgba(255,45,149,0.4);}
        .bottom-nav{
            position:fixed; bottom:0; left:0; right:0; background:rgba(10,12,22,0.85);
            backdrop-filter:blur(22px); display:flex; justify-content:space-around; padding:10px 0;
            padding-bottom:calc(10px + env(safe-area-inset-bottom)); border-top:1px solid rgba(0,229,255,0.2);
            z-index:100;
        }
        .nav-item{text-align:center; cursor:pointer; flex:1; transition:all 0.3s;}
        .nav-icon{font-size:22px;} .nav-text{font-size:10px; color:var(--text-dim);}
        .nav-item.active .nav-text{color:var(--cyan);text-shadow:0 0 10px rgba(0,229,255,0.5);}
        .page{display:none; position:relative; z-index:2;}
        .page.active{display:block; animation:pageIn 0.35s;}
        @keyframes pageIn{from{opacity:0;transform:translateY(12px);}to{opacity:1;transform:translateY(0);}}
        .empty-state{text-align:center;padding:36px;color:var(--text-dim);}
        .gacha-container{text-align:center; padding:20px;}
        .gacha-machine{
            width:160px; height:160px; margin:20px auto; background:radial-gradient(circle at 30% 30%, rgba(0,229,255,0.3), rgba(10,14,26,0.9));
            border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:48px;
            border:3px solid rgba(0,229,255,0.5); box-shadow:0 0 30px rgba(0,229,255,0.4); cursor:pointer;
            transition:all 0.2s; animation:float 3s ease-in-out infinite;
        }
        @keyframes float{0%,100%{transform:translateY(0);}50%{transform:translateY(-8px);}}
        .gacha-machine:active{transform:scale(0.9) rotate(10deg);}
        .progress-bar{height:12px; background:rgba(255,255,255,0.1); border-radius:6px; overflow:hidden; margin-top:8px;}
        .progress-fill{height:100%; background:linear-gradient(90deg,var(--cyan),var(--purple)); border-radius:6px; transition:width 0.5s;}
        .badge-grid{display:grid; grid-template-columns:repeat(4,1fr); gap:10px;}
        .badge-item{text-align:center; padding:10px; background:rgba(20,24,40,0.5); border-radius:12px; opacity:0.5;}
        .badge-item.unlocked{opacity:1; border:1px solid var(--cyan); box-shadow:0 0 12px rgba(0,229,255,0.3);}
    </style>
</head>
<body>
<canvas id="particles-canvas"></canvas>
<div class="header"><h1>◆ 积分小管家 · 旗舰版 ◆</h1></div>

<div class="bottom-nav">
    <div class="nav-item active" onclick="switchPage('home')"><div class="nav-icon">&#127968;</div><div class="nav-text">首页</div></div>
    <div class="nav-item" onclick="switchPage('records')"><div class="nav-icon">&#128202;</div><div class="nav-text">记录</div></div>
    <div class="nav-item" onclick="switchPage('habit')"><div class="nav-icon">&#128203;</div><div class="nav-text">打卡</div></div>
    <div class="nav-item" onclick="switchPage('achievement')"><div class="nav-icon">&#127942;</div><div class="nav-text">成就</div></div>
</div>

<!-- 页面容器 -->
<div class="page active" id="home-page">
    <div class="points-card">
        <div class="points-header"><div class="points-title">&#9672; 总积分 &#9672;</div><div class="points-amount" id="total-points">0</div></div>
        <div class="points-today"><span>&#128197; 今日积分</span><span class="today-divider"></span><span class="today-value" id="daily-challenge">赚0分 - 扣0分 = 0分</span></div>
    </div>
    <div class="features">
        <div class="feature-item" onclick="switchPage('earn')"><div class="feature-icon">&#10133;</div><div class="feature-name">赚取积分</div></div>
        <div class="feature-item" onclick="switchPage('deduct')"><div class="feature-icon">&#10134;</div><div class="feature-name">扣取积分</div></div>
        <div class="feature-item" onclick="switchPage('exchange')"><div class="feature-icon">&#127978;</div><div class="feature-name">奖励兑换</div></div>
        <div class="feature-item" onclick="switchPage('earn-manage')"><div class="feature-icon">&#128176;</div><div class="feature-name">积分项设置</div></div>
        <div class="feature-item" onclick="switchPage('deduct-manage')"><div class="feature-icon">&#9888;&#65039;</div><div class="feature-name">扣分项设置</div></div>
        <div class="feature-item" onclick="switchPage('exchange-manage')"><div class="feature-icon">&#127873;</div><div class="feature-name">兑换设置</div></div>
        <div class="feature-item" onclick="switchPage('goal')"><div class="feature-icon">&#127919;</div><div class="feature-name">积分目标</div></div>
        <div class="feature-item" onclick="switchPage('gacha')"><div class="feature-icon">&#127920;</div><div class="feature-name">扭蛋机</div></div>
        <div class="feature-item" onclick="switchPage('habit')"><div class="feature-icon">&#128203;</div><div class="feature-name">习惯打卡</div></div>
    </div>
    <div class="content-section">
        <div class="section-title"><span id="week-score-text">本周积分</span></div>
        <div class="week-grid" id="current-week-grid"></div>
    </div>
    <div class="features">
        <div class="feature-item" onclick="showClearPointsModal()"><div class="feature-icon">&#128465;&#65039;</div><div class="feature-name">积分清空</div></div>
        <div class="feature-item" onclick="systemReset()"><div class="feature-icon">&#128260;</div><div class="feature-name">系统重置</div></div>
        <div class="feature-item" onclick="generateReport()"><div class="feature-icon">&#128228;</div><div class="feature-name">生成战报</div></div>
    </div>
</div>

<div class="page" id="earn-page"><div class="content-section"><div class="section-title"><span>赚取积分</span></div><div id="earn-list"></div></div></div>
<div class="page" id="deduct-page"><div class="content-section"><div class="section-title"><span>扣取积分</span></div><div id="deduct-list"></div></div></div>
<div class="page" id="exchange-page"><div class="content-section"><div class="section-title"><span>兑换中心</span></div><div id="exchange-list"></div></div></div>
<div class="page" id="earn-manage-page"><div class="content-section"><div class="section-title"><span>积分项管理</span><button class="action-btn add" onclick="showAddEarnItemModal()">+ 添加</button></div><div id="earn-manage-list"></div></div></div>
<div class="page" id="deduct-manage-page"><div class="content-section"><div class="section-title"><span>扣分项管理</span><button class="action-btn add" onclick="showAddDeductItemModal()">+ 添加</button></div><div id="deduct-manage-list"></div></div></div>
<div class="page" id="exchange-manage-page"><div class="content-section"><div class="section-title"><span>兑换奖励管理</span><button class="action-btn add" onclick="showAddRewardModal()">+ 添加</button></div><div id="reward-manage-list"></div></div></div>

<div class="page" id="records-page">
    <div class="content-section"><div class="section-title"><span id="records-week-score-text">本周积分</span><button class="action-btn add" onclick="showAddPointsModal()">补积分</button></div><div class="week-grid" id="records-week-grid"></div></div>
    <div class="content-section"><div class="section-title">每日积分记录</div><div class="record-list" id="day-records"></div></div>
    <div class="content-section"><div class="section-title">历史积分</div><div id="history-weeks"></div></div>
</div>

<div class="page" id="goal-page">
    <div class="content-section"><div class="section-title"><span>积分目标追踪</span><button class="action-btn add" onclick="showAddGoalModal()">+ 新目标</button></div><div id="goal-list"></div></div>
</div>

<div class="page" id="gacha-page">
    <div class="content-section"><div class="section-title"><span>积分扭蛋机</span></div>
        <div class="gacha-container"><div class="gacha-machine" onclick="playGacha()">&#127920;</div><p style="color:var(--text-dim);">消耗 20 积分抽一次</p><div id="gacha-result" style="margin-top:16px;font-weight:bold;"></div></div>
    </div>
</div>

<div class="page" id="habit-page">
    <div class="content-section"><div class="section-title"><span>习惯打卡</span><button class="action-btn add" onclick="showAddHabitModal()">+ 新习惯</button></div><div id="habit-list"></div></div>
</div>

<div class="page" id="achievement-page">
    <div class="content-section"><div class="section-title"><span>成就勋章馆</span></div><div class="badge-grid" id="badge-grid"></div></div>
</div>

<!-- 弹窗集合 -->
<div class="modal" id="add-earn-item-modal"><div class="modal-content"><div class="modal-title">添加赚取积分项</div><div class="modal-body"><div class="form-group"><label class="form-label">项目名称</label><input class="form-input" id="earn-item-name" placeholder="例如:完成作业"></div><div class="form-group"><label class="form-label">积分数量</label><input type="number" class="form-input" id="earn-item-points" placeholder="10"></div></div><div class="modal-footer"><button class="modal-btn cancel" onclick="closeModal('add-earn-item-modal')">取消</button><button class="modal-btn confirm" onclick="saveEarnItem()">保存</button></div></div></div>
<div class="modal" id="add-deduct-item-modal"><div class="modal-content"><div class="modal-title">添加扣取积分项</div><div class="modal-body"><div class="form-group"><label class="form-label">项目名称</label><input class="form-input" id="deduct-item-name" placeholder="例如:未完成作业"></div><div class="form-group"><label class="form-label">积分数量</label><input type="number" class="form-input" id="deduct-item-points" placeholder="10"></div></div><div class="modal-footer"><button class="modal-btn cancel" onclick="closeModal('add-deduct-item-modal')">取消</button><button class="modal-btn confirm" onclick="saveDeductItem()">保存</button></div></div></div>
<div class="modal" id="add-reward-modal"><div class="modal-content"><div class="modal-title">添加兑换奖励</div><div class="modal-body"><div class="form-group"><label class="form-label">奖励名称</label><input class="form-input" id="reward-name" placeholder="例如:看电视30分钟"></div><div class="form-group"><label class="form-label">所需积分</label><input type="number" class="form-input" id="reward-points" placeholder="50"></div></div><div class="modal-footer"><button class="modal-btn cancel" onclick="closeModal('add-reward-modal')">取消</button><button class="modal-btn confirm" onclick="saveReward()">保存</button></div></div></div>
<div class="modal" id="exchange-confirm-modal"><div class="modal-content"><div class="modal-title">确认兑换</div><div class="modal-body"><p id="exchange-reward-name"></p><p style="color:var(--purple);font-weight:700;font-size:20px;" id="exchange-reward-points"></p></div><div class="modal-footer"><button class="modal-btn cancel" onclick="closeModal('exchange-confirm-modal')">取消</button><button class="modal-btn confirm" onclick="confirmExchange()">确认兑换</button></div></div></div>
<div class="modal" id="add-points-modal"><div class="modal-content"><div class="modal-title">补积分</div><div class="modal-body"><div class="form-group"><label class="form-label">原因</label><input class="form-input" id="add-points-reason" placeholder="例如:忘记记录"></div><div class="form-group"><label class="form-label">积分数值</label><input type="number" class="form-input" id="add-points-value" placeholder="10"></div><div class="form-group"><label class="form-label">日期</label><input type="date" class="form-input" id="add-points-date"></div></div><div class="modal-footer"><button class="modal-btn cancel" onclick="closeModal('add-points-modal')">取消</button><button class="modal-btn confirm" onclick="addPoints()">确认</button></div></div></div>
<div class="modal" id="clear-points-modal"><div class="modal-content"><div class="modal-title">确认清空积分</div><div class="modal-body"><p>确定要清空所有积分吗?此操作不可恢复!</p></div><div class="modal-footer"><button class="modal-btn cancel" onclick="closeModal('clear-points-modal')">取消</button><button class="modal-btn danger" onclick="confirmClearPoints()">确认清空</button></div></div></div>
<div class="modal" id="delete-confirm-modal"><div class="modal-content"><div class="modal-title">确认删除</div><div class="modal-body"><p>确定要删除此项目吗?</p></div><div class="modal-footer"><button class="modal-btn cancel" onclick="closeModal('delete-confirm-modal')">取消</button><button class="modal-btn danger" onclick="confirmDelete()">确认删除</button></div></div></div>
<div class="modal" id="add-goal-modal"><div class="modal-content"><div class="modal-title">添加积分目标</div><div class="modal-body"><div class="form-group"><label class="form-label">目标名称</label><input class="form-input" id="goal-name" placeholder="如:乐高玩具"></div><div class="form-group"><label class="form-label">所需积分</label><input type="number" class="form-input" id="goal-points" placeholder="200"></div></div><div class="modal-footer"><button class="modal-btn cancel" onclick="closeModal('add-goal-modal')">取消</button><button class="modal-btn confirm" onclick="saveGoal()">保存</button></div></div></div>
<div class="modal" id="add-habit-modal"><div class="modal-content"><div class="modal-title">添加习惯</div><div class="modal-body"><div class="form-group"><label class="form-label">习惯名称</label><input class="form-input" id="habit-name" placeholder="如:早起"></div><div class="form-group"><label class="form-label">积分</label><input type="number" class="form-input" id="habit-points" placeholder="5"></div><div class="form-group"><label class="form-label">周期</label><select class="form-input" id="habit-period"><option value="daily">每天</option><option value="weekly">每周</option></select></div></div><div class="modal-footer"><button class="modal-btn cancel" onclick="closeModal('add-habit-modal')">取消</button><button class="modal-btn confirm" onclick="saveHabit()">保存</button></div></div></div>

<script>
    (function(){
        const canvas=document.getElementById('particles-canvas'),ctx=canvas.getContext('2d');
        let particles=[], w,h;
        function resize(){w=canvas.width=window.innerWidth;h=canvas.height=window.innerHeight;}
        window.addEventListener('resize',resize); resize();
        class P{constructor(){this.reset();}reset(){this.x=Math.random()*w;this.y=Math.random()*h;this.size=Math.random()*2+0.8;this.sx=(Math.random()-0.5)*0.5;this.sy=(Math.random()-0.5)*0.5;this.color=`rgba(${[0,229,255,180,77,255,0,255,136,255,45,149][Math.floor(Math.random()*4)]},`;this.alpha=Math.random()*0.6+0.2;}update(){this.x+=this.sx;this.y+=this.sy;if(this.x<-20||this.x>w+20||this.y<-20||this.y>h+20)this.reset();}draw(){ctx.beginPath();ctx.arc(this.x,this.y,this.size,0,Math.PI*2);ctx.fillStyle=this.color+this.alpha+')';ctx.fill();}}
        for(let i=0;i<60;i++)particles.push(new P());
        function anim(){ctx.clearRect(0,0,w,h);particles.forEach(p=>{p.update();p.draw();});requestAnimationFrame(anim);}
        anim();
    })();

    const KEYS={
        total:'jf_total', earnItems:'jf_earn', deductItems:'jf_deduct', rewards:'jf_rewards',
        records:'jf_records', rid:'jf_rid', goals:'jf_goals', habits:'jf_habits',
        achievements:'jf_achieve', backpack:'jf_backpack'
    };
    let totalPoints=0, earnItems=[], deductItems=[], rewards=[], records=[], recordIdCounter=0;
    let goals=[], habits=[], unlockedAchievements=[], backpack={};
    let currentEditItem=null, currentDeleteItem=null, currentDeleteType='', currentExchangeReward=null;
    let selectedDate=null, displayYear=null, displayMonth=null;

    function initData(){
        totalPoints=parseInt(localStorage.getItem(KEYS.total))||0;
        earnItems=JSON.parse(localStorage.getItem(KEYS.earnItems))||[{id:1,name:'完成作业',points:10},{id:2,name:'阅读',points:5}];
        deductItems=JSON.parse(localStorage.getItem(KEYS.deductItems))||[{id:1,name:'未完成作业',points:-10}];
        rewards=JSON.parse(localStorage.getItem(KEYS.rewards))||[{id:1,name:'看电视30分钟',points:50}];
        records=JSON.parse(localStorage.getItem(KEYS.records))||[];
        recordIdCounter=parseInt(localStorage.getItem(KEYS.rid))||0;
        goals=JSON.parse(localStorage.getItem(KEYS.goals))||[];
        habits=JSON.parse(localStorage.getItem(KEYS.habits))||[];
        unlockedAchievements=JSON.parse(localStorage.getItem(KEYS.achievements))||[];
        backpack=JSON.parse(localStorage.getItem(KEYS.backpack))||{};
    }
    function save(){
        localStorage.setItem(KEYS.total,totalPoints);
        localStorage.setItem(KEYS.earnItems,JSON.stringify(earnItems));
        localStorage.setItem(KEYS.deductItems,JSON.stringify(deductItems));
        localStorage.setItem(KEYS.rewards,JSON.stringify(rewards));
        localStorage.setItem(KEYS.records,JSON.stringify(records));
        localStorage.setItem(KEYS.rid,recordIdCounter);
        localStorage.setItem(KEYS.goals,JSON.stringify(goals));
        localStorage.setItem(KEYS.habits,JSON.stringify(habits));
        localStorage.setItem(KEYS.achievements,JSON.stringify(unlockedAchievements));
        localStorage.setItem(KEYS.backpack,JSON.stringify(backpack));
    }
    function formatDate(d){return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;}
    function addRecord(title,amount,type,date=null,time=null){
        const now=new Date(); recordIdCounter++;
        records.unshift({id:recordIdCounter,title,amount,type,date:date||formatDate(now),time:time||now.toLocaleTimeString('zh-CN',{hour:'2-digit',minute:'2-digit'})});
        checkAchievements();
    }
    function updateUI(){document.getElementById('total-points').textContent=totalPoints.toLocaleString();}
    function updateToday(){
        const today=formatDate(new Date()), dayR=records.filter(r=>r.date===today);
        const earn=dayR.filter(r=>r.type==='income').reduce((s,r)=>s+r.amount,0);
        const deduct=Math.abs(dayR.filter(r=>r.type==='expense').reduce((s,r)=>s+r.amount,0));
        document.getElementById('daily-challenge').textContent=`赚${earn}分 - 扣${deduct}分 = ${earn-deduct}分`;
    }
    function showAlert(msg){
        const m=document.createElement('div'); m.className='modal show';
        m.innerHTML=`<div class="modal-content"><div class="modal-title">提示</div><div class="modal-body"><p>${msg}</p></div><div class="modal-footer"><button class="modal-btn confirm" onclick="this.closest('.modal').remove()">确定</button></div></div>`;
        document.body.appendChild(m); m.addEventListener('click',e=>{if(e.target===m)m.remove();});
    }
    function closeModal(id){document.getElementById(id).classList.remove('show');}

    function switchPage(name){
        document.querySelectorAll('.page').forEach(p=>p.classList.remove('active'));
        const target=document.getElementById(name+'-page'); if(target)target.classList.add('active');
        document.querySelectorAll('.nav-item').forEach(n=>n.classList.remove('active'));
        const navMap={home:0, records:1, habit:2, achievement:3};
        if(navMap[name]!==undefined)document.querySelectorAll('.nav-item')[navMap[name]].classList.add('active');
        if(name==='home'){loadHome();}
        else if(name==='records'){loadRecords();}
        else if(name==='goal'){loadGoals();}
        else if(name==='gacha'){}
        else if(name==='habit'){loadHabits();}
        else if(name==='achievement'){loadAchievements();}
        else if(name==='earn'){loadEarnList();}
        else if(name==='deduct'){loadDeductList();}
        else if(name==='exchange'){loadExchangeList();}
        else if(name==='earn-manage'){loadEarnManage();}
        else if(name==='deduct-manage'){loadDeductManage();}
        else if(name==='exchange-manage'){loadRewardManage();}
        window.scrollTo(0,0);
    }

    function loadHome(){updateUI();updateToday();loadWeekGrid('current-week-grid','week-score-text');}
    function loadRecords(){if(!selectedDate)selectedDate=formatDate(new Date());loadWeekGrid('records-week-grid','records-week-score-text');loadDayRecords();loadHistory();}
    function loadWeekGrid(gridId,titleId){
        const grid=document.getElementById(gridId), now=new Date(), curDay=now.getDay();
        const start=new Date(now); start.setDate(now.getDate()-(curDay===0?6:curDay-1));
        let total=0, html=''; const days=['周一','周二','周三','周四','周五','周六','周日'];
        days.forEach((d,i)=>{
            const date=new Date(start); date.setDate(start.getDate()+i); const ds=formatDate(date);
            const dayR=records.filter(r=>r.date===ds); const dayTotal=dayR.reduce((s,r)=>s+r.amount,0); total+=dayTotal;
            const isToday=date.toDateString()===now.toDateString(), isSel=selectedDate===ds;
            html+=`<div class="day-item ${isToday?'today':''} ${isSel?'selected':''}" onclick="selectDay('${ds}')"><div class="day-name">${d}</div><div class="day-points">${dayTotal>0?'+':''}${dayTotal}</div></div>`;
        });
        grid.innerHTML=html;
        const el=document.getElementById(titleId); if(el)el.textContent=`本周积分 (${total>=0?'+':''}${total})`;
    }
    function selectDay(ds){selectedDate=ds; switchPage('records');}
    function loadDayRecords(){
        const c=document.getElementById('day-records');
        if(!selectedDate){c.innerHTML='<div class="empty-state">请选择日期</div>';return;}
        const dayR=records.filter(r=>r.date===selectedDate);
        if(dayR.length===0)c.innerHTML='<div class="empty-state">暂无记录</div>';
        else c.innerHTML=dayR.map(r=>`<div class="list-item"><div class="item-info"><div class="item-name">${r.title}</div><div class="record-time">${r.time}</div></div><div class="item-points ${r.type}">${r.type==='income'?'+':''}${r.amount}</div><button class="action-btn delete" onclick="undoRecord(${r.id})">撤销</button></div>`).join('');
    }
    function loadHistory(){
        const container=document.getElementById('history-weeks'); if(!container)return;
        const now=new Date(), curYear=now.getFullYear(), curMonth=now.getMonth();
        if(displayYear===null){displayYear=curYear; displayMonth=curMonth;}
        const dYear=displayYear, dMonth=displayMonth;
        const yearStart=formatDate(new Date(dYear,0,1)), yearEnd=formatDate(new Date(dYear,11,31));
        const yearRecords=records.filter(r=>r.date>=yearStart&&r.date<=yearEnd);
        const yearTotal=yearRecords.reduce((s,r)=>s+r.amount,0);
        const daysInMonth=new Date(dYear,dMonth+1,0).getDate();
        const monthStart=formatDate(new Date(dYear,dMonth,1)), monthEnd=formatDate(new Date(dYear,dMonth,daysInMonth));
        const monthRecords=records.filter(r=>r.date>=monthStart&&r.date<=monthEnd);
        const monthTotal=monthRecords.reduce((s,r)=>s+r.amount,0);
        const firstDay=new Date(dYear,dMonth,1).getDay(), startPadding=firstDay===0?6:firstDay-1;
        let html=`<div class="month-calendar"><div class="section-title">${dYear}年${dMonth+1}月 (${monthTotal>=0?'+':''}${monthTotal})</div><div class="month-weekdays">${['一','二','三','四','五','六','日'].map(w=>`<div class="month-weekday">${w}</div>`).join('')}</div><div class="month-days">`;
        for(let p=0;p<startPadding;p++)html+='<div class="month-day empty"></div>';
        for(let d=1;d<=daysInMonth;d++){
            const ds=formatDate(new Date(dYear,dMonth,d));
            const dayR=records.filter(r=>r.date===ds); const dayTotal=dayR.reduce((s,r)=>s+r.amount,0);
            const ptsStr=dayTotal!==0?((dayTotal>0?'+':'')+dayTotal):'';
            const isToday=ds===formatDate(now)?' today':'';
            html+=`<div class="month-day${isToday}"><div class="month-day-num">${d}</div><div class="month-day-pts">${ptsStr}</div></div>`;
        }
        html+=`</div></div><div class="year-calendar">`;
        for(let m=0;m<12;m++){
            const ms=formatDate(new Date(dYear,m,1)), me=formatDate(new Date(dYear,m,new Date(dYear,m+1,0).getDate()));
            const mRec=records.filter(r=>r.date>=ms&&r.date<=me); const mTotal=mRec.reduce((s,r)=>s+r.amount,0);
            html+=`<div class="year-month-card${(dYear===curYear&&m===curMonth)?' current':''}" onclick="displayMonth=${m};loadHistory();">${m+1}月<br>${mTotal>=0?'+':''}${mTotal}</div>`;
        }
        html+='</div>'; container.innerHTML=html;
    }

    function loadEarnList(){
        const c=document.getElementById('earn-list');
        let h=`<div class="quick-add"><input class="qa-name" id="quick-earn-name" placeholder="名称"><input class="qa-points" id="quick-earn-points" type="number" placeholder="积分"><button class="qa-btn" onclick="quickEarn()">赚取</button></div>`;
        if(earnItems.length===0)h+='<div class="empty-state">暂无赚取项</div>';
        else h+=earnItems.map(i=>`<div class="list-item"><div class="item-info"><div class="item-name">${i.name}</div><div class="item-points income">+${i.points}</div></div><button class="item-btn earn" onclick="earnPoints(${i.id})">赚取</button></div>`).join('');
        c.innerHTML=h;
    }
    function quickEarn(){
        const name=document.getElementById('quick-earn-name').value.trim()||formatDate(new Date());
        const pts=parseInt(document.getElementById('quick-earn-points').value);
        if(!pts||pts<=0)return showAlert('请输入有效积分');
        totalPoints+=pts; addRecord(name,pts,'income');
        document.getElementById('quick-earn-name').value=''; document.getElementById('quick-earn-points').value='';
        save(); updateUI(); updateToday(); loadEarnList();
    }
    function earnPoints(id){
        const item=earnItems.find(i=>i.id===id); if(!item)return;
        totalPoints+=item.points; addRecord(item.name,item.points,'income');
        save(); updateUI(); updateToday();
    }

    function loadDeductList(){
        const c=document.getElementById('deduct-list');
        let h=`<div class="quick-add deduct"><input class="qa-name" id="quick-deduct-name" placeholder="名称"><input class="qa-points" id="quick-deduct-points" type="number" placeholder="积分"><button class="qa-btn" onclick="quickDeduct()">扣取</button></div>`;
        if(deductItems.length===0)h+='<div class="empty-state">暂无扣分项</div>';
        else h+=deductItems.map(i=>`<div class="list-item"><div class="item-info"><div class="item-name">${i.name}</div><div class="item-points expense">${i.points}</div></div><button class="item-btn deduct" onclick="deductPoints(${i.id})">扣取</button></div>`).join('');
        c.innerHTML=h;
    }
    function quickDeduct(){
        const name=document.getElementById('quick-deduct-name').value.trim()||formatDate(new Date());
        const pts=parseInt(document.getElementById('quick-deduct-points').value);
        if(!pts||pts<=0)return showAlert('请输入有效积分');
        totalPoints-=pts; addRecord(name,-pts,'expense');
        document.getElementById('quick-deduct-name').value=''; document.getElementById('quick-deduct-points').value='';
        save(); updateUI(); updateToday(); loadDeductList();
    }
    function deductPoints(id){
        const item=deductItems.find(i=>i.id===id); if(!item)return;
        totalPoints+=item.points; addRecord(item.name,item.points,'expense');
        save(); updateUI(); updateToday();
    }

    function loadExchangeList(){
        const c=document.getElementById('exchange-list');
        if(rewards.length===0){c.innerHTML='<div class="empty-state">暂无奖励</div>';return;}
        c.innerHTML=rewards.map(r=>`<div class="list-item"><div class="item-info"><div class="item-name">${r.name}</div><div class="item-points">${r.points}积分</div></div><button class="item-btn exchange" onclick="showExchangeModal(${r.id})">兑换</button></div>`).join('');
    }
    function showExchangeModal(id){
        const r=rewards.find(x=>x.id===id); if(!r)return;
        currentExchangeReward=r;
        document.getElementById('exchange-reward-name').textContent=r.name;
        document.getElementById('exchange-reward-points').textContent=r.points+'积分';
        document.getElementById('exchange-confirm-modal').classList.add('show');
    }
    function confirmExchange(){
        if(!currentExchangeReward)return;
        if(totalPoints<currentExchangeReward.points){closeModal('exchange-confirm-modal');showAlert('积分不足');return;}
        totalPoints-=currentExchangeReward.points;
        addRecord('兑换:'+currentExchangeReward.name,-currentExchangeReward.points,'expense');
        save(); updateUI(); updateToday(); closeModal('exchange-confirm-modal');
    }

    function loadEarnManage(){
        const c=document.getElementById('earn-manage-list');
        if(earnItems.length===0){c.innerHTML='<div class="empty-state">暂无</div>';return;}
        c.innerHTML=earnItems.map(i=>`<div class="list-item"><div class="item-info"><div class="item-name">${i.name}</div><div class="item-points income">+${i.points}</div></div><div class="item-actions"><button class="action-btn edit" onclick="editEarnItem(${i.id})">编辑</button><button class="action-btn delete" onclick="deleteEarnItem(${i.id})">删除</button></div></div>`).join('');
    }
    function showAddEarnItemModal(){currentEditItem=null; document.getElementById('earn-item-name').value=''; document.getElementById('earn-item-points').value=''; document.getElementById('add-earn-item-modal').classList.add('show');}
    function editEarnItem(id){const item=earnItems.find(i=>i.id===id); if(item){currentEditItem=item; document.getElementById('earn-item-name').value=item.name; document.getElementById('earn-item-points').value=item.points; document.getElementById('add-earn-item-modal').classList.add('show');}}
    function saveEarnItem(){
        const name=document.getElementById('earn-item-name').value.trim(), pts=parseInt(document.getElementById('earn-item-points').value);
        if(!name||isNaN(pts))return showAlert('请填写完整');
        if(currentEditItem){currentEditItem.name=name; currentEditItem.points=pts;}
        else{const id=earnItems.length?Math.max(...earnItems.map(i=>i.id))+1:1; earnItems.push({id,name,points:pts});}
        save(); loadEarnManage(); closeModal('add-earn-item-modal');
    }
    function deleteEarnItem(id){currentDeleteItem=id; currentDeleteType='earn'; document.getElementById('delete-confirm-modal').classList.add('show');}

    function loadDeductManage(){
        const c=document.getElementById('deduct-manage-list');
        if(deductItems.length===0){c.innerHTML='<div class="empty-state">暂无</div>';return;}
        c.innerHTML=deductItems.map(i=>`<div class="list-item"><div class="item-info"><div class="item-name">${i.name}</div><div class="item-points expense">${i.points}</div></div><div class="item-actions"><button class="action-btn edit" onclick="editDeductItem(${i.id})">编辑</button><button class="action-btn delete" onclick="deleteDeductItem(${i.id})">删除</button></div></div>`).join('');
    }
    function showAddDeductItemModal(){currentEditItem=null; document.getElementById('deduct-item-name').value=''; document.getElementById('deduct-item-points').value=''; document.getElementById('add-deduct-item-modal').classList.add('show');}
    function editDeductItem(id){const item=deductItems.find(i=>i.id===id); if(item){currentEditItem=item; document.getElementById('deduct-item-name').value=item.name; document.getElementById('deduct-item-points').value=Math.abs(item.points); document.getElementById('add-deduct-item-modal').classList.add('show');}}
    function saveDeductItem(){
        const name=document.getElementById('deduct-item-name').value.trim(), pts=parseInt(document.getElementById('deduct-item-points').value);
        if(!name||isNaN(pts))return showAlert('请填写完整');
        if(currentEditItem){currentEditItem.name=name; currentEditItem.points=-pts;}
        else{const id=deductItems.length?Math.max(...deductItems.map(i=>i.id))+1:1; deductItems.push({id,name,points:-pts});}
        save(); loadDeductManage(); closeModal('add-deduct-item-modal');
    }
    function deleteDeductItem(id){currentDeleteItem=id; currentDeleteType='deduct'; document.getElementById('delete-confirm-modal').classList.add('show');}

    function loadRewardManage(){
        const c=document.getElementById('reward-manage-list');
        if(rewards.length===0){c.innerHTML='<div class="empty-state">暂无</div>';return;}
        c.innerHTML=rewards.map(r=>`<div class="list-item"><div class="item-info"><div class="item-name">${r.name}</div><div class="item-points">${r.points}积分</div></div><div class="item-actions"><button class="action-btn edit" onclick="editReward(${r.id})">编辑</button><button class="action-btn delete" onclick="deleteReward(${r.id})">删除</button></div></div>`).join('');
    }
    function showAddRewardModal(){currentEditItem=null; document.getElementById('reward-name').value=''; document.getElementById('reward-points').value=''; document.getElementById('add-reward-modal').classList.add('show');}
    function editReward(id){const r=rewards.find(x=>x.id===id); if(r){currentEditItem=r; document.getElementById('reward-name').value=r.name; document.getElementById('reward-points').value=r.points; document.getElementById('add-reward-modal').classList.add('show');}}
    function saveReward(){
        const name=document.getElementById('reward-name').value.trim(), pts=parseInt(document.getElementById('reward-points').value);
        if(!name||isNaN(pts))return showAlert('请填写完整');
        if(currentEditItem){currentEditItem.name=name; currentEditItem.points=pts;}
        else{const id=rewards.length?Math.max(...rewards.map(r=>r.id))+1:1; rewards.push({id,name,points:pts});}
        save(); loadRewardManage(); closeModal('add-reward-modal');
    }
    function deleteReward(id){currentDeleteItem=id; currentDeleteType='reward'; document.getElementById('delete-confirm-modal').classList.add('show');}
    function confirmDelete(){
        if(currentDeleteType==='earn'){earnItems=earnItems.filter(i=>i.id!==currentDeleteItem);loadEarnManage();}
        else if(currentDeleteType==='deduct'){deductItems=deductItems.filter(i=>i.id!==currentDeleteItem);loadDeductManage();}
        else if(currentDeleteType==='reward'){rewards=rewards.filter(r=>r.id!==currentDeleteItem);loadRewardManage();}
        save(); closeModal('delete-confirm-modal');
    }

    function showAddPointsModal(){
        document.getElementById('add-points-date').value=formatDate(new Date());
        document.getElementById('add-points-reason').value=''; document.getElementById('add-points-value').value='';
        document.getElementById('add-points-modal').classList.add('show');
    }
    function addPoints(){
        const reason=document.getElementById('add-points-reason').value.trim();
        const val=parseInt(document.getElementById('add-points-value').value);
        const date=document.getElementById('add-points-date').value;
        if(!reason||isNaN(val)||!date)return showAlert('请填写完整');
        totalPoints+=val; addRecord('补积分:'+reason,val,'income',date);
        save(); updateUI(); updateToday(); closeModal('add-points-modal'); loadRecords();
    }
    function showClearPointsModal(){document.getElementById('clear-points-modal').classList.add('show');}
    function confirmClearPoints(){totalPoints=0;records=[];save();updateUI();updateToday();closeModal('clear-points-modal');}
    function systemReset(){
        if(!confirm('确定重置所有数据?'))return;
        totalPoints=0; records=[]; recordIdCounter=0;
        earnItems=[{id:1,name:'完成作业',points:10}]; deductItems=[{id:1,name:'未完成作业',points:-10}]; rewards=[{id:1,name:'看电视30分钟',points:50}];
        goals=[]; habits=[]; unlockedAchievements=[]; backpack={};
        save(); updateUI(); updateToday(); loadHome();
    }
    function undoRecord(id){
        const idx=records.findIndex(r=>r.id===id); if(idx===-1)return;
        totalPoints-=records[idx].amount; records.splice(idx,1);
        save(); updateUI(); updateToday(); loadDayRecords();
    }

    function loadGoals(){
        const c=document.getElementById('goal-list');
        if(goals.length===0){c.innerHTML='<div class="empty-state">还没有目标</div>';return;}
        c.innerHTML=goals.map(g=>{
            const pct=Math.min(100,Math.floor(totalPoints/g.points*100));
            return `<div class="list-item"><div class="item-info"><div class="item-name">${g.name} (${totalPoints}/${g.points})</div><div class="progress-bar"><div class="progress-fill" style="width:${pct}%"></div></div></div><button class="action-btn delete" onclick="deleteGoal(${g.id})">删除</button></div>`;
        }).join('');
    }
    function showAddGoalModal(){document.getElementById('goal-name').value='';document.getElementById('goal-points').value='';document.getElementById('add-goal-modal').classList.add('show');}
    function saveGoal(){
        const name=document.getElementById('goal-name').value.trim(), pts=parseInt(document.getElementById('goal-points').value);
        if(!name||isNaN(pts))return showAlert('请填写完整');
        const id=goals.length?Math.max(...goals.map(g=>g.id))+1:1;
        goals.push({id,name,points:pts}); save(); loadGoals(); closeModal('add-goal-modal');
    }
    function deleteGoal(id){goals=goals.filter(g=>g.id!==id);save();loadGoals();}

    function playGacha(){
        if(totalPoints<20)return showAlert('积分不足20');
        totalPoints-=20; addRecord('扭蛋抽奖',-20,'expense');
        const pool=[
            {name:'积分+5',type:'points',value:5},{name:'积分+10',type:'points',value:10},
            {name:'免扣金牌',type:'shield'},{name:'兑换券',type:'voucher'},{name:'谢谢参与',type:'none'}
        ];
        const prize=pool[Math.floor(Math.random()*pool.length)];
        if(prize.type==='points'){totalPoints+=prize.value;addRecord('扭蛋奖励',prize.value,'income');}
        else if(prize.type==='shield'){backpack.shield=(backpack.shield||0)+1;}
        else if(prize.type==='voucher'){backpack.voucher=(backpack.voucher||0)+1;}
        save(); updateUI(); updateToday();
        document.getElementById('gacha-result').innerHTML=`&#127881; 获得:${prize.name}`;
        setTimeout(()=>{document.getElementById('gacha-result').innerHTML='';},2000);
    }

    function loadHabits(){
        const c=document.getElementById('habit-list');
        if(habits.length===0){c.innerHTML='<div class="empty-state">还没有习惯</div>';return;}
        const today=formatDate(new Date());
        c.innerHTML=habits.map(h=>{
            const doneToday=records.some(r=>r.title===h.name&&r.date===today);
            return `<div class="list-item"><div class="item-info"><div class="item-name">${h.name} (${h.period==='daily'?'每天':'每周'} +${h.points})</div></div><button class="item-btn earn" onclick="doHabit(${h.id})" ${doneToday?'disabled':''}>${doneToday?'已完成':'打卡'}</button></div>`;
        }).join('');
    }
    function showAddHabitModal(){document.getElementById('habit-name').value='';document.getElementById('habit-points').value='';document.getElementById('add-habit-modal').classList.add('show');}
    function saveHabit(){
        const name=document.getElementById('habit-name').value.trim(), pts=parseInt(document.getElementById('habit-points').value), period=document.getElementById('habit-period').value;
        if(!name||isNaN(pts))return showAlert('请填写完整');
        const id=habits.length?Math.max(...habits.map(h=>h.id))+1:1;
        habits.push({id,name,points:pts,period}); save(); loadHabits(); closeModal('add-habit-modal');
    }
    function doHabit(id){
        const h=habits.find(x=>x.id===id); if(!h)return;
        totalPoints+=h.points; addRecord(h.name,h.points,'income');
        save(); updateUI(); updateToday(); loadHabits();
    }

    const ACHIEVEMENTS=[
        {id:'first_earn',name:'初尝甜头',desc:'首次赚取积分',check:()=>records.some(r=>r.type==='income')},
        {id:'points_100',name:'积分破百',desc:'总积分达到100',check:()=>totalPoints>=100},
        {id:'streak_7',name:'连续7天',desc:'连续7天有积分记录',check:()=>{const dates=[...new Set(records.map(r=>r.date))].sort().slice(-7);return dates.length===7;}},
        {id:'gacha_5',name:'扭蛋爱好者',desc:'抽扭蛋5次',check:()=>records.filter(r=>r.title==='扭蛋抽奖').length>=5}
    ];
    function checkAchievements(){
        ACHIEVEMENTS.forEach(a=>{if(!unlockedAchievements.includes(a.id)&&a.check()){unlockedAchievements.push(a.id);showAlert(`&#127942; 解锁成就:${a.name}`);}});
        save();
    }
    function loadAchievements(){
        const grid=document.getElementById('badge-grid');
        grid.innerHTML=ACHIEVEMENTS.map(a=>{
            const unlocked=unlockedAchievements.includes(a.id);
            return `<div class="badge-item ${unlocked?'unlocked':''}"><div style="font-size:28px;">${unlocked?'&#127942;':'&#128274;'}</div><div style="font-size:10px;">${a.name}</div></div>`;
        }).join('');
    }

    function generateReport(){
        const canvas=document.createElement('canvas'); canvas.width=400; canvas.height=600;
        const ctx=canvas.getContext('2d');
        ctx.fillStyle='#0a0c16'; ctx.fillRect(0,0,400,600);
        ctx.fillStyle='#00e5ff'; ctx.font='bold 22px sans-serif'; ctx.fillText('积分战报',120,50);
        const now=new Date(); const start=new Date(now); start.setDate(now.getDate()-now.getDay()+1);
        const weekR=records.filter(r=>{const d=new Date(r.date);return d>=start;});
        const earn=weekR.filter(r=>r.type==='income').reduce((s,r)=>s+r.amount,0);
        const deduct=Math.abs(weekR.filter(r=>r.type==='expense').reduce((s,r)=>s+r.amount,0));
        ctx.fillStyle='#fff'; ctx.font='16px sans-serif';
        ctx.fillText(`总积分:${totalPoints}`,30,120);
        ctx.fillText(`本周赚取:+${earn}  扣取:-${deduct}`,30,160);
        ctx.fillText(`成就:${unlockedAchievements.length}个`,30,200);
        canvas.toBlob(blob=>{
            const url=URL.createObjectURL(blob); const a=document.createElement('a'); a.href=url; a.download='战报.png'; a.click();
        });
    }

    document.querySelectorAll('.modal').forEach(m=>{m.addEventListener('click',function(e){if(e.target===this)this.classList.remove('show');});});
    document.addEventListener('DOMContentLoaded',()=>{initData();loadHome();});
</script>
</body>
</html>
打包不难,功能太简单了 待迭代

免费评分

参与人数 2热心值 +2 收起 理由
海门人 + 1 网页版打开黑球球的,走都看不清
weidechan + 1 谢谢@Thanks!

查看全部评分

Piz.liu 发表于 2026-6-16 19:28
我用夸克网盘分享了「app-debug.apk」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:https://pan.quark.cn/s/738b41cd141a

codex打的包,试试
kan2009 发表于 2026-6-16 17:31
非常不错......
Laurenceo278 发表于 2026-6-16 17:37
坐等封装
一丝风 发表于 2026-6-16 17:38
不错哦哦
杜先森 发表于 2026-6-16 17:45
坐等大佬!
星峰 发表于 2026-6-16 17:56
https://www.52pojie.cn/thread-2113082-1-1.html
这个软件可以将本地网页转APP
 楼主| 跳墙的爷 发表于 2026-6-16 19:07
星峰 发表于 2026-6-16 17:56
https://www.52pojie.cn/thread-2113082-1-1.html
这个软件可以将本地网页转APP

这个我用过,之前把在线网页转app,也能离线转吗,我去试试
Piz.liu 发表于 2026-6-16 19:31
这应该分成家装端和儿童端,儿童端完成任务,给家长申请,家长同意添加积分,然后比如孩子用积分换20分钟电视,控制路由器,定时断开电视网络,玩平板,定时解除应用使用限制
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-7-10 19:36

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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