首页 / 教程文章 / WordPress文创项目柔性众筹插件开发详解

WordPress文创项目柔性众筹插件开发详解

WordPress文创项目柔性众筹插件开发详解

一、项目背景与需求分析

随着文创产业的蓬勃发展,越来越多的创作者需要灵活的资金支持方式。传统的众筹平台往往采用"全有或全无"的固定模式,缺乏灵活性。为此,我们开发了一款WordPress柔性众筹插件,允许创作者设置弹性目标,按实际筹集金额比例交付回报。

核心需求:

  1. 支持弹性目标设置(最低目标、理想目标、超额目标)
  2. 多种支付方式集成(支付宝、微信支付、银行卡)
  3. 多级回报体系
  4. 实时进度展示
  5. 后台管理界面
  6. 数据统计与分析

二、插件架构设计

2.1 数据库设计

<?php
/**
 * 创建插件所需数据表
 * 在插件激活时执行
 */
function flexible_crowdfunding_create_tables() {
    global $wpdb;
    
    $charset_collate = $wpdb->get_charset_collate();
    $table_prefix = $wpdb->prefix . 'fc_';
    
    // 项目表
    $projects_table = $table_prefix . 'projects';
    $projects_sql = "CREATE TABLE IF NOT EXISTS $projects_table (
        id INT(11) NOT NULL AUTO_INCREMENT,
        post_id INT(11) NOT NULL,
        creator_id INT(11) NOT NULL,
        title VARCHAR(255) NOT NULL,
        description TEXT,
        min_target DECIMAL(10,2) DEFAULT 0.00,
        ideal_target DECIMAL(10,2) DEFAULT 0.00,
        stretch_target DECIMAL(10,2) DEFAULT 0.00,
        current_amount DECIMAL(10,2) DEFAULT 0.00,
        start_date DATETIME,
        end_date DATETIME,
        status ENUM('draft', 'active', 'completed', 'failed') DEFAULT 'draft',
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        INDEX idx_post_id (post_id),
        INDEX idx_status (status)
    ) $charset_collate;";
    
    // 支持记录表
    $backers_table = $table_prefix . 'backers';
    $backers_sql = "CREATE TABLE IF NOT EXISTS $backers_table (
        id INT(11) NOT NULL AUTO_INCREMENT,
        project_id INT(11) NOT NULL,
        user_id INT(11),
        anonymous_name VARCHAR(100),
        amount DECIMAL(10,2) NOT NULL,
        reward_id INT(11),
        payment_method VARCHAR(50),
        transaction_id VARCHAR(100),
        status ENUM('pending', 'completed', 'refunded') DEFAULT 'pending',
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        INDEX idx_project_id (project_id),
        INDEX idx_user_id (user_id),
        INDEX idx_status (status)
    ) $charset_collate;";
    
    // 回报等级表
    $rewards_table = $table_prefix . 'rewards';
    $rewards_sql = "CREATE TABLE IF NOT EXISTS $rewards_table (
        id INT(11) NOT NULL AUTO_INCREMENT,
        project_id INT(11) NOT NULL,
        title VARCHAR(255) NOT NULL,
        description TEXT,
        amount DECIMAL(10,2) NOT NULL,
        limit_count INT(11) DEFAULT 0,
        claimed_count INT(11) DEFAULT 0,
        delivery_date DATE,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        INDEX idx_project_id (project_id)
    ) $charset_collate;";
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($projects_sql);
    dbDelta($backers_sql);
    dbDelta($rewards_sql);
}
register_activation_hook(__FILE__, 'flexible_crowdfunding_create_tables');
?>

2.2 插件主类结构

<?php
/**
 * 柔性众筹插件主类
 */
class Flexible_Crowdfunding_Plugin {
    
    private static $instance = null;
    
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function __construct() {
        $this->init_hooks();
    }
    
