首页 / 应用软件 / 实战教程,在网站中添加在线个人习惯追踪与目标管理小程序

实战教程,在网站中添加在线个人习惯追踪与目标管理小程序

实战教程:在WordPress网站中添加在线个人习惯追踪与目标管理小程序

引言:为什么网站需要个人习惯追踪功能?

在当今快节奏的数字时代,个人效率管理和习惯养成已成为许多人关注的焦点。研究表明,习惯追踪能够提高目标达成率高达42%,而将这一功能集成到个人或专业网站中,不仅能提升用户体验,还能增加网站粘性和实用价值。

WordPress作为全球最流行的内容管理系统,其强大的可扩展性使其成为实现此类功能的理想平台。本教程将指导您通过代码二次开发,在WordPress网站中集成一个完整的在线个人习惯追踪与目标管理小程序,让您的网站从单纯的内容展示平台转变为实用的个人成长工具。

第一部分:项目规划与准备工作

1.1 功能需求分析

在开始编码之前,我们需要明确小程序的核心功能:

  1. 用户习惯管理:创建、编辑、删除个人习惯
  2. 进度追踪:每日习惯打卡与进度可视化
  3. 目标设定:短期与长期目标管理
  4. 数据统计:习惯坚持率、完成趋势分析
  5. 提醒功能:邮件或站内消息提醒
  6. 社交分享:成就分享到社交媒体
  7. 数据导出:支持CSV格式数据导出

1.2 技术栈选择

  • 前端:HTML5、CSS3、JavaScript (使用Vue.js或React简化开发)
  • 后端:PHP (WordPress原生支持)
  • 数据库:MySQL (WordPress数据库)
  • 图表库:Chart.js 或 Google Charts
  • 日期处理:Moment.js
  • 开发环境:本地WordPress安装或开发服务器

1.3 开发环境搭建

  1. 安装本地服务器环境(如XAMPP、MAMP或Local by Flywheel)
  2. 下载最新版WordPress并完成安装
  3. 创建子主题或自定义插件目录结构
  4. 安装代码编辑器(如VS Code)并配置PHP开发环境

第二部分:数据库设计与数据模型

2.1 自定义数据库表设计

为了存储习惯追踪数据,我们需要在WordPress数据库中添加几个自定义表:

-- 习惯表
CREATE TABLE wp_habits (
    habit_id INT AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT(20) UNSIGNED NOT NULL,
    habit_name VARCHAR(255) NOT NULL,
    habit_description TEXT,
    habit_category VARCHAR(100),
    frequency ENUM('daily', 'weekly', 'monthly') DEFAULT 'daily',
    target_days INT DEFAULT 7,
    start_date DATE NOT NULL,
    end_date DATE,
    color_code VARCHAR(7) DEFAULT '#3498db',
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES wp_users(ID)
);

-- 习惯记录表
CREATE TABLE wp_habit_logs (
    log_id INT AUTO_INCREMENT PRIMARY KEY,
    habit_id INT NOT NULL,
    user_id BIGINT(20) UNSIGNED NOT NULL,
    log_date DATE NOT NULL,
    status ENUM('completed', 'skipped', 'failed') DEFAULT 'completed',
    notes TEXT,
    duration INT COMMENT '完成习惯所用时间(分钟)',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY unique_habit_date (habit_id, log_date),
    FOREIGN KEY (habit_id) REFERENCES wp_habits(habit_id),
    FOREIGN KEY (user_id) REFERENCES wp_users(ID)
);

-- 目标表
CREATE TABLE wp_goals (
    goal_id INT AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT(20) UNSIGNED NOT NULL,
    goal_name VARCHAR(255) NOT NULL,
    goal_description TEXT,
    goal_type ENUM('habit_based', 'milestone', 'quantitative') DEFAULT 'habit_based',
    target_value DECIMAL(10,2),
    current_value DECIMAL(10,2) DEFAULT 0,
    start_date DATE NOT NULL,
    target_date DATE,
    status ENUM('active', 'completed', 'abandoned') DEFAULT 'active',
    related_habit_id INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES wp_users(ID),
    FOREIGN KEY (related_habit_id) REFERENCES wp_habits(habit_id)
);

2.2 WordPress数据表集成策略

