首页 / 教程文章 / WordPress文创产品柔性预售插件开发指南

WordPress文创产品柔性预售插件开发指南

WordPress文创产品柔性预售插件开发指南

引言:文创产品预售的市场需求

随着文创产业的蓬勃发展,越来越多的创作者和品牌开始采用预售模式来测试市场反应、降低库存风险并筹集生产资金。柔性预售作为一种灵活的销售策略,允许商家根据订单数量调整生产计划,特别适合文创产品这种具有创意性、小批量特点的商品。

WordPress作为全球最流行的内容管理系统,为文创产品销售提供了强大的平台基础。本指南将详细介绍如何开发一个功能完整的WordPress文创产品柔性预售插件,帮助创作者和商家实现高效的预售管理。

插件功能规划与设计

核心功能需求分析

  1. 预售产品管理:创建和管理预售产品,设置预售时间、目标数量等
  2. 预售进度展示:实时显示预售进度,激励用户参与
  3. 订单管理:处理预售订单,支持多种支付方式
  4. 生产与发货管理:根据预售结果安排生产和发货
  5. 数据统计与分析:提供预售数据报表和分析工具

数据库设计

<?php
/**
 * 创建预售插件所需的数据表
 */
function create_presale_tables() {
    global $wpdb;
    
    $charset_collate = $wpdb->get_charset_collate();
    
    // 预售产品表
    $products_table = $wpdb->prefix . 'presale_products';
    $products_sql = "CREATE TABLE IF NOT EXISTS $products_table (
        id int(11) NOT NULL AUTO_INCREMENT,
        product_id int(11) NOT NULL,
        presale_start datetime NOT NULL,
        presale_end datetime NOT NULL,
        target_quantity int(11) NOT NULL,
        min_quantity int(11) DEFAULT 0,
        current_quantity int(11) DEFAULT 0,
        status varchar(20) DEFAULT 'pending',
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY product_id (product_id)
    ) $charset_collate;";
    
    // 预售订单表
    $orders_table = $wpdb->prefix . 'presale_orders';
    $orders_sql = "CREATE TABLE IF NOT EXISTS $orders_table (
        id int(11) NOT NULL AUTO_INCREMENT,
        order_id int(11) NOT NULL,
        presale_product_id int(11) NOT NULL,
        quantity int(11) NOT NULL,
        customer_id int(11),
        customer_email varchar(100),
        status varchar(20) DEFAULT 'pending',
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY presale_product_id (presale_product_id),
        KEY order_id (order_id)
    ) $charset_collate;";
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($products_sql);
    dbDelta($orders_sql);
}
register_activation_hook(__FILE__, 'create_presale_tables');
?>

插件核心功能开发

1. 预售产品管理模块

<?php
/**
 * 预售产品管理类
 */
class Presale_Product_Manager {
    
    /**
     * 添加预售产品
     * @param array $product_data 产品数据
     * @return int|false 插入ID或失败
     */
    public function add_presale_product($product_data) {
        global $wpdb;
        
        $table_name = $wpdb->prefix . 'presale_products';
        
        $defaults = array(
            'status' => 'pending',
            'current_quantity' => 0,
            'created_at' => current_time('mysql')
        );
        
        $data = wp_parse_args($product_data, $defaults);
        
        // 验证必要字段
        $required_fields = array('product_id', 'presale_start', 'presale_end', 'target_quantity');
        foreach ($required_fields as $field) {
            if (empty($data[$field])) {
                return false;
            }
        }
        
        $result = $wpdb->insert($table_name, $data);
        
        if ($result) {
            return $wpdb->insert_id;
        }
        
        return false;
    }
    
    /**
     * 获取预售产品信息
     * @param int $product_id WooCommerce产品ID
     * @return array|false 产品信息或失败
     */
    public function get_presale_product($product_id) {
        global $wpdb;
        
        $table_name = $wpdb->prefix . 'presale_products';
        
        $query = $wpdb->prepare(
            "SELECT * FROM $table_name WHERE product_id = %d AND status != 'cancelled'",
            $product_id
        );
        
        return $wpdb->get_row($query, ARRAY_A);
    }
    