    /**
     * 初始化WordPress钩子
     */
    private function init_hooks() {
        // 注册自定义文章类型
        add_action('init', array($this, 'register_crowdfunding_post_type'));
        
        // 添加管理菜单
        add_action('admin_menu', array($this, 'add_admin_menu'));
        
        // 注册短代码
        add_shortcode('crowdfunding_project', array($this, 'render_project_shortcode'));
        
        // 注册AJAX处理
        add_action('wp_ajax_support_project', array($this, 'handle_support_ajax'));
        add_action('wp_ajax_nopriv_support_project', array($this, 'handle_support_ajax'));
        
        // 添加CSS和JS
        add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets'));
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
    }
    
    /**
     * 注册众筹项目自定义文章类型
     */
    public function register_crowdfunding_post_type() {
        $labels = array(
            'name'               => '众筹项目',
            'singular_name'      => '众筹项目',
            'menu_name'          => '文创众筹',
            'add_new'            => '添加项目',
            'add_new_item'       => '添加新项目',
            'edit_item'          => '编辑项目',
            'new_item'           => '新项目',
            'view_item'          => '查看项目',
            'search_items'       => '搜索项目',
            'not_found'          => '未找到项目',
            'not_found_in_trash' => '回收站中无项目'
        );
        
        $args = array(
            'labels'             => $labels,
            'public'            => true,
            'publicly_queryable'=> true,
            'show_ui'           => true,
            'show_in_menu'      => true,
            'query_var'         => true,
            'rewrite'           => array('slug' => 'crowdfunding'),
            'capability_type'   => 'post',
            'has_archive'       => true,
            'hierarchical'      => false,
            'menu_position'     => 5,
            'menu_icon'         => 'dashicons-heart',
            'supports'          => array('title', 'editor', 'thumbnail', 'excerpt', 'comments'),
            'show_in_rest'      => true
        );
        
        register_post_type('crowdfunding_project', $args);
    }
    
    // 其他方法将在后续章节实现
}
?>

三、前端展示模块开发

3.1 项目展示短代码

<?php
/**
 * 渲染众筹项目短代码
 * @param array $atts 短代码属性
 * @return string HTML内容
 */