虽然我们创建了自定义表,但仍需确保与WordPress用户系统的无缝集成:

  1. 使用WordPress的$wpdb类进行数据库操作
  2. 利用WordPress的用户认证系统
  3. 遵循WordPress的数据转义和安全规范
  4. 考虑使用自定义Post Type作为替代方案(适合简单需求)

第三部分:创建WordPress插件框架

3.1 插件基础结构

创建插件目录wp-content/plugins/habit-tracker/,并添加以下文件:

<?php
/*
Plugin Name: 个人习惯追踪与目标管理
Plugin URI: https://yourwebsite.com/habit-tracker
Description: 在WordPress网站中添加在线个人习惯追踪与目标管理功能
Version: 1.0.0
Author: 您的名称
License: GPL v2 or later
Text Domain: habit-tracker
*/

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

// 定义插件常量
define('HABIT_TRACKER_VERSION', '1.0.0');
define('HABIT_TRACKER_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('HABIT_TRACKER_PLUGIN_URL', plugin_dir_url(__FILE__));

// 数据库表版本
define('HABIT_TRACKER_DB_VERSION', '1.0');

// 包含必要文件
require_once HABIT_TRACKER_PLUGIN_DIR . 'includes/class-database.php';
require_once HABIT_TRACKER_PLUGIN_DIR . 'includes/class-habit-tracker.php';
require_once HABIT_TRACKER_PLUGIN_DIR . 'includes/class-shortcodes.php';
require_once HABIT_TRACKER_PLUGIN_DIR . 'includes/class-ajax-handler.php';

// 初始化插件
function habit_tracker_init() {
    $plugin = new Habit_Tracker();
    $plugin->run();
}
add_action('plugins_loaded', 'habit_tracker_init');

// 激活插件时创建数据库表
register_activation_hook(__FILE__, array('Habit_Tracker_Database', 'create_tables'));

// 停用插件时的清理操作
register_deactivation_hook(__FILE__, array('Habit_Tracker_Database', 'cleanup'));

3.2 数据库操作类

创建includes/class-database.php文件:

<?php
class Habit_Tracker_Database {
    
    private static $table_prefix;
    
    public static function init() {
        global $wpdb;
        self::$table_prefix = $wpdb->prefix . 'habit_';
    }
    
    // 创建数据库表
    public static function create_tables() {
        global $wpdb;
        
        $charset_collate = $wpdb->get_charset_collate();
        
        $sql = array();
        
        // 创建习惯表
        $sql[] = "CREATE TABLE " . self::$table_prefix . "habits (
            habit_id INT AUTO_INCREMENT PRIMARY KEY,
            user_id BIGINT(20) UNSIGNED NOT NULL,
            habit_name VARCHAR(255) NOT NULL,
            habit_description TEXT,
            habit_category VARCHAR(100),
            frequency ENUM('daily', 'weekly', 'monthly') DEFAULT 'daily',
            target_days INT DEFAULT 7,
            start_date DATE NOT NULL,
            end_date DATE,
            color_code VARCHAR(7) DEFAULT '#3498db',
            is_active BOOLEAN DEFAULT TRUE,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        ) $charset_collate;";
        
        // 创建习惯记录表
        $sql[] = "CREATE TABLE " . self::$table_prefix . "logs (
            log_id INT AUTO_INCREMENT PRIMARY KEY,
            habit_id INT NOT NULL,
            user_id BIGINT(20) UNSIGNED NOT NULL,
            log_date DATE NOT NULL,
            status ENUM('completed', 'skipped', 'failed') DEFAULT 'completed',
            notes TEXT,
            duration INT COMMENT '完成习惯所用时间(分钟)',
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            UNIQUE KEY unique_habit_date (habit_id, log_date)
        ) $charset_collate;";
        
        // 创建目标表
        $sql[] = "CREATE TABLE " . self::$table_prefix . "goals (
            goal_id INT AUTO_INCREMENT PRIMARY KEY,
            user_id BIGINT(20) UNSIGNED NOT NULL,
            goal_name VARCHAR(255) NOT NULL,
            goal_description TEXT,
            goal_type ENUM('habit_based', 'milestone', 'quantitative') DEFAULT 'habit_based',
            target_value DECIMAL(10,2),
            current_value DECIMAL(10,2) DEFAULT 0,
            start_date DATE NOT NULL,
            target_date DATE,
            status ENUM('active', 'completed', 'abandoned') DEFAULT 'active',
            related_habit_id INT,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        ) $charset_collate;";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        
        foreach ($sql as $query) {
            dbDelta($query);
        }
        
        add_option('habit_tracker_db_version', HABIT_TRACKER_DB_VERSION);
    }
    
    // 获取用户的所有习惯
    public static function get_user_habits($user_id, $active_only = true) {
        global $wpdb;
        
        $table_name = self::$table_prefix . 'habits';
        $condition = $active_only ? " AND is_active = 1" : "";
        
        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM $table_name WHERE user_id = %d $condition ORDER BY created_at DESC",
                $user_id
            )
        );
    }
    
    // 添加更多数据库操作方法...
}

第四部分:前端界面开发

4.1 主界面HTML结构

创建templates/dashboard.php文件:

<div class="habit-tracker-container">
    <div class="habit-tracker-header">
        <h1>个人习惯追踪与目标管理</h1>
        <div class="date-navigation">
            <button class="prev-date">← 前一天</button>
            <span class="current-date"><?php echo date('Y年m月d日'); ?></span>
            <button class="next-date">后一天 →</button>
        </div>
    </div>
    
    <div class="habit-tracker-main">
        <!-- 左侧习惯管理区域 -->
        <div class="habits-section">
            <div class="section-header">
                <h2>我的习惯</h2>
                <button class="btn-add-habit">+ 添加新习惯</button>
            </div>
            
            <div class="habits-list">
                <!-- 习惯项将通过JavaScript动态加载 -->
                <div class="loading-habits">加载习惯中...</div>
            </div>
            
            <div class="habits-stats">
                <div class="stat-card">
                    <div class="stat-value" id="current-streak">0</div>
                    <div class="stat-label">当前连续天数</div>
                </div>
                <div class="stat-card">
                    <div class="stat-value" id="completion-rate">0%</div>
                    <div class="stat-label">本月完成率</div>
                </div>
                <div class="stat-card">
                    <div class="stat-value" id="total-habits">0</div>
                    <div class="stat-label">活跃习惯</div>
                </div>
            </div>
        </div>
        
        <!-- 右侧目标与统计区域 -->
        <div class="goals-stats-section">
            <div class="goals-section">
                <div class="section-header">
                    <h2>我的目标</h2>
                    <button class="btn-add-goal">+ 添加新目标</button>
                </div>
                
                <div class="goals-list">
                    <!-- 目标项将通过JavaScript动态加载 -->
                </div>
            </div>
            
            <div class="stats-section">
                <div class="section-header">
                    <h2>习惯统计</h2>
                    <select id="stats-period">
                        <option value="week">本周</option>
                        <option value="month" selected>本月</option>
                        <option value="year">今年</option>
                        <option value="all">全部</option>
                    </select>
                </div>
                
                <div class="charts-container">
                    <canvas id="completionChart" width="400" height="200"></canvas>
                    <canvas id="categoryChart" width="400" height="200"></canvas>
                </div>
            </div>
        </div>
    </div>
    
    <!-- 添加习惯模态框 -->
    <div class="modal" id="addHabitModal">
        <div class="modal-content">
            <span class="close-modal">&times;</span>
            <h3>添加新习惯</h3>
            <form id="habitForm">
                <div class="form-group">
                    <label for="habitName">习惯名称 *</label>
                    <input type="text" id="habitName" name="habit_name" required>
                </div>
                <div class="form-group">
                    <label for="habitDescription">习惯描述</label>
                    <textarea id="habitDescription" name="habit_description" rows="3"></textarea>
                </div>
                <div class="form-row">
                    <div class="form-group">
                        <label for="habitCategory">分类</label>
                        <select id="habitCategory" name="habit_category">
                            <option value="health">健康</option>
                            <option value="work">工作</option>
                            <option value="learning">学习</option>
                            <option value="finance">财务</option>
                            <option value="relationship">人际关系</option>
                            <option value="hobby">兴趣爱好</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label for="habitFrequency">频率</label>
                        <select id="habitFrequency" name="frequency">
                            <option value="daily">每日</option>
                            <option value="weekly">每周</option>
                            <option value="monthly">每月</option>
                        </select>
                    </div>
                </div>
                <div class="form-row">
                    <div class="form-group">
                        <label for="targetDays">目标天数 (周)</label>
                        <input type="number" id="targetDays" name="target_days" min="1" max="7" value="7">
                    </div>
                    <div class="form-group">
                        <label for="habitColor">颜色标识</label>
                        <input type="color" id="habitColor" name="color_code" value="#3498db">
                    </div>
                </div>
                <div class="form-actions">
                    <button type="button" class="btn-cancel">取消</button>
                    <button type="submit" class="btn-submit">创建习惯</button>
                </div>
            </form>
        </div>
    </div>