    /**
     * 更新预售进度
     * @param int $presale_id 预售ID
     * @param int $quantity 新增数量
     * @return bool 更新结果
     */
    public function update_presale_progress($presale_id, $quantity) {
        global $wpdb;
        
        $table_name = $wpdb->prefix . 'presale_products';
        
        // 使用原子操作更新数量,避免并发问题
        $result = $wpdb->query(
            $wpdb->prepare(
                "UPDATE $table_name 
                 SET current_quantity = current_quantity + %d 
                 WHERE id = %d",
                $quantity,
                $presale_id
            )
        );
        
        // 检查是否达到目标数量
        $presale = $wpdb->get_row(
            $wpdb->prepare("SELECT * FROM $table_name WHERE id = %d", $presale_id)
        );
        
        if ($presale && $presale->current_quantity >= $presale->target_quantity) {
            $this->update_presale_status($presale_id, 'successful');
        }
        
        return $result;
    }
}
?>

2. 预售进度展示组件

<?php
/**
 * 预售进度展示短代码
 * 使用方式:[presale_progress product_id="123"]
 */
function presale_progress_shortcode($atts) {
    $atts = shortcode_atts(array(
        'product_id' => 0,
        'show_title' => true,
        'show_bar' => true,
        'show_numbers' => true
    ), $atts);
    
    $product_id = intval($atts['product_id']);
    
    if (!$product_id) {
        return '<p>错误:未指定产品ID</p>';
    }
    
    $presale_manager = new Presale_Product_Manager();
    $presale_product = $presale_manager->get_presale_product($product_id);
    
    if (!$presale_product) {
        return '<p>该产品未开启预售</p>';
    }
    
    $progress_percentage = 0;
    if ($presale_product['target_quantity'] > 0) {
        $progress_percentage = min(100, 
            ($presale_product['current_quantity'] / $presale_product['target_quantity']) * 100
        );
    }
    
    $output = '<div class="presale-progress-container">';
    
    if ($atts['show_title']) {
        $output .= '<h3 class="presale-title">产品预售进度</h3>';
    }
    
    if ($atts['show_bar']) {
        $output .= '<div class="presale-progress-bar">';
        $output .= '<div class="presale-progress-fill" style="width: ' . $progress_percentage . '%;"></div>';
        $output .= '</div>';
    }
    
    if ($atts['show_numbers']) {
        $output .= '<div class="presale-numbers">';
        $output .= '<span class="current">已预售:' . $presale_product['current_quantity'] . '</span>';
        $output .= '<span class="target">目标:' . $presale_product['target_quantity'] . '</span>';
        $output .= '<span class="percentage">完成度:' . round($progress_percentage, 1) . '%</span>';
        $output .= '</div>';
    }
    
    // 显示剩余时间
    $end_time = strtotime($presale_product['presale_end']);
    $current_time = current_time('timestamp');
    $time_left = $end_time - $current_time;
    
    if ($time_left > 0) {
        $days_left = floor($time_left / (60 * 60 * 24));
        $hours_left = floor(($time_left % (60 * 60 * 24)) / (60 * 60));
        
        $output .= '<div class="presale-time-left">';
        $output .= '<span>剩余时间:' . $days_left . '天' . $hours_left . '小时</span>';
        $output .= '</div>';
    } else {
        $output .= '<div class="presale-ended">预售已结束</div>';
    }
    
    $output .= '</div>';
    
    return $output;
}
add_shortcode('presale_progress', 'presale_progress_shortcode');
?>

前端界面与用户体验优化

响应式预售产品页面集成

<?php
/**
 * 在WooCommerce产品页面添加预售信息
 */