public function render_project_shortcode($atts) {
    // 解析短代码属性
    $atts = shortcode_atts(array(
        'id' => 0,
        'show_progress' => true,
        'show_backers' => true,
        'show_rewards' => true
    ), $atts, 'crowdfunding_project');
    
    // 获取项目数据
    $project_id = intval($atts['id']);
    if ($project_id <= 0) {
        return '<div class="fc-error">无效的项目ID</div>';
    }
    
    global $wpdb;
    $table_name = $wpdb->prefix . 'fc_projects';
    $project = $wpdb->get_row($wpdb->prepare(
        "SELECT * FROM $table_name WHERE post_id = %d",
        $project_id
    ));
    
    if (!$project) {
        return '<div class="fc-error">项目不存在</div>';
    }
    
    // 计算进度百分比
    $progress_percentage = 0;
    if ($project->ideal_target > 0) {
        $progress_percentage = min(100, ($project->current_amount / $project->ideal_target) * 100);
    }
    
    // 计算剩余天数
    $days_left = 0;
    if ($project->end_date) {
        $end_date = new DateTime($project->end_date);
        $now = new DateTime();
        if ($end_date > $now) {
            $days_left = $end_date->diff($now)->days;
        }
    }
    
    ob_start();
    ?>
    <div class="fc-project-container" data-project-id="<?php echo esc_attr($project_id); ?>">
        
        <!-- 项目标题和描述 -->
        <div class="fc-project-header">
            <h2 class="fc-project-title"><?php echo esc_html($project->title); ?></h2>
            <div class="fc-project-description">
                <?php echo wp_kses_post($project->description); ?>
            </div>
        </div>
        
        <!-- 进度条 -->
        <?php if ($atts['show_progress']): ?>
        <div class="fc-progress-section">
            <div class="fc-progress-stats">
                <div class="fc-amount-raised">
                    <span class="fc-label">已筹集</span>
                    <span class="fc-value">¥<?php echo number_format($project->current_amount, 2); ?></span>
                </div>
                <div class="fc-target-amount">
                    <span class="fc-label">目标金额</span>
                    <span class="fc-value">¥<?php echo number_format($project->ideal_target, 2); ?></span>
                </div>
                <div class="fc-backers-count">
                    <span class="fc-label">支持者</span>
                    <span class="fc-value"><?php echo $this->get_backers_count($project->id); ?></span>
                </div>
                <div class="fc-days-left">
                    <span class="fc-label">剩余时间</span>
                    <span class="fc-value"><?php echo $days_left; ?>天</span>
                </div>
            </div>
            
            <div class="fc-progress-bar-container">
                <div class="fc-progress-bar">
                    <div class="fc-progress-fill" style="width: <?php echo esc_attr($progress_percentage); ?>%;"></div>
                </div>
                <div class="fc-progress-labels">
                    <span>¥<?php echo number_format($project->min_target, 2); ?> (最低)</span>
                    <span>¥<?php echo number_format($project->ideal_target, 2); ?> (理想)</span>
                    <?php if ($project->stretch_target > 0): ?>
                    <span>¥<?php echo number_format($project->stretch_target, 2); ?> (超额)</span>
                    <?php endif; ?>
                </div>
            </div>
        </div>
        <?php endif; ?>
        
        <!-- 支持按钮 -->
        <div class="fc-support-section">
            <button class="fc-support-button" data-action="open-support-modal">
                支持这个项目
            </button>
        </div>
        
        <!-- 回报等级 -->
        <?php if ($atts['show_rewards']): 
            $rewards = $this->get_project_rewards($project->id);
            if ($rewards):
        ?>
        <div class="fc-rewards-section">
            <h3>选择回报</h3>
            <div class="fc-rewards-grid">
                <?php foreach ($rewards as $reward): 
                    $claimed_percentage = 0;
                    if ($reward->limit_count > 0) {
                        $claimed_percentage = ($reward->claimed_count / $reward->limit_count) * 100;
                    }
                ?>
                <div class="fc-reward-card" data-reward-id="<?php echo esc_attr($reward->id); ?>">
                    <div class="fc-reward-header">
                        <h4 class="fc-reward-title"><?php echo esc_html($reward->title); ?></h4>
                        <div class="fc-reward-amount">¥<?php echo number_format($reward->amount, 2); ?></div>
                    </div>
                    <div class="fc-reward-description">
                        <?php echo wp_kses_post($reward->description); ?>
                    </div>
                    <?php if ($reward->limit_count > 0): ?>
                    <div class="fc-reward-limit">
                        <div class="fc-limit-progress">
                            <div class="fc-limit-progress-bar" style="width: <?php echo esc_attr($claimed_percentage); ?>%;"></div>
                        </div>
                        <div class="fc-limit-text">
                            已领取 <?php echo esc_html($reward->claimed_count); ?> / <?php echo esc_html($reward->limit_count); ?>
                        </div>
                    </div>
                    <?php endif; ?>
                    <button class="fc-select-reward" data-reward-id="<?php echo esc_attr($reward->id); ?>">
                        选择此回报
                    </button>
                </div>
                <?php endforeach; ?>
            </div>
        </div>
        <?php endif; endif; ?>
        
    </div>
    
    <!-- 支持模态框 -->
    <div class="fc-modal" id="fc-support-modal">
        <div class="fc-modal-content">
            <span class="fc-modal-close">&times;</span>
            <h3>支持项目</h3>
            <form id="fc-support-form">
                <input type="hidden" name="project_id" value="<?php echo esc_attr($project->id); ?>">
                <input type="hidden" name="reward_id" id="fc-selected-reward" value="0">
                
                <div class="fc-form-group">
                    <label for="fc-support-amount">支持金额 (元)</label>
                    <input type="number" id="fc-support-amount" name="amount" min="1" step="0.01" required>
                </div>
                
                <div class="fc-form-group">
                    <label for="fc-payment-method">支付方式</label>
                    <select id="fc-payment-method" name="payment_method" required>
                        <option value="">请选择支付方式</option>
                        <option value="alipay">支付宝</option>
                        <option value="wechat">微信支付</option>
                        <option value="bank">银行卡</option>
                    </select>
                </div>
                
                <div class="fc-form-group">
                    <label>
                        <input type="checkbox" name="anonymous" value="1">
                        匿名支持
                    </label>
                </div>
                
                <div class="fc-form-group" id="fc-anonymous-name-group" style="display: none;">
                    <label for="fc-anonymous-name">显示名称</label>
                    <input type="text" id="fc-anonymous-name" name="anonymous_name" placeholder="请输入显示名称">
                </div>
                
                <button type="submit" class="fc-submit-button">确认支持</button>
            </form>
        </div>
    </div>
    <?php
    
    return ob_get_clean();
}