</div>

4.2 CSS样式设计

创建assets/css/habit-tracker.css文件:

/* 主容器样式 */
.habit-tracker-container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
}

.habit-tracker-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 30px;
    padding-bottom: 20px;
    border-bottom: 1px solid #eaeaea;
}

.habit-tracker-header h1 {
    margin: 0;
    color: #2c3e50;
    font-size: 28px;
}

.date-navigation {
    display: flex;
    align-items: center;
    gap: 15px;
}

.date-navigation button {
    background: #f8f9fa;
    border: 1px solid #ddd;
    padding: 8px 15px;
    border-radius: 4px;
    cursor: pointer;
    transition: all 0.3s;
}

.date-navigation button:hover {
    background: #e9ecef;
}

.current-date {
    font-weight: 600;
    color: #495057;
}

/* 主内容区域 */
.habit-tracker-main {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 30px;
}

@media (max-width: 992px) {
    .habit-tracker-main {
        grid-template-columns: 1fr;
    }
}

/* 习惯列表样式 */
.habits-section, .goals-section, .stats-section {
    background: white;
    border-radius: 8px;
    padding: 25px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.08);
}

.section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 25px;
}

.section-header h2 {
    margin: 0;
    color: #2c3e50;
    font-size: 22px;
}

.btn-add-habit, .btn-add-goal {
    background: #3498db;
    color: white;
    border: none;
    padding: 10px 20px;
    border-radius: 4px;
    cursor: pointer;
    font-weight: 600;
    transition: background 0.3s;
}

.btn-add-habit:hover, .btn-add-goal:hover {
    background: #2980b9;
}

/* 习惯项样式 */
.habit-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 15px;
    margin-bottom: 15px;
    border-radius: 6px;
    background: #f8f9fa;
    border-left: 4px solid #3498db;
    transition: transform 0.2s;
}

.habit-item:hover {
    transform: translateY(-2px);

(接上文)

.habit-info {
    flex: 1;
}

.habit-name {
    font-weight: 600;
    color: #2c3e50;
    margin-bottom: 5px;
    font-size: 16px;
}

.habit-meta {
    display: flex;
    gap: 15px;
    font-size: 14px;
    color: #6c757d;
}

.habit-category {
    background: #e9ecef;
    padding: 2px 8px;
    border-radius: 12px;
    font-size: 12px;
}

.habit-actions {
    display: flex;
    gap: 10px;
    align-items: center;
}

.check-habit {
    width: 24px;
    height: 24px;
    border: 2px solid #dee2e6;
    border-radius: 50%;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.3s;
}

.check-habit.checked {
    background: #28a745;
    border-color: #28a745;
    color: white;
}

.check-habit.checked::after {
    content: "✓";
    font-size: 14px;
}

/* 统计卡片样式 */
.habits-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 15px;
    margin-top: 25px;
}

.stat-card {
    background: white;
    border-radius: 8px;
    padding: 20px;
    text-align: center;
    box-shadow: 0 2px 5px rgba(0,0,0,0.05);
    border: 1px solid #eaeaea;
}

.stat-value {
    font-size: 32px;
    font-weight: 700;
    color: #3498db;
    margin-bottom: 5px;
}

.stat-label {
    font-size: 14px;
    color: #6c757d;
}

/* 目标项样式 */
.goal-item {
    padding: 15px;
    margin-bottom: 15px;
    background: #f8f9fa;
    border-radius: 6px;
    border-left: 4px solid #9b59b6;
}

.goal-progress {
    margin-top: 10px;
}

.progress-bar {
    height: 8px;
    background: #e9ecef;
    border-radius: 4px;
    overflow: hidden;
}