function add_presale_info_to_product_page() {
    global $product;
    
    $product_id = $product->get_id();
    $presale_manager = new Presale_Product_Manager();
    $presale_product = $presale_manager->get_presale_product($product_id);
    
    if (!$presale_product) {
        return;
    }
    
    // 检查预售是否进行中
    $current_time = current_time('timestamp');
    $start_time = strtotime($presale_product['presale_start']);
    $end_time = strtotime($presale_product['presale_end']);
    
    if ($current_time < $start_time) {
        echo '<div class="presale-notice presale-upcoming">';
        echo '<p>预售即将开始:' . date('Y-m-d H:i', $start_time) . '</p>';
        echo '</div>';
        return;
    }
    
    if ($current_time > $end_time) {
        echo '<div class="presale-notice presale-ended">';
        echo '<p>预售已结束</p>';
        echo '</div>';
        return;
    }
    
    // 显示预售进行中信息
    echo '<div class="presale-notice presale-active">';
    echo '<h3>🎉 产品预售中!</h3>';
    
    // 显示进度条
    $progress_percentage = min(100, 
        ($presale_product['current_quantity'] / $presale_product['target_quantity']) * 100
    );
    
    echo '<div class="presale-progress">';
    echo '<div class="progress-bar">';
    echo '<div class="progress-fill" style="width: ' . $progress_percentage . '%;"></div>';
    echo '</div>';
    echo '<div class="progress-text">';
    echo '已预售 ' . $presale_product['current_quantity'] . ' / ' . $presale_product['target_quantity'];
    echo ' (' . round($progress_percentage, 1) . '%)';
    echo '</div>';
    echo '</div>';
    
    // 显示预售说明
    echo '<div class="presale-description">';
    echo '<p>此产品采用预售模式,将在预售结束后统一安排生产。</p>';
    echo '<p>预计发货时间:' . date('Y-m-d', strtotime('+30 days', $end_time)) . '</p>';
    echo '</div>';
    
    echo '</div>';
}
add_action('woocommerce_before_add_to_cart_form', 'add_presale_info_to_product_page');
?>

订单处理与支付集成

WooCommerce订单钩子集成

<?php
/**
 * 处理预售订单
 */
class Presale_Order_Handler {
    
    /**
     * 创建预售订单记录
     * @param int $order_id WooCommerce订单ID
     */
    public function create_presale_order($order_id) {
        $order = wc_get_order($order_id);
        
        if (!$order) {
            return;
        }
        
        $presale_manager = new Presale_Product_Manager();
        
        foreach ($order->get_items() as $item) {
            $product_id = $item->get_product_id();
            $presale_product = $presale_manager->get_presale_product($product_id);
            
            if ($presale_product) {
                $this->save_presale_order_record($order_id, $presale_product['id'], $item);
                
                // 更新预售进度
                $presale_manager->update_presale_progress(
                    $presale_product['id'], 
                    $item->get_quantity()
                );
            }
        }
    }
    
    /**
     * 保存预售订单记录
     * @param int $order_id WooCommerce订单ID
     * @param int $presale_product_id 预售产品ID
     * @param WC_Order_Item_Product $item 订单项
     */
    private function save_presale_order_record($order_id, $presale_product_id, $item) {
        global $wpdb;
        
        $table_name = $wpdb->prefix . 'presale_orders';
        
        $order = wc_get_order($order_id);
        
        $data = array(
            'order_id' => $order_id,
            'presale_product_id' => $presale_product_id,
            'quantity' => $item->get_quantity(),
            'customer_id' => $order->get_customer_id(),
            'customer_email' => $order->get_billing_email(),
            'status' => 'pending',
            'created_at' => current_time('mysql')
        );
        
        $wpdb->insert($table_name, $data);
    }
    
    /**
     * 处理订单状态变更
     * @param int $order_id 订单ID
     * @param string $old_status 旧状态
     * @param string $new_status 新状态
     */
    public function handle_order_status_change($order_id, $old_status, $new_status) {
        global $wpdb;
        
        $table_name = $wpdb->prefix . 'presale_orders';
        
        // 更新预售订单状态
        $wpdb->update(
            $table_name,
            array('status' => $new_status),
            array('order_id' => $order_id),
            array('%s'),
            array('%d')
        );
        
        // 如果订单取消或退款,需要减少预售数量
        if (in_array($new_status, array('cancelled', 'refunded'))) {
            $this->adjust_presale_quantity($order_id, 'decrease');
        }
        
        // 如果订单从取消状态恢复,需要增加预售数量
        if (in_array($old_status, array('cancelled', 'refunded')) && 
            !in_array($new_status, array('cancelled', 'refunded'))) {
            $this->adjust_presale_quantity($order_id, 'increase');
        }
    }
    