/**
 * 获取项目支持者数量
 */
private function get_backers_count($project_id) {
    global $wpdb;
    $table_name = $wpdb->prefix . 'fc_backers';
    return $wpdb->get_var($wpdb->prepare(
        "SELECT COUNT(*) FROM $table_name WHERE project_id = %d AND status = 'completed'",
        $project_id
    ));
}

/**
 * 获取项目回报等级
 */
private function get_project_rewards($project_id) {
    global $wpdb;
    $table_name = $wpdb->prefix . 'fc_rewards';
    return $wpdb->get_results($wpdb->prepare(
        "SELECT * FROM $table_name WHERE project_id = %d ORDER BY amount ASC",
        $project_id
    ));
}
?>

3.2 前端样式与交互

/* 柔性众筹插件前端样式 */
.fc-project-container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
}

.fc-project-header {
    margin-bottom: 30px;
}

.fc-project-title {
    font-size: 2.5rem;
    color: #333;
    margin-bottom: 15px;
}

.fc-project-description {
    font-size: 1.1rem;
    line-height: 1.6;
    color: #666;
}

.fc-progress-section {
    background: #f8f9fa;
    border-radius: 10px;
    padding: 25px;
    margin-bottom: 30px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}

.fc-progress-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 20px;
    margin-bottom: 25px;
}

.fc-progress-stats > div {
    text-align: center;
}

.fc-label {
    display: block;
    font-size: 0.9rem;
    color: #666;
    margin-bottom: 5px;
}

.fc-value {
    display: block;
    font-size: 1.8rem;
    font-weight: bold;
    color: #2c3e50;
}

.fc-progress-bar-container {
    margin-top: 20px;
}

.fc-progress-bar {
    height: 20px;
    background: #e9ecef;
    border-radius: 10px;
    overflow: hidden;
    position: relative;
}

.fc-progress-fill {
    height: 100%;
    background: linear-gradient(90deg, #3498db, #2ecc71);
    border-radius: 10px;
    transition: width 1s ease-in-out;
}

.fc-progress-labels {
    display: flex;
    justify-content: space-between;
    margin-top: 10px;
    font-size: 0.9rem;
    color: #666;
}

.fc-support-section {
.fc-support-button {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    border: none;
    padding: 15px 40px;
    font-size: 1.2rem;
    border-radius: 50px;
    cursor: pointer;
    transition: all 0.3s ease;
    display: block;
    margin: 30px auto;
    box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}

.fc-support-button:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
}

.fc-rewards-section {
    margin-top: 40px;
}

.fc-rewards-section h3 {
    font-size: 1.8rem;
    color: #333;
    margin-bottom: 25px;
    text-align: center;
}

.fc-rewards-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 25px;
    margin-top: 20px;
}

.fc-reward-card {
    border: 2px solid #e9ecef;
    border-radius: 12px;
    padding: 25px;
    transition: all 0.3s ease;
    position: relative;
    overflow: hidden;
}

.fc-reward-card:hover {
    border-color: #3498db;
    box-shadow: 0 10px 30px rgba(52, 152, 219, 0.1);
    transform: translateY(-5px);
}

.fc-reward-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    margin-bottom: 15px;
}

.fc-reward-title {
    font-size: 1.3rem;
    color: #2c3e50;
    margin: 0;
    flex: 1;
}

.fc-reward-amount {
    font-size: 1.5rem;
    font-weight: bold;
    color: #e74c3c;
    margin-left: 15px;
}

.fc-reward-description {
    color: #666;
    line-height: 1.6;
    margin-bottom: 20px;
    min-height: 80px;
}

.fc-reward-limit {
    margin-bottom: 20px;
}

.fc-limit-progress {
    height: 8px;
    background: #f1f1f1;
    border-radius: 4px;
    overflow: hidden;
    margin-bottom: 8px;
}

.fc-limit-progress-bar {
    height: 100%;
    background: linear-gradient(90deg, #f39c12, #e67e22);
    transition: width 0.5s ease;
}

.fc-limit-text {
    font-size: 0.9rem;
    color: #7f8c8d;
    text-align: center;
}

.fc-select-reward {
    background: #2ecc71;
    color: white;
    border: none;
    padding: 12px 25px;
    border-radius: 6px;
    cursor: pointer;
    width: 100%;
    font-size: 1rem;
    transition: all 0.3s ease;
}

.fc-select-reward:hover {
    background: #27ae60;
    transform: scale(1.02);
}

/* 模态框样式 */
.fc-modal {
    display: none;
    position: fixed;
    z-index: 1000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    animation: fadeIn 0.3s ease;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.fc-modal-content {
    background-color: white;
    margin: 5% auto;
    padding: 30px;
    border-radius: 15px;
    width: 90%;
    max-width: 500px;
    position: relative;
    animation: slideIn 0.3s ease;
}

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

.fc-modal-close {
    position: absolute;
    right: 20px;
    top: 15px;
    font-size: 28px;
    cursor: pointer;
    color: #95a5a6;
    transition: color 0.3s;
}

.fc-modal-close:hover {
    color: #e74c3c;
}

.fc-modal-content h3 {
    color: #2c3e50;
    margin-bottom: 25px;
    text-align: center;
}

.fc-form-group {
    margin-bottom: 20px;
}

.fc-form-group label {
    display: block;
    margin-bottom: 8px;
    color: #34495e;
    font-weight: 500;
}

.fc-form-group input[type="number"],
.fc-form-group input[type="text"],
.fc-form-group select {
    width: 100%;
    padding: 12px 15px;
    border: 2px solid #ddd;
    border-radius: 8px;
    font-size: 1rem;
    transition: border-color 0.3s;
}

.fc-form-group input:focus,
.fc-form-group select:focus {
    outline: none;
    border-color: #3498db;
}

.fc-submit-button {
    background: linear-gradient(135deg, #3498db, #2980b9);
    color: white;
    border: none;
    padding: 15px 30px;
    font-size: 1.1rem;
    border-radius: 8px;
    cursor: pointer;
    width: 100%;
    transition: all 0.3s ease;
    margin-top: 10px;
}

.fc-submit-button:hover {
    background: linear-gradient(135deg, #2980b9, #1c5a7a);
    transform: translateY(-2px);
}

/* 响应式设计 */
@media (max-width: 768px) {
    .fc-progress-stats {
        grid-template-columns: repeat(2, 1fr);
    }
    
    .fc-rewards-grid {
        grid-template-columns: 1fr;
    }
    
    .fc-project-title {
        font-size: 2rem;
    }
    
    .fc-modal-content {
        margin: 10% auto;
        width: 95%;
    }
}
// 前端交互脚本
jQuery(document).ready(function($) {
    'use strict';
    
    // 支持按钮点击事件
    $(document).on('click', '.fc-support-button', function() {
        $('#fc-support-modal').fadeIn(300);
        $('body').css('overflow', 'hidden');
    });
    
    // 关闭模态框
    $(document).on('click', '.fc-modal-close, .fc-modal', function(e) {
        if ($(e.target).hasClass('fc-modal') || $(e.target).hasClass('fc-modal-close')) {
            $('#fc-support-modal').fadeOut(300);
            $('body').css('overflow', 'auto');
        }
    });
    
    // 选择回报
    $(document).on('click', '.fc-select-reward', function(e) {
        e.preventDefault();
        const rewardId = $(this).data('reward-id');
        const rewardAmount = $(this).closest('.fc-reward-card').find('.fc-reward-amount').text();
        
        // 设置选中的回报
        $('#fc-selected-reward').val(rewardId);
        $('#fc-support-amount').val(rewardAmount.replace('¥', '').trim());
        
        // 显示模态框
        $('#fc-support-modal').fadeIn(300);
        $('body').css('overflow', 'hidden');
        
        // 添加选中效果
        $('.fc-reward-card').removeClass('fc-reward-selected');
        $(this).closest('.fc-reward-card').addClass('fc-reward-selected');
    });
    
    // 匿名支持复选框
    $('input[name="anonymous"]').on('change', function() {
        if ($(this).is(':checked')) {
            $('#fc-anonymous-name-group').slideDown(300);
            $('#fc-anonymous-name').prop('required', true);
        } else {
            $('#fc-anonymous-name-group').slideUp(300);
            $('#fc-anonymous-name').prop('required', false);
        }
    });
    
    // 提交支持表单
    $('#fc-support-form').on('submit', function(e) {
        e.preventDefault();
        
        const formData = $(this).serialize();
        const submitButton = $(this).find('.fc-submit-button');
        const originalText = submitButton.text();
        
        // 显示加载状态
        submitButton.prop('disabled', true).text('处理中...');
        
        // AJAX请求
        $.ajax({
            url: fc_ajax.ajax_url,
            type: 'POST',
            data: {
                action: 'support_project',
                nonce: fc_ajax.nonce,
                form_data: formData
            },
            success: function(response) {
                if (response.success) {
                    // 成功处理
                    submitButton.text('支持成功!');
                    submitButton.css('background', '#2ecc71');
                    
                    // 更新页面数据
                    updateProjectStats(response.data.project_id);
                    
                    // 3秒后关闭模态框
                    setTimeout(function() {
                        $('#fc-support-modal').fadeOut(300);
                        $('body').css('overflow', 'auto');
                        submitButton.prop('disabled', false).text(originalText).css('background', '');
                    }, 3000);
                } else {
                    // 错误处理
                    alert(response.data.message || '操作失败,请重试');
                    submitButton.prop('disabled', false).text(originalText);
                }
            },
            error: function() {
                alert('网络错误,请检查连接后重试');
                submitButton.prop('disabled', false).text(originalText);
            }
        });
    });
    
    // 更新项目统计数据
    function updateProjectStats(projectId) {
        $.ajax({
            url: fc_ajax.ajax_url,
            type: 'POST',
            data: {
                action: 'get_project_stats',
                project_id: projectId,
                nonce: fc_ajax.nonce
            },
            success: function(response) {
                if (response.success) {
                    const data = response.data;
                    
                    // 更新金额
                    $('.fc-amount-raised .fc-value').text('¥' + data.current_amount);
                    
                    // 更新支持者数量
                    $('.fc-backers-count .fc-value').text(data.backers_count);
                    
                    // 更新进度条
                    const percentage = Math.min(100, (data.current_amount / data.ideal_target) * 100);
                    $('.fc-progress-fill').css('width', percentage + '%');
                    
                    // 更新回报领取数量
                    if (data.rewards) {
                        data.rewards.forEach(function(reward) {
                            const $rewardCard = $('.fc-reward-card[data-reward-id="' + reward.id + '"]');
                            if ($rewardCard.length) {
                                $rewardCard.find('.fc-limit-text').text(
                                    '已领取 ' + reward.claimed_count + ' / ' + reward.limit_count
                                );
                                
                                const claimedPercentage = (reward.claimed_count / reward.limit_count) * 100;
                                $rewardCard.find('.fc-limit-progress-bar').css('width', claimedPercentage + '%');
                            }
                        });
                    }
                }
            }
        });
    }
    
    // 实时倒计时
    function updateCountdown() {
        $('.fc-days-left .fc-value').each(function() {
            const days = parseInt($(this).text());
            if (days > 0) {
                $(this).text((days - 1) + '天');
            } else if (days === 0) {
                $(this).text('已结束');
                $(this).css('color', '#e74c3c');
            }
        });
    }
    
    // 每小时更新一次倒计时
    setInterval(updateCountdown, 3600000);
});

四、支付处理模块

<?php
/**
 * 支付处理类
 */
class FC_Payment_Handler {
    
    /**
     * 处理支付请求
     */
    public function process_payment($data) {
        // 验证数据
        $validation = $this->validate_payment_data($data);
        if (!$validation['valid']) {
            return array(
                'success' => false,
                'message' => $validation['message']
            );
        }
        
        // 根据支付方式选择处理器
        switch ($data['payment_method']) {
            case 'alipay':
                return $this->process_alipay($data);
            case 'wechat':
                return $this->process_wechat_pay($data);
            case 'bank':
                return $this->process_bank_transfer($data);
            default:
                return array(
                    'success' => false,
                    'message' => '不支持的支付方式'
                );
        }
    }
    
    /**
     * 验证支付数据
     */
    private function validate_payment_data($data) {
        // 检查必填字段
        $required_fields = array('project_id', 'amount', 'payment_method');
        foreach ($required_fields as $field) {
            if (empty($data[$field])) {
                return array(
                    'valid' => false,
                    'message' => '缺少必要字段: ' . $field
                );
            }
        }
        
        // 验证金额
        $amount = floatval($data['amount']);
        if ($amount <= 0) {
            return array(
                'valid' => false,
                'message' => '金额必须大于0'
            );
        }
        
        // 验证项目是否存在
        global $wpdb;
        $projects_table = $wpdb->prefix . 'fc_projects';
        $project = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM $projects_table WHERE id = %d AND status = 'active'",
            intval($data['project_id'])
        ));
        
        if (!$project) {
            return array(
                'valid' => false,
                'message' => '项目不存在或未激活'
            );
        }
        
        // 验证回报(如果选择了回报)
        if (!empty($data['reward_id'])) {
            $rewards_table = $wpdb->prefix . 'fc_rewards';
            $reward = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM $rewards_table WHERE id = %d AND project_id = %d",
                intval($data['reward_id']),
                intval($data['project_id'])
            ));
            
            if (!$reward) {
                return array(
                    'valid' => false,
                    'message' => '选择的回报不存在'
                );
            }
            
            // 检查回报是否已领完
            if ($reward->limit_count > 0 && $reward->claimed_count >= $reward->limit_count) {
                return array(
                    'valid' => false,
                    'message' => '该回报已领完'
                );
            }
            
            // 检查金额是否达到回报要求
            if ($amount < $reward->amount) {
                return array(
                    'valid' => false,
                    'message' => '金额未达到该回报要求'
                );
            }
        }
        
        return array('valid' => true);
    }
    
    /**
     * 处理支付宝支付
     */
    private function process_alipay($data) {
        // 这里应该集成支付宝SDK
        // 以下为示例代码
        
        $order_id = $this->generate_order_id();
        
        // 创建本地订单记录
        $backer_id = $this->create_backer_record(array_merge($data, array(
            'order_id' => $order_id,
            'status' => 'pending'
        )));
        
        if (!$backer_id) {
            return array(
                'success' => false,
                'message' => '创建订单失败'
            );
        }
        
        // 实际项目中这里应该调用支付宝API
        // $alipay_result = $this->call_alipay_api($order_id, $data['amount']);
        
        // 模拟支付成功
        $payment_result = array(
            'success' => true,
            'trade_no' => 'ALIPAY' . time() . rand(1000, 9999),
            'payment_url' => '#', // 实际项目中返回支付页面URL
            'order_id' => $order_id
        );
        
        if ($payment_result['success']) {
            // 更新订单状态
            $this->update_backer_status($backer_id, 'completed', array(
                'transaction_id' => $payment_result['trade_no']
            ));
            
            // 更新项目金额
            $this->update_project_amount($data['project_id'], $data['amount']);
            
            // 更新回报领取数量
            if (!empty($data['reward_id'])) {
                $this->update_reward_claimed_count($data['reward_id']);
            }
            
            return array(
                'success' => true,
                'data' => array(
                    'order_id' => $order_id,
                    'payment_url' => $payment_result['payment_url']
                )
            );
        }
        
        return array(
            'success' => false,
            'message' => '支付处理失败'
        );
    }
    
    /**
     * 生成订单ID
     */
    private function generate_order_id() {
        return date('YmdHis') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
    }
    
    /**
     * 创建支持者记录
     */
    private function create_backer_record($data) {
        global $wpdb;
        
        $user_id = get_current_user_id();
        $anonymous = isset($data['anonymous']) && $data['anonymous'] == 1;
        
        $backer_data = array(
            'project_id' => intval($data['project_id']),
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5737.html

EXCHANGES®作者

EXCHANGES® 技术支持:漳州柔性供应链服务有限公司
上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

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