.progress-fill {
    height: 100%;
    background: linear-gradient(90deg, #9b59b6, #8e44ad);
    border-radius: 4px;
    transition: width 0.5s ease;
}

.goal-details {
    display: flex;
    justify-content: space-between;
    margin-top: 5px;
    font-size: 14px;
    color: #6c757d;
}

/* 图表容器 */
.charts-container {
    margin-top: 20px;
}

.charts-container canvas {
    max-width: 100%;
    margin-bottom: 20px;
}

/* 模态框样式 */
.modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.5);
    z-index: 1000;
    align-items: center;
    justify-content: center;
}

.modal-content {
    background: white;
    border-radius: 8px;
    width: 90%;
    max-width: 500px;
    padding: 30px;
    position: relative;
    animation: modalSlideIn 0.3s ease;
}

@keyframes modalSlideIn {
    from {
        opacity: 0;
        transform: translateY(-50px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.close-modal {
    position: absolute;
    top: 15px;
    right: 20px;
    font-size: 24px;
    cursor: pointer;
    color: #6c757d;
}

.close-modal:hover {
    color: #343a40;
}

/* 表单样式 */
.form-group {
    margin-bottom: 20px;
}

.form-group label {
    display: block;
    margin-bottom: 8px;
    font-weight: 600;
    color: #495057;
}

.form-group input[type="text"],
.form-group input[type="number"],
.form-group select,
.form-group textarea {
    width: 100%;
    padding: 10px;
    border: 1px solid #ced4da;
    border-radius: 4px;
    font-size: 16px;
    transition: border-color 0.3s;
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
    outline: none;
    border-color: #3498db;
    box-shadow: 0 0 0 3px rgba(52,152,219,0.1);
}

.form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
}

.form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 15px;
    margin-top: 30px;
}

.btn-cancel, .btn-submit {
    padding: 12px 25px;
    border-radius: 4px;
    font-weight: 600;
    cursor: pointer;
    border: none;
    transition: all 0.3s;
}

.btn-cancel {
    background: #f8f9fa;
    color: #6c757d;
    border: 1px solid #dee2e6;
}

.btn-cancel:hover {
    background: #e9ecef;
}

.btn-submit {
    background: #3498db;
    color: white;
}

.btn-submit:hover {
    background: #2980b9;
}

/* 响应式调整 */
@media (max-width: 768px) {
    .habit-tracker-header {
        flex-direction: column;
        align-items: flex-start;
        gap: 15px;
    }
    
    .form-row {
        grid-template-columns: 1fr;
    }
    
    .habits-stats {
        grid-template-columns: 1fr;
    }
}

第五部分:JavaScript交互功能

5.1 主JavaScript文件

创建assets/js/habit-tracker.js文件:

// 习惯追踪器主应用
class HabitTracker {
    constructor() {
        this.currentDate = new Date();
        this.habits = [];
        this.goals = [];
        this.stats = {};
        
        this.init();
    }
    
    init() {
        // 绑定事件监听器
        this.bindEvents();
        
        // 加载初始数据
        this.loadUserData();
        
        // 初始化图表
        this.initCharts();
    }
    
    bindEvents() {
        // 日期导航
        document.querySelector('.prev-date')?.addEventListener('click', () => this.changeDate(-1));
        document.querySelector('.next-date')?.addEventListener('click', () => this.changeDate(1));
        
        // 添加习惯按钮
        document.querySelector('.btn-add-habit')?.addEventListener('click', () => this.showAddHabitModal());
        
        // 模态框关闭
        document.querySelector('.close-modal')?.addEventListener('click', () => this.hideModal());
        document.querySelector('.btn-cancel')?.addEventListener('click', () => this.hideModal());
        
        // 习惯表单提交
        document.getElementById('habitForm')?.addEventListener('submit', (e) => this.handleAddHabit(e));
        
        // 统计周期选择
        document.getElementById('stats-period')?.addEventListener('change', (e) => this.updateStats(e.target.value));
        
        // 点击模态框外部关闭
        document.querySelector('.modal')?.addEventListener('click', (e) => {
            if (e.target.classList.contains('modal')) {
                this.hideModal();
            }
        });
    }
    
    // 加载用户数据
    async loadUserData() {
        try {
            // 加载习惯
            const habitsResponse = await this.ajaxRequest('get_user_habits');
            this.habits = habitsResponse.data || [];
            
            // 加载目标
            const goalsResponse = await this.ajaxRequest('get_user_goals');
            this.goals = goalsResponse.data || [];
            
            // 加载今日习惯状态
            const todayStatus = await this.ajaxRequest('get_today_status');
            
            // 渲染数据
            this.renderHabits();
            this.renderGoals();
            this.updateStats('month');
            
        } catch (error) {
            console.error('加载数据失败:', error);
            this.showMessage('加载数据失败,请刷新页面重试', 'error');
        }
    }
    
    // 渲染习惯列表
    renderHabits() {
        const habitsList = document.querySelector('.habits-list');
        if (!habitsList) return;
        
        if (this.habits.length === 0) {
            habitsList.innerHTML = `
                <div class="empty-state">
                    <p>还没有添加任何习惯</p>
                    <button class="btn-add-habit">添加第一个习惯</button>
                </div>
            `;
            return;
        }
        
        let html = '';
        this.habits.forEach(habit => {
            const isChecked = habit.today_status === 'completed';
            html += `
                <div class="habit-item" data-habit-id="${habit.habit_id}" style="border-left-color: ${habit.color_code}">
                    <div class="habit-info">
                        <div class="habit-name">${habit.habit_name}</div>
                        <div class="habit-meta">
                            <span class="habit-category">${this.getCategoryName(habit.habit_category)}</span>
                            <span>已坚持 ${habit.current_streak || 0} 天</span>
                            <span>${habit.completion_rate || 0}% 完成率</span>
                        </div>
                    </div>
                    <div class="habit-actions">
                        <div class="check-habit ${isChecked ? 'checked' : ''}" 
                             onclick="habitTracker.toggleHabit(${habit.habit_id})">
                        </div>
                        <button class="btn-habit-detail" onclick="habitTracker.showHabitDetail(${habit.habit_id})">
                            详情
                        </button>
                    </div>
                </div>
            `;
        });
        
        habitsList.innerHTML = html;
        
        // 更新统计卡片
        this.updateStatCards();
    }
    
    // 渲染目标列表
    renderGoals() {
        const goalsList = document.querySelector('.goals-list');
        if (!goalsList) return;
        
        if (this.goals.length === 0) {
            goalsList.innerHTML = `
                <div class="empty-state">
                    <p>还没有设置任何目标</p>
                    <button class="btn-add-goal">添加第一个目标</button>
                </div>
            `;
            return;
        }
        
        let html = '';
        this.goals.forEach(goal => {
            const progress = goal.target_value > 0 ? (goal.current_value / goal.target_value * 100) : 0;
            const progressPercent = Math.min(100, Math.round(progress));
            
            html += `
                <div class="goal-item" data-goal-id="${goal.goal_id}">
                    <div class="goal-info">
                        <div class="goal-name">${goal.goal_name}</div>
                        <div class="goal-description">${goal.goal_description || ''}</div>
                    </div>
                    <div class="goal-progress">
                        <div class="progress-bar">
                            <div class="progress-fill" style="width: ${progressPercent}%"></div>
                        </div>
                        <div class="goal-details">
                            <span>${goal.current_value} / ${goal.target_value}</span>
                            <span>${progressPercent}%</span>
                        </div>
                    </div>
                </div>
            `;
        });
        
        goalsList.innerHTML = html;
    }
    
    // 切换习惯完成状态
    async toggleHabit(habitId) {
        try {
            const response = await this.ajaxRequest('toggle_habit_status', {
                habit_id: habitId,
                date: this.formatDate(this.currentDate)
            });
            
            if (response.success) {
                // 更新本地数据
                const habit = this.habits.find(h => h.habit_id == habitId);
                if (habit) {
                    habit.today_status = habit.today_status === 'completed' ? null : 'completed';
                    habit.current_streak = response.data.current_streak;
                    habit.completion_rate = response.data.completion_rate;
                }
                
                // 重新渲染
                this.renderHabits();
                this.updateStats();
                
                this.showMessage('习惯状态已更新', 'success');
            }
        } catch (error) {
            console.error('更新习惯状态失败:', error);
            this.showMessage('更新失败,请重试', 'error');
        }
    }
    
    // 显示添加习惯模态框
    showAddHabitModal() {
        const modal = document.getElementById('addHabitModal');
        if (modal) {
            modal.style.display = 'flex';
            document.getElementById('habitName').focus();
        }
    }
    
    // 隐藏模态框
    hideModal() {
        const modal = document.getElementById('addHabitModal');
        if (modal) {
            modal.style.display = 'none';
            document.getElementById('habitForm').reset();
        }
    }
    
    // 处理添加习惯表单提交
    async handleAddHabit(e) {
        e.preventDefault();
        
        const formData = new FormData(e.target);
        const habitData = {
            habit_name: formData.get('habit_name'),
            habit_description: formData.get('habit_description'),
            habit_category: formData.get('habit_category'),
            frequency: formData.get('frequency'),
            target_days: parseInt(formData.get('target_days')),
            color_code: formData.get('color_code'),
            start_date: this.formatDate(new Date())
        };
        
        try {
            const response = await this.ajaxRequest('add_habit', habitData);
            
            if (response.success) {
                // 添加新习惯到列表
                this.habits.unshift(response.data);
                
                // 重新渲染
                this.renderHabits();
                this.hideModal();
                
                this.showMessage('习惯添加成功', 'success');
            }
        } catch (error) {
            console.error('添加习惯失败:', error);
            this.showMessage('添加失败,请重试', 'error');
        }
    }
    
    // 更新统计卡片
    updateStatCards() {
        if (this.habits.length === 0) return;
        
        // 计算最长连续天数
        const longestStreak = Math.max(...this.habits.map(h => h.current_streak || 0));
        
        // 计算本月完成率
        const completedHabits = this.habits.filter(h => h.today_status === 'completed').length;
        const completionRate = this.habits.length > 0 ? 
            Math.round((completedHabits / this.habits.length) * 100) : 0;
        
        // 更新DOM
        document.getElementById('current-streak').textContent = longestStreak;
        document.getElementById('completion-rate').textContent = `${completionRate}%`;
        document.getElementById('total-habits').textContent = this.habits.length;
    }
    
    // 更新统计图表
    async updateStats(period = 'month') {
        try {
            const response = await this.ajaxRequest('get_stats', { period });
            this.stats = response.data || {};
            
            this.updateCharts();
        } catch (error) {
            console.error('加载统计数据失败:', error);
        }
    }
    
    // 初始化图表
    initCharts() {
        // 完成率图表
        const completionCtx = document.getElementById('completionChart')?.getContext('2d');
        if (completionCtx) {
            this.completionChart = new Chart(completionCtx, {
                type: 'line',
                data: {
                    labels: [],
                    datasets: [{
                        label: '完成率',
                        data: [],
                        borderColor: '#3498db',
                        backgroundColor: 'rgba(52, 152, 219, 0.1)',
                        fill: true,
                        tension: 0.4
                    }]
                },
                options: {
                    responsive: true,
                    plugins: {
                        legend: {
                            display: false
                        }
                    },
                    scales: {
                        y: {
                            beginAtZero: true,
                            max: 100,
                            ticks: {
                                callback: function(value) {
                                    return value + '%';
                                }
                            }
                        }
                    }
                }
            });
        }
        
        // 分类分布图表
        const categoryCtx = document.getElementById('categoryChart')?.getContext('2d');
        if (categoryCtx) {
            this.categoryChart = new Chart(categoryCtx, {
                type: 'doughnut',
                data: {
                    labels: [],
                    datasets: [{
                        data: [],
                        backgroundColor: [
                            '#3498db', '#2ecc71', '#9b59b6', 
                            '#e74c3c', '#f39c12', '#1abc9c'
                        ]
                    }]
                },
                options: {
                    responsive: true,
                    plugins: {
                        legend: {
                            position: 'bottom'
                        }
                    }
                }
            });
        }
    }
    
    // 更新图表数据
    updateCharts() {
        // 更新完成率图表
        if (this.completionChart && this.stats.completion_trend) {
            const trend = this.stats.completion_trend;
            this.completionChart.data.labels = trend.labels;
            this.completionChart.data.datasets[0].data = trend.data;
            this.completionChart.update();
        }
        
        // 更新分类分布图表
        if (this.categoryChart && this.stats.category_distribution) {
            const distribution = this.stats.category_distribution;
            this.categoryChart.data.labels = distribution.labels;
            this.categoryChart.data.datasets[0].data = distribution.data;
            this.categoryChart.update();
        }
    }
    
    // 辅助方法:AJAX请求
    async ajaxRequest(action, data = {}) {
        return new Promise((resolve, reject) => {
            jQuery.ajax({
                url: habitTrackerAjax.ajax_url,
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5365.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部