    /**
     * 调整预售数量
     * @param int $order_id 订单ID
     * @param string $action 操作类型:increase/decrease
     */
    private function adjust_presale_quantity($order_id, $action) {
        global $wpdb;
        
        $presale_orders_table = $wpdb->prefix . 'presale_orders';
        $presale_products_table = $wpdb->prefix . 'presale_products';
        
        // 获取订单中的预售产品
        $presale_orders = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM $presale_orders_table WHERE order_id = %d",
                $order_id
            )
        );
        
        foreach ($presale_orders as $presale_order) {
            $operator = ($action === 'increase') ? '+' : '-';
            
            $wpdb->query(
                $wpdb->prepare(
                    "UPDATE $presale_products_table 
                     SET current_quantity = current_quantity $operator %d 
                     WHERE id = %d",
                    $presale_order->quantity,
                    $presale_order->presale_product_id
                )
            );
        }
    }
}

// 注册订单钩子
$presale_order_handler = new Presale_Order_Handler();
add_action('woocommerce_checkout_order_processed', array($presale_order_handler, 'create_presale_order'));
add_action('woocommerce_order_status_changed', array($presale_order_handler, 'handle_order_status_change'), 10, 3);
?>

管理后台功能开发

预售产品管理界面

<?php
/**
 * 添加预售产品管理菜单
 */
function add_presale_admin_menu() {
    add_menu_page(
        '文创产品预售管理',
        '文创预售',
        'manage_options',
        'presale-management',
        'presale_admin_page',
        'dashicons-cart',
        30
    );
    
    add_submenu_page(
        'presale-management',
        '预售产品',
        '预售产品',
        'manage_options',
        'presale-products',
        'presale_products_page'
    );
    
    add_submenu_page(
        'presale-management',
        '预售订单',
        '预售订单',
        'manage_options',
        'presale-orders',
        'presale_orders_page'
    );
    
    add_submenu_page(
        'presale-management',
        '预售统计',
        '预售统计',
        'manage_options',
        'presale-statistics',
        'presale_statistics_page'
    );
}
add_action('admin_menu', 'add_presale_admin_menu');

/**
 * 预售产品管理页面
 */
function presale_products_page() {
    ?>
    <div class="wrap">
        <h1 class="wp-heading-inline">文创产品预售管理</h1>
        <a href="<?php echo admin_url('admin.php?page=presale-products&action=add'); ?>" class="page-title-action">添加预售产品</a>
        
        <?php
        // 处理不同的操作
        $action = isset($_GET['action']) ? $_GET['action'] : 'list';
        
        switch ($action) {
            case 'add':
                display_add_presale_form();
                break;
            case 'edit':

form();

            break;
        case 'delete':
            handle_delete_presale();
            break;
        default:
            display_presale_products_list();
            break;
    }
    ?>
</div>
<?php

}

/**

  • 显示预售产品列表
    */

