文章目录[隐藏]
WordPress文创产品柔性预售插件开发指南
引言:文创产品预售的市场需求
随着文创产业的蓬勃发展,越来越多的创作者和品牌开始采用预售模式来测试市场反应、降低库存风险并筹集生产资金。柔性预售作为一种灵活的销售策略,允许商家根据订单数量调整生产计划,特别适合文创产品这种具有创意性、小批量特点的商品。
WordPress作为全球最流行的内容管理系统,为文创产品销售提供了强大的平台基础。本指南将详细介绍如何开发一个功能完整的WordPress文创产品柔性预售插件,帮助创作者和商家实现高效的预售管理。
插件功能规划与设计
核心功能需求分析
- 预售产品管理:创建和管理预售产品,设置预售时间、目标数量等
- 预售进度展示:实时显示预售进度,激励用户参与
- 订单管理:处理预售订单,支持多种支付方式
- 生产与发货管理:根据预售结果安排生产和发货
- 数据统计与分析:提供预售数据报表和分析工具
数据库设计
<?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' => '«',
'next_text' => '»',
'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:
