文章目录
-
- 随着文创产业的蓬勃发展,越来越多的创作者需要灵活的资金支持方式。传统的众筹平台往往采用"全有或全无"的固定模式,缺乏灵活性。为此,我们开发了一款WordPress柔性众筹插件,允许创作者设置弹性目标,按实际筹集金额比例交付回报。 核心需求: 支持弹性目标设置(最低目标、理想目标、超额目标) 多种支付方式集成(支付宝、微信支付、银行卡) 多级回报体系 实时进度展示 后台管理界面 数据统计与分析
-
- <?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'); ?>
- <?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); } // 其他方法将在后续章节实现 } ?>
-
- <?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">×</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 )); } ?>
- /* 柔性众筹插件前端样式 */ .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']),
随着文创产业的蓬勃发展,越来越多的创作者需要灵活的资金支持方式。传统的众筹平台往往采用"全有或全无"的固定模式,缺乏灵活性。为此,我们开发了一款WordPress柔性众筹插件,允许创作者设置弹性目标,按实际筹集金额比例交付回报。
核心需求:
- 支持弹性目标设置(最低目标、理想目标、超额目标)
- 多种支付方式集成(支付宝、微信支付、银行卡)
- 多级回报体系
- 实时进度展示
- 后台管理界面
- 数据统计与分析
<?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');
?>
<?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');
?>
<?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);
}
// 其他方法将在后续章节实现
}
?>
<?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);
}
// 其他方法将在后续章节实现
}
?>
<?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">×</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
));
}
?>
<?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">×</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
));
}
?>
/* 柔性众筹插件前端样式 */
.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);
});
/* 柔性众筹插件前端样式 */
.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']),
<?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']),