function display_presale_products_list() {

global $wpdb;

$table_name = $wpdb->prefix . 'presale_products';

// 分页处理
$per_page = 20;
$current_page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
$offset = ($current_page - 1) * $per_page;

// 搜索处理
$search = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : '';
$where = '';

if (!empty($search)) {
    $where = $wpdb->prepare("WHERE product_id LIKE %s OR status LIKE %s", 
        '%' . $search . '%', 
        '%' . $search . '%'
    );
}

// 获取总记录数
$total_query = "SELECT COUNT(*) FROM $table_name $where";
$total = $wpdb->get_var($total_query);

// 获取产品数据
$query = "SELECT p.*, 
                 pm.meta_value as product_name
          FROM $table_name p
          LEFT JOIN {$wpdb->prefix}posts ps ON p.product_id = ps.ID
          LEFT JOIN {$wpdb->prefix}postmeta pm ON p.product_id = pm.post_id AND pm.meta_key = '_sku'
          $where
          ORDER BY p.created_at DESC
          LIMIT $offset, $per_page";

$products = $wpdb->get_results($query);

?>

<div class="tablenav top">
    <div class="alignleft actions">
        <form method="get">
            <input type="hidden" name="page" value="presale-products">
            <p class="search-box">
                <label class="screen-reader-text" for="post-search-input">搜索预售产品:</label>
                <input type="search" id="post-search-input" name="s" value="<?php echo esc_attr($search); ?>">
                <input type="submit" id="search-submit" class="button" value="搜索">
            </p>
        </form>
    </div>
    
    <div class="tablenav-pages">
        <?php
        $total_pages = ceil($total / $per_page);
        if ($total_pages > 1) {
            echo paginate_links(array(
                'base' => add_query_arg('paged', '%#%'),
                'format' => '',
                'prev_text' => '&laquo;',
                'next_text' => '&raquo;',
                'total' => $total_pages,
                'current' => $current_page
            ));
        }
        ?>
    </div>
</div>

<table class="wp-list-table widefat fixed striped">
    <thead>
        <tr>
            <th>ID</th>
            <th>产品ID</th>
            <th>产品名称/SKU</th>
            <th>预售开始</th>
            <th>预售结束</th>
            <th>目标数量</th>
            <th>当前数量</th>
            <th>完成度</th>
            <th>状态</th>
            <th>操作</th>
        </tr>
    </thead>
    <tbody>
        <?php if (empty($products)): ?>
            <tr>
                <td colspan="10">暂无预售产品</td>
            </tr>
        <?php else: ?>
            <?php foreach ($products as $product): 
                $progress = $product->target_quantity > 0 ? 
                    round(($product->current_quantity / $product->target_quantity) * 100, 1) : 0;
                
                // 获取产品状态
                $current_time = current_time('timestamp');
                $start_time = strtotime($product->presale_start);
                $end_time = strtotime($product->presale_end);
                
                $status_class = '';
                if ($current_time < $start_time) {
                    $status = '未开始';
                    $status_class = 'status-pending';
                } elseif ($current_time > $end_time) {
                    $status = '已结束';
                    $status_class = 'status-ended';
                } else {
                    $status = '进行中';
                    $status_class = 'status-active';
                }
            ?>
            <tr>
                <td><?php echo $product->id; ?></td>
                <td><?php echo $product->product_id; ?></td>
                <td>
                    <?php 
                    $product_name = get_the_title($product->product_id);
                    echo $product_name ?: '产品#' . $product->product_id;
                    if ($product->product_name) {
                        echo '<br><small>SKU: ' . esc_html($product->product_name) . '</small>';
                    }
                    ?>
                </td>
                <td><?php echo date('Y-m-d H:i', strtotime($product->presale_start)); ?></td>
                <td><?php echo date('Y-m-d H:i', strtotime($product->presale_end)); ?></td>
                <td><?php echo $product->target_quantity; ?></td>
                <td><?php echo $product->current_quantity; ?></td>
                <td>
                    <div class="progress-container">
                        <div class="progress-bar">
                            <div class="progress-fill" style="width: <?php echo min(100, $progress); ?>%;"></div>
                        </div>
                        <span class="progress-text"><?php echo $progress; ?>%</span>
                    </div>
                </td>
                <td><span class="status-badge <?php echo $status_class; ?>"><?php echo $status; ?></span></td>
                <td>
                    <a href="<?php echo admin_url('admin.php?page=presale-products&action=edit&id=' . $product->id); ?>" class="button button-small">编辑</a>
                    <a href="<?php echo admin_url('admin.php?page=presale-products&action=delete&id=' . $product->id); ?>" class="button button-small button-link-delete" onclick="return confirm('确定要删除这个预售产品吗?');">删除</a>
                </td>
            </tr>
            <?php endforeach; ?>
        <?php endif; ?>
    </tbody>
</table>

<style>
.progress-container {
    display: flex;
    align-items: center;
    gap: 10px;
}
.progress-bar {
    flex: 1;
    height: 10px;
    background: #f0f0f0;
    border-radius: 5px;
    overflow: hidden;
}
.progress-fill {
    height: 100%;
    background: #0073aa;
    transition: width 0.3s ease;
}
.progress-text {
    min-width: 50px;
    text-align: right;
}
.status-badge {
    display: inline-block;
    padding: 3px 8px;
    border-radius: 3px;
    font-size: 12px;
    font-weight: bold;
}
.status-pending {
    background: #f0f0f0;
    color: #666;
}
.status-active {
    background: #d4edda;
    color: #155724;
}
.status-ended {
    background: #f8d7da;
    color: #721c24;
}
</style>
<?php

}
?>


## 数据统计与报表功能

### 预售数据统计模块

<?php
/**

  • 预售统计页面
    */

function presale_statistics_page() {

global $wpdb;

$products_table = $wpdb->prefix . 'presale_products';
$orders_table = $wpdb->prefix . 'presale_orders';

// 获取总体统计
$total_stats = $wpdb->get_row("
    SELECT 
        COUNT(*) as total_products,
        SUM(target_quantity) as total_target,
        SUM(current_quantity) as total_current,
        AVG(CASE WHEN target_quantity > 0 THEN (current_quantity * 100.0 / target_quantity) ELSE 0 END) as avg_progress
    FROM $products_table
    WHERE status != 'cancelled'
");

// 获取按状态统计
$status_stats = $wpdb->get_results("
    SELECT 
        status,
        COUNT(*) as count,
        SUM(target_quantity) as target_sum,
        SUM(current_quantity) as current_sum
    FROM $products_table
    GROUP BY status
");

// 获取最近30天的预售趋势
$trend_data = $wpdb->get_results("
    SELECT 
        DATE(created_at) as date,
        COUNT(*) as new_products,
        SUM(target_quantity) as daily_target,
        SUM(current_quantity) as daily_current
    FROM $products_table
    WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
    GROUP BY DATE(created_at)
    ORDER BY date ASC
");

// 获取最受欢迎的预售产品
$popular_products = $wpdb->get_results("
    SELECT 
        p.product_id,
        pm.meta_value as sku,
        p.target_quantity,
        p.current_quantity,
        ROUND((p.current_quantity * 100.0 / NULLIF(p.target_quantity, 0)), 1) as progress
    FROM $products_table p
    LEFT JOIN {$wpdb->prefix}postmeta pm ON p.product_id = pm.post_id AND pm.meta_key = '_sku'
    WHERE p.status != 'cancelled'
    ORDER BY progress DESC
    LIMIT 10
");

?>

<div class="wrap">
    <h1>文创产品预售统计</h1>
    
    <div class="presale-stats-container">
        <!-- 总体统计卡片 -->
        <div class="stats-cards">
            <div class="stats-card">
                <h3>预售产品总数</h3>
                <div class="stats-number"><?php echo $total_stats->total_products ?: 0; ?></div>
            </div>
            
            <div class="stats-card">
                <h3>总目标数量</h3>
                <div class="stats-number"><?php echo $total_stats->total_target ?: 0; ?></div>
            </div>
            
            <div class="stats-card">
                <h3>总预售数量</h3>
                <div class="stats-number"><?php echo $total_stats->total_current ?: 0; ?></div>
            </div>
            
            <div class="stats-card">
                <h3>平均完成度</h3>
                <div class="stats-number"><?php echo round($total_stats->avg_progress ?: 0, 1); ?>%</div>
            </div>
        </div>
        
        <!-- 状态分布 -->
        <div class="stats-section">
            <h2>预售状态分布</h2>
            <table class="wp-list-table widefat fixed">
                <thead>
                    <tr>
                        <th>状态</th>
                        <th>产品数量</th>
                        <th>目标总数</th>
                        <th>预售总数</th>
                        <th>平均完成度</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($status_stats as $stat): 
                        $avg_progress = $stat->target_sum > 0 ? 
                            round(($stat->current_sum / $stat->target_sum) * 100, 1) : 0;
                    ?>
                    <tr>
                        <td><?php echo esc_html($stat->status); ?></td>
                        <td><?php echo $stat->count; ?></td>
                        <td><?php echo $stat->target_sum; ?></td>
                        <td><?php echo $stat->current_sum; ?></td>
                        <td><?php echo $avg_progress; ?>%</td>
                    </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        </div>
        
        <!-- 热门产品 -->
        <div class="stats-section">
            <h2>最受欢迎预售产品</h2>
            <table class="wp-list-table widefat fixed">
                <thead>
                    <tr>
                        <th>产品ID</th>
                        <th>SKU</th>
                        <th>目标数量</th>
                        <th>预售数量</th>
                        <th>完成度</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ($popular_products as $product): 
                        $product_name = get_the_title($product->product_id);
                    ?>
                    <tr>
                        <td><?php echo $product->product_id; ?></td>
                        <td>
                            <?php echo $product_name ?: '产品#' . $product->product_id; ?>
                            <?php if ($product->sku): ?>
                            <br><small>SKU: <?php echo esc_html($product->sku); ?></small>
                            <?php endif; ?>
                        </td>
                        <td><?php echo $product->target_quantity; ?></td>
                        <td><?php echo $product->current_quantity; ?></td>
                        <td>
                            <div class="progress-container">
                                <div class="progress-bar">
                                    <div class="progress-fill" style="width: <?php echo min(100, $product->progress); ?>%;"></div>
                                </div>
                                <span class="progress-text"><?php echo $product->progress; ?>%</span>
                            </div>
                        </td>
                    </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        </div>
        
        <!-- 趋势图表 -->
        <div class="stats-section">
            <h2>最近30天预售趋势</h2>
            <div id="presale-trend-chart" style="height: 300px;"></div>
            
            <script>
            jQuery(document).ready(function($) {
                // 准备图表数据
                var trendData = [
                    <?php foreach ($trend_data as $data): ?>
                    {
                        date: '<?php echo $data->date; ?>',
                        newProducts: <?php echo $data->new_products; ?>,
                        dailyTarget: <?php echo $data->daily_target; ?>,
                        dailyCurrent: <?php echo $data->daily_current; ?>
                    },
                    <?php endforeach; ?>
                ];
                
                // 使用Chart.js绘制图表
                if (trendData.length > 0 && typeof Chart !== 'undefined') {
                    var ctx = document.getElementById('presale-trend-chart').getContext('2d');
                    
                    var dates = trendData.map(item => item.date);
                    var newProducts = trendData.map(item => item.newProducts);
                    var dailyCurrent = trendData.map(item => item.dailyCurrent);
                    
                    var chart = new Chart(ctx, {
                        type: 'line',
                        data: {
                            labels: dates,
                            datasets: [
                                {
                                    label: '新增预售产品',
                                    data: newProducts,
                                    borderColor: '#0073aa',
                                    backgroundColor: 'rgba(0, 115, 170, 0.1)',
                                    fill: true,
                                    tension: 0.4
                                },
                                {
                                    label: '每日预售数量',
                                    data: dailyCurrent,
                                    borderColor: '#46b450',
                                    backgroundColor: 'rgba(70, 180, 80, 0.1)',
                                    fill: true,
                                    tension: 0.4
                                }
                            ]
                        },
                        options: {
                            responsive: true,
                            maintainAspectRatio: false,
                            scales: {
                                y: {
                                    beginAtZero: true
                                }
                            }
                        }
                    });
                }
            });
            </script>
        </div>
    </div>
    
    <!-- 导出功能 -->
    <div class="stats-export">
        <h2>数据导出</h2>
        <form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
            <input type="hidden" name="action" value="export_presale_data">
            <?php wp_nonce_field('export_presale_data', 'presale_export_nonce'); ?>
            
            <p>
                <label for="export_type">导出类型:</label>
                <select name="export_type" id="export_type">
                    <option value="products">预售产品数据</option>
                    <option value="orders">预售订单数据</option>
                    <option value="statistics">统计报表</option>
                </select>
            </p>
            
            <p>
                <label for="start_date">开始日期:</label>
                <input type="date" name="start_date" id="start_date">
                
                <label for="end_date">结束日期:</label>
                <input type="date" name="end_date" id="end_date">
            </p>
            
            <p>
                <label for="format">导出格式:</label>
                <select name="format" id="format">
                    <option value="csv">CSV</option>
                    <option value="excel">Excel</option>
                    <option value="json">JSON</option>
                </select>
            </p>
            
            <p>
                <input type="submit" class="button button-primary" value="导出数据">
            </p>
        </form>
    </div>
</div>

<style>
.presale-stats-container {
    margin-top: 20px;
}

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

.stats-card {
    background: white;
    border: 1px solid #ccd0d4;
    border-radius: 4px;
    padding: 20px;
    text-align: center;
    box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

.stats-card h3 {
    margin-top: 0;
    color: #666;
    font-size: 14px;
    text-transform:
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5695.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

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