文章目录
-
- 在当今全球化的商业环境中,供应链管理已成为企业成功的关键因素。柔性供应链可视化看板能够帮助企业实时监控物流状态、库存水平和订单进度,从而快速响应市场变化。本教程将指导您如何在WordPress平台上构建一个功能完善的柔性供应链可视化看板,无需昂贵的专业软件,即可实现供应链数据的直观展示与分析。
- 在开始开发之前,请确保您的WordPress环境满足以下要求: WordPress 5.0或更高版本 PHP 7.4或更高版本 管理员权限 安装并激活以下插件: Advanced Custom Fields(用于自定义字段) 图表生成插件(如Data Tables Generator)
-
- 我们将创建三个自定义文章类型来管理供应链数据:供应商、产品和订单。 <?php /** * 注册供应链相关自定义文章类型 */ function register_supply_chain_post_types() { // 注册供应商类型 $supplier_labels = array( 'name' => '供应商', 'singular_name' => '供应商', 'add_new' => '添加供应商', 'add_new_item' => '添加新供应商', 'edit_item' => '编辑供应商', 'new_item' => '新供应商', 'view_item' => '查看供应商', 'search_items' => '搜索供应商', 'not_found' => '未找到供应商', 'not_found_in_trash' => '回收站中无供应商' ); register_post_type('supplier', array( 'labels' => $supplier_labels, 'public' => true, 'has_archive' => true, 'menu_icon' => 'dashicons-truck', 'supports' => array('title', 'editor', 'thumbnail'), 'show_in_rest' => true, // 启用Gutenberg编辑器支持 )); // 注册产品类型 $product_labels = array( 'name' => '供应链产品', 'singular_name' => '产品', 'add_new' => '添加产品', 'add_new_item' => '添加新产品', 'edit_item' => '编辑产品', 'new_item' => '新产品', 'view_item' => '查看产品', 'search_items' => '搜索产品', ); register_post_type('supply_product', array( 'labels' => $product_labels, 'public' => true, 'has_archive' => true, 'menu_icon' => 'dashicons-products', 'supports' => array('title', 'editor', 'thumbnail'), 'show_in_rest' => true, )); // 注册订单类型 $order_labels = array( 'name' => '供应链订单', 'singular_name' => '订单', 'add_new' => '添加订单', 'add_new_item' => '添加新订单', 'edit_item' => '编辑订单', 'new_item' => '新订单', 'view_item' => '查看订单', ); register_post_type('supply_order', array( 'labels' => $order_labels, 'public' => true, 'has_archive' => true, 'menu_icon' => 'dashicons-clipboard', 'supports' => array('title'), 'show_in_rest' => true, )); } add_action('init', 'register_supply_chain_post_types'); ?>
- 通过ACF插件创建以下字段组: 供应商字段组: 联系人姓名(文本) 联系电话(文本) 供应能力评级(选择:高/中/低) 地理位置(谷歌地图) 产品字段组: 产品SKU(文本) 当前库存(数字) 安全库存水平(数字) 关联供应商(关系字段) 订单字段组: 订单状态(选择:待处理/生产中/运输中/已完成) 订单数量(数字) 关联产品(关系字段) 预计交付日期(日期选择器) 实际交付日期(日期选择器)
-
- <?php /** * 供应链可视化看板模板 * Template Name: 供应链可视化看板 */ get_header(); ?> <div class="supply-chain-dashboard"> <div class="dashboard-header"> <h1>柔性供应链可视化看板</h1> <div class="last-updated">最后更新: <span id="update-time"><?php echo current_time('Y-m-d H:i:s'); ?></span></div> <button class="refresh-btn" onclick="refreshDashboard()">刷新数据</button> </div> <div class="dashboard-grid"> <!-- 关键指标卡片 --> <div class="dashboard-card metrics-card"> <h3>关键绩效指标</h3> <div class="metrics-grid"> <div class="metric-item"> <div class="metric-value" id="total-orders">0</div> <div class="metric-label">总订单数</div> </div> <div class="metric-item"> <div class="metric-value" id="pending-orders">0</div> <div class="metric-label">待处理订单</div> </div> <div class="metric-item"> <div class="metric-value" id="on-time-delivery">0%</div> <div class="metric-label">准时交付率</div> </div> <div class="metric-item"> <div class="metric-value" id="inventory-alerts">0</div> <div class="metric-label">库存预警</div> </div> </div> </div> <!-- 订单状态图表 --> <div class="dashboard-card chart-card"> <h3>订单状态分布</h3> <canvas id="order-status-chart" width="400" height="300"></canvas> </div> <!-- 库存水平图表 --> <div class="dashboard-card chart-card"> <h3>库存水平监控</h3> <canvas id="inventory-chart" width="400" height="300"></canvas> </div> <!-- 供应商绩效表格 --> <div class="dashboard-card table-card"> <h3>供应商绩效排名</h3> <table id="supplier-performance-table"> <thead> <tr> <th>供应商</th> <th>订单完成率</th> <th>准时率</th> <th>质量评分</th> <th>状态</th> </tr> </thead> <tbody id="supplier-table-body"> <!-- 数据将通过AJAX加载 --> </tbody> </table> </div> <!-- 实时订单列表 --> <div class="dashboard-card orders-card"> <h3>近期订单状态</h3> <div class="orders-list" id="recent-orders"> <!-- 订单数据将通过AJAX加载 --> </div> </div> </div> </div> <?php get_footer(); ?>
- /* 供应链看板样式 */ .supply-chain-dashboard { padding: 20px; background-color: #f5f7fa; min-height: 100vh; } .dashboard-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 2px solid #e0e6ed; } .dashboard-header h1 { color: #2c3e50; margin: 0; } .last-updated { color: #7f8c8d; font-size: 14px; } .refresh-btn { background-color: #3498db; color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-weight: bold; } .refresh-btn:hover { background-color: #2980b9; } .dashboard-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 20px; } .dashboard-card { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .dashboard-card h3 { margin-top: 0; color: #34495e; border-bottom: 1px solid #ecf0f1; padding-bottom: 10px; } .metrics-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; } .metric-item { text-align: center; padding: 15px; background-color: #f8f9fa; border-radius: 6px; } .metric-value { font-size: 28px; font-weight: bold; color: #2c3e50; } .metric-label { font-size: 14px; color: #7f8c8d; margin-top: 5px; } .orders-list { max-height: 300px; overflow-y: auto; } .order-item { padding: 10px; border-bottom: 1px solid #ecf0f1; display: flex; justify-content: space-between; } .order-item:last-child { border-bottom: none; } .order-status { padding: 3px 8px; border-radius: 12px; font-size: 12px; font-weight: bold; } .status-pending { background-color: #f39c12; color: white; } .status-production { background-color: #3498db; color: white; } .status-shipping { background-color: #9b59b6; color: white; } .status-completed { background-color: #2ecc71; color: white; } #supplier-performance-table { width: 100%; border-collapse: collapse; } #supplier-performance-table th, #supplier-performance-table td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; } #supplier-performance-table th { background-color: #f2f6fc; font-weight: bold; }
-
- <?php /** * 注册供应链数据API端点 */ function register_supply_chain_api() { register_rest_route('supply-chain/v1', '/dashboard-data', array( 'methods' => 'GET', 'callback' => 'get_dashboard_data', 'permission_callback' => function() { return current_user_can('edit_posts'); // 仅限有编辑权限的用户 } )); register_rest_route('supply-chain/v1', '/refresh-data', array( 'methods' => 'POST', 'callback' => 'refresh_dashboard_data', 'permission_callback' => function() { return current_user_can('edit_posts'); } )); } add_action('rest_api_init', 'register_supply_chain_api'); /** * 获取看板数据 */ function get_dashboard_data() { $data = array(); // 获取订单统计数据 $order_stats = get_order_statistics(); $data['order_stats'] = $order_stats; // 获取库存数据 $inventory_data = get_inventory_data(); $data['inventory'] = $inventory_data; // 获取供应商绩效数据 $supplier_performance = get_supplier_performance(); $data['suppliers'] = $supplier_performance; // 获取最近订单 $recent_orders = get_recent_orders(10); $data['recent_orders'] = $recent_orders; // 计算关键指标 $data['metrics'] = calculate_key_metrics($order_stats, $inventory_data); return rest_ensure_response($data); } /** * 获取订单统计数据 */ function get_order_statistics() { $statuses = array('pending', 'production', 'shipping', 'completed'); $stats = array(); foreach ($statuses as $status) { $args = array( 'post_type' => 'supply_order', 'posts_per_page' => -1, 'meta_query' => array( array( 'key' => 'order_status', 'value' => $status, 'compare' => '=' ) ) ); $query = new WP_Query($args); $stats[$status] = $query->found_posts; } return $stats; } /** * 获取库存数据 */ function get_inventory_data() { $inventory = array(); $args = array( 'post_type' => 'supply_product', 'posts_per_page' => -1, ); $query = new WP_Query($args); while ($query->have_posts()) { $query->the_post(); $product_id = get_the_ID(); $current_stock = get_field('current_stock', $product_id); $safety_stock = get_field('safety_stock_level', $product_id); $inventory[] = array( 'product_name' => get_the_title(), 'current_stock' => $current_stock ?: 0, 'safety_stock' => $safety_stock ?: 10, 'status' => $current_stock <= $safety_stock ? 'low' : 'normal' ); } wp_reset_postdata(); return $inventory; } ?>
- /** * 供应链看板数据交互脚本 */ document.addEventListener('DOMContentLoaded', function() { // 初始化看板 loadDashboardData(); // 设置自动刷新(每5分钟) setInterval(loadDashboardData, 300000); }); /** * 加载看板数据 */ function loadDashboardData() { // 显示加载状态 document.getElementById('update-time').textContent = '加载中...'; // 获取API数据 fetch('/wp-json/supply-chain/v1/dashboard-data') .then(response => response.json()) .then(data => { updateDashboard(data); updateCharts(data); updateTables(data); // 更新最后刷新时间 const now = new Date(); document.getElementById('update-time').textContent = now.toLocaleDateString() + ' ' + now.toLocaleTimeString(); }) .catch(error => { console.error('加载数据失败:', error); document.getElementById('update-time').textContent = '加载失败'; }); } /** * 更新关键指标 */ function updateDashboard(data) { const metrics = data.metrics; document.getElementById('total-orders').textContent = metrics.total_orders; document.getElementById('pending-orders').textContent = metrics.pending_orders; document.getElementById('on-time-delivery').textContent = metrics.on_time_delivery + '%'; document.getElementById('inventory-alerts').textContent = metrics.inventory_alerts; } /** * 更新图表 */ function updateCharts(data) { // 订单状态图表 const orderCtx = document.getElementById('order-status-chart').getContext('2d'); const orderChart = new Chart(orderCtx, { type: 'doughnut', data: { labels: ['待处理', '生产中', '运输中', '已完成'], datasets: [{ data: [ data.order_stats.pending, data.order_stats.production, data.order_stats.shipping, data.order_stats.completed ], backgroundColor: [ '#f39c12', '#3498db', '#9b59b6', '#2ecc71' ] }] }, options: { responsive: true, maintainAspectRatio: false } }); // 库存水平图表 const inventoryCtx = document.getElementById('inventory-chart').getContext('2d'); const productNames = data.inventory.map(item => item.product_name); const currentStock = data.inventory.map(item => item.current_stock); const safetyStock = data.inventory.map(item => item.safety_stock); const inventoryChart = new Chart(inventoryCtx, { type: 'bar', data: { labels: productNames, datasets: [ { label: '当前库存', data: currentStock, backgroundColor: '#3498db' }, { label: '安全库存', data: safetyStock, backgroundColor: '#e74c3c', type: 'line', fill: false } ] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true } } } }); } /** * 更新供应商表格 */ function updateTables(data) { // 更新供应商绩效表格 const supplierTableBody = document.getElementById('supplier-table-body'); supplierTableBody.innerHTML = ''; data.suppliers.forEach(supplier => { const row = document.createElement('tr'); row.innerHTML = ` <td>${supplier.name}</td> <td>${supplier.completion_rate}%</td> <td>${supplier.quality_score}/10</td> <td><span class="status-badge ${supplier.status}">${supplier.status_text}</span></td> `; supplierTableBody.appendChild(row); }); // 更新近期订单列表 const recentOrdersContainer = document.getElementById('recent-orders'); recentOrdersContainer.innerHTML = ''; data.recent_orders.forEach(order => { const orderItem = document.createElement('div'); orderItem.className = 'order-item'; orderItem.innerHTML = ` <div class="order-info"> <strong>${order.product_name}</strong> <div class="order-meta">订单号: ${order.order_number}</div> </div> <div class="order-status-info"> <span class="order-status status-${order.status}">${order.status_text}</span> <div class="order-date">${order.delivery_date}</div> </div> `; recentOrdersContainer.appendChild(orderItem); }); } /** * 手动刷新看板 */ function refreshDashboard() { const refreshBtn = document.querySelector('.refresh-btn'); const originalText = refreshBtn.textContent; refreshBtn.textContent = '刷新中...'; refreshBtn.disabled = true; loadDashboardData(); setTimeout(() => { refreshBtn.textContent = originalText; refreshBtn.disabled = false; }, 1000); }
-
- <?php /** * 供应链预警系统 */ class SupplyChainAlertSystem { /** * 检查库存预警 */ public static function check_inventory_alerts() { $alerts = array(); $products = get_posts(array( 'post_type' => 'supply_product', 'posts_per_page' => -1, )); foreach ($products as $product) { $current_stock = get_field('current_stock', $product->ID); $safety_stock = get_field('safety_stock_level', $product->ID); $product_name = get_the_title($product->ID); if ($current_stock <= $safety_stock) { $alerts[] = array( 'type' => 'inventory', 'level' => $current_stock == 0 ? 'critical' : 'warning', 'message' => sprintf( '产品 "%s" 库存不足!当前库存:%d,安全库存:%d', $product_name, $current_stock, $safety_stock ), 'product_id' => $product->ID, 'timestamp' => current_time('mysql') ); } } return $alerts; } /** * 检查订单延迟 */ public static function check_order_delays() { $alerts = array(); $today = current_time('Y-m-d'); $orders = get_posts(array( 'post_type' => 'supply_order', 'posts_per_page' => -1, 'meta_query' => array( 'relation' => 'AND', array( 'key' => 'order_status', 'value' => 'completed', 'compare' => '!=' ), array( 'key' => 'estimated_delivery_date', 'value' => $today, 'compare' => '<', 'type' => 'DATE' ) ) )); foreach ($orders as $order) { $estimated_date = get_field('estimated_delivery_date', $order->ID); $product_id = get_field('related_product', $order->ID); $product_name = get_the_title($product_id); $alerts[] = array( 'type' => 'order_delay', 'level' => 'warning', 'message' => sprintf( '订单 #%s (%s) 预计交付日期已过:%s', $order->ID, $product_name, $estimated_date ), 'order_id' => $order->ID, 'timestamp' => current_time('mysql') ); } return $alerts; } /** * 获取所有预警 */ public static function get_all_alerts() { $inventory_alerts = self::check_inventory_alerts(); $order_alerts = self::check_order_delays(); return array_merge($inventory_alerts, $order_alerts); } } /** * 注册预警API端点 */ function register_alert_api() { register_rest_route('supply-chain/v1', '/alerts', array( 'methods' => 'GET', 'callback' => 'get_supply_chain_alerts', 'permission_callback' => function() { return current_user_can('edit_posts'); } )); } add_action('rest_api_init', 'register_alert_api'); function get_supply_chain_alerts() { $alerts = SupplyChainAlertSystem::get_all_alerts(); return rest_ensure_response($alerts); } ?>
- /** * 预警通知系统 */ class AlertSystem { constructor() { this.alertContainer = null; this.init(); } init() { this.createAlertContainer(); this.loadAlerts(); setInterval(() => this.loadAlerts(), 60000); // 每分钟检查一次 } createAlertContainer() { const container = document.createElement('div'); container.id = 'supply-chain-alerts'; container.className = 'alert-container'; container.innerHTML = ` <div class="alert-header"> <h4>供应链预警</h4> <button class="alert-toggle">隐藏</button> </div> <div class="alert-list" id="alert-list"></div> `; document.querySelector('.supply-chain-dashboard').prepend(container); this.alertContainer = container; // 添加切换显示/隐藏功能 container.querySelector('.alert-toggle').addEventListener('click', () => { const list = container.querySelector('.alert-list'); const toggleBtn = container.querySelector('.alert-toggle'); if (list.style.display === 'none') { list.style.display = 'block'; toggleBtn.textContent = '隐藏'; } else { list.style.display = 'none'; toggleBtn.textContent = '显示'; } }); } async loadAlerts() { try { const response = await fetch('/wp-json/supply-chain/v1/alerts'); const alerts = await response.json(); this.displayAlerts(alerts); } catch (error) { console.error('加载预警失败:', error); } } displayAlerts(alerts) { const alertList = document.getElementById('alert-list'); if (alerts.length === 0) { alertList.innerHTML = '<div class="alert-item no-alerts">暂无预警信息</div>'; return; } let alertHTML = ''; alerts.forEach(alert => { const alertClass = `alert-item alert-${alert.level}`; const time = new Date(alert.timestamp).toLocaleTimeString(); alertHTML += ` <div class="${alertClass}"> <div class="alert-icon"> ${alert.level === 'critical' ? '⚠️' : 'ℹ️'} </div> <div class="alert-content"> <div class="alert-message">${alert.message}</div> <div class="alert-time">${time}</div> </div> </div> `; }); alertList.innerHTML = alertHTML; } } // 初始化预警系统 document.addEventListener('DOMContentLoaded', () => { new AlertSystem(); });
- /* 预警系统样式 */ .alert-container { background: white; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); overflow: hidden; } .alert-header { display: flex; justify-content: space-between; align-items: center; padding: 15px 20px; background-color: #f8f9fa; border-bottom: 1px solid #e9ecef; } .alert-header h4 { margin: 0; color: #2c3e50; } .alert-toggle { background: none; border: 1px solid #dee2e6; padding: 5px 15px; border-radius: 4px; cursor: pointer; font-size: 12px; } .alert-toggle:hover { background-color: #e9ecef; } .alert-list { max-height: 300px; overflow-y: auto; } .alert-item { display: flex; padding: 12px 20px; border-bottom: 1px solid #f1f3f4; align-items: flex-start; } .alert-item:last-child { border-bottom: none; } .alert-item.no-alerts { justify-content: center; color: #6c757d; font-style: italic; } .alert-item.alert-critical { background-color: #fff5f5; border-left: 4px solid #e53e3e; } .alert-item.alert-warning { background-color: #fffaf0; border-left: 4px solid #dd6b20; } .alert-icon { font-size: 18px; margin-right: 12px; margin-top: 2px; } .alert-content { flex: 1; } .alert-message { font-weight: 500; margin-bottom: 4px; } .alert-time { font-size: 12px; color: #6c757d; } .status-badge { padding: 4px 8px; border-radius: 12px; font-size: 12px; font-weight: bold; } .status-badge.active { background-color: #2ecc71; color: white; } .status-badge.inactive { background-color: #95a5a6; color: white; } .status-badge.warning { background-color: #f39c12; color: white; }
-
- <?php /** * 数据导出功能 */ class SupplyChainExporter { /** * 导出订单数据为CSV */ public static function export_orders_csv($start_date = null, $end_date = null) { $args = array( 'post_type' => 'supply_order', 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC' ); // 添加日期筛选 if ($start_date && $end_date) { $args['date_query'] = array( array( 'after' => $start_date, 'before' => $end_date, 'inclusive' => true ) ); } $orders = get_posts($args); // 设置CSV头部 $headers = array( '订单ID', '产品名称', '订单数量', '订单状态', '预计交付日期', '实际交付日期', '创建时间' ); $output = fopen('php://output', 'w'); fputcsv($output, $headers); foreach ($orders as $order) { $product_id = get_field('related_product', $order->ID); $product_name = $product_id ? get_the_title($product_id) : 'N/A'; $row = array( $order->ID, $product_name, get_field('order_quantity', $order->ID) ?: 0, self::get_status_text(get_field('order_status', $order->ID)), get_field('estimated_delivery_date', $order->ID) ?: '', get_field('actual_delivery_date', $order->ID) ?: '', get_the_date('Y-m-d H:i:s', $order->ID) ); fputcsv($output, $row); } fclose($output); } /** * 导出库存报告 */ public static function export_inventory_report() { $products = get_posts(array( 'post_type' => 'supply_product', 'posts_per_page' => -1, 'orderby' => 'title', 'order' => 'ASC' )); $headers = array( '产品ID', '产品名称', 'SKU', '当前库存', '安全库存', '库存状态', '关联供应商' ); $output = fopen('php://output', 'w'); fputcsv($output, $headers); foreach ($products as $product) { $current_stock = get_field('current_stock', $product->ID) ?: 0; $safety_stock = get_field('safety_stock_level', $product->ID) ?: 0; $sku = get_field('product_sku', $product->ID) ?: ''; $supplier_id = get_field('related_supplier', $product->ID); $supplier_name = $supplier_id ? get_the_title($supplier_id) : 'N/A'; $status = $current_stock <= $safety_stock ? '库存不足' : '正常'; $row = array( $product->ID, get_the_title($product->ID), $sku, $current_stock, $safety_stock, $status, $supplier_name ); fputcsv($output, $row); } fclose($output); } /** * 获取状态文本 */ private static function get_status_text($status) { $status_map = array( 'pending' => '待处理', 'production' => '生产中', 'shipping' => '运输中', 'completed' => '已完成' ); return $status_map[$status] ?? $status; } } /** * 注册导出API端点 */ function register_export_api() { register_rest_route('supply-chain/v1', '/export/orders', array( 'methods' => 'GET', 'callback' => 'handle_orders_export', 'permission_callback' => function() { return current_user_can('export'); } )); register_rest_route('supply-chain/v1', '/export/inventory', array( 'methods' => 'GET', 'callback' => 'handle_inventory_export', 'permission_callback' => function() { return current_user_can('export'); } )); } add_action('rest_api_init', 'register_export_api'); function handle_orders_export($request) { $start_date = $request->get_param('start_date'); $end_date = $request->get_param('end_date'); // 设置CSV头 header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename=orders_export_' . date('Y-m-d') . '.csv'); SupplyChainExporter::export_orders_csv($start_date, $end_date); exit; } function handle_inventory_export($request) { header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename=inventory_report_' . date('Y-m-d') . '.csv'); SupplyChainExporter::export_inventory_report(); exit; } ?>
- /** * 数据导出功能 */ class DataExporter { constructor() { this.initExportButtons(); } initExportButtons() { // 创建导出按钮容器 const exportContainer = document.createElement('div'); exportContainer.className = 'export-container'; exportContainer.innerHTML = ` <h4>数据导出</h4> <div class="export-buttons"> <button class="export-btn" data-type="orders">导出订单数据</button> <button class="export-btn" data-type="inventory">导出库存报告</button> </div> <div class="date-range" id="date-range-container" style="display: none;"> <h5>选择日期范围</h5> <div class="date-inputs"> <div> <label>开始日期:</label> <input type="date" id="start-date"> </div> <div> <label>结束日期:</label> <input type="date" id="end-date"> </div> </div> <button class="confirm-export">确认导出</button> </div> `; document.querySelector('.dashboard-header').appendChild(exportContainer); // 绑定按钮事件 document.querySelectorAll('.export-btn').forEach(button => { button.addEventListener('click', (e) => { const exportType = e.target.dataset.type; this.handleExport(exportType); }); }); document.querySelector('.confirm-export').addEventListener('click', () => { this.performExport(); }); } handleExport(type) { this.currentExportType = type; if (type === 'orders') { // 显示日期选择器 document.getElementById('date-range-container').style.display = 'block'; } else { // 直接导出库存报告 this.performExport(); } } performExport() { let url = ''; if (this.currentExportType === 'orders') { const startDate = document.getElementById('start-date').value; const endDate = document.getElementById('end-date').value; if (!startDate || !endDate) {
在当今全球化的商业环境中,供应链管理已成为企业成功的关键因素。柔性供应链可视化看板能够帮助企业实时监控物流状态、库存水平和订单进度,从而快速响应市场变化。本教程将指导您如何在WordPress平台上构建一个功能完善的柔性供应链可视化看板,无需昂贵的专业软件,即可实现供应链数据的直观展示与分析。
在开始开发之前,请确保您的WordPress环境满足以下要求:
- WordPress 5.0或更高版本
- PHP 7.4或更高版本
- 管理员权限
-
安装并激活以下插件:
- Advanced Custom Fields(用于自定义字段)
- 图表生成插件(如Data Tables Generator)
我们将创建三个自定义文章类型来管理供应链数据:供应商、产品和订单。
<?php
/**
* 注册供应链相关自定义文章类型
*/
function register_supply_chain_post_types() {
// 注册供应商类型
$supplier_labels = array(
'name' => '供应商',
'singular_name' => '供应商',
'add_new' => '添加供应商',
'add_new_item' => '添加新供应商',
'edit_item' => '编辑供应商',
'new_item' => '新供应商',
'view_item' => '查看供应商',
'search_items' => '搜索供应商',
'not_found' => '未找到供应商',
'not_found_in_trash' => '回收站中无供应商'
);
register_post_type('supplier', array(
'labels' => $supplier_labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-truck',
'supports' => array('title', 'editor', 'thumbnail'),
'show_in_rest' => true, // 启用Gutenberg编辑器支持
));
// 注册产品类型
$product_labels = array(
'name' => '供应链产品',
'singular_name' => '产品',
'add_new' => '添加产品',
'add_new_item' => '添加新产品',
'edit_item' => '编辑产品',
'new_item' => '新产品',
'view_item' => '查看产品',
'search_items' => '搜索产品',
);
register_post_type('supply_product', array(
'labels' => $product_labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-products',
'supports' => array('title', 'editor', 'thumbnail'),
'show_in_rest' => true,
));
// 注册订单类型
$order_labels = array(
'name' => '供应链订单',
'singular_name' => '订单',
'add_new' => '添加订单',
'add_new_item' => '添加新订单',
'edit_item' => '编辑订单',
'new_item' => '新订单',
'view_item' => '查看订单',
);
register_post_type('supply_order', array(
'labels' => $order_labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-clipboard',
'supports' => array('title'),
'show_in_rest' => true,
));
}
add_action('init', 'register_supply_chain_post_types');
?>
通过ACF插件创建以下字段组:
-
供应商字段组:
- 联系人姓名(文本)
- 联系电话(文本)
- 供应能力评级(选择:高/中/低)
- 地理位置(谷歌地图)
-
产品字段组:
- 产品SKU(文本)
- 当前库存(数字)
- 安全库存水平(数字)
- 关联供应商(关系字段)
-
订单字段组:
- 订单状态(选择:待处理/生产中/运输中/已完成)
- 订单数量(数字)
- 关联产品(关系字段)
- 预计交付日期(日期选择器)
- 实际交付日期(日期选择器)
<?php
/**
* 供应链可视化看板模板
* Template Name: 供应链可视化看板
*/
get_header(); ?>
<div class="supply-chain-dashboard">
<div class="dashboard-header">
<h1>柔性供应链可视化看板</h1>
<div class="last-updated">最后更新: <span id="update-time"><?php echo current_time('Y-m-d H:i:s'); ?></span></div>
<button class="refresh-btn" onclick="refreshDashboard()">刷新数据</button>
</div>
<div class="dashboard-grid">
<!-- 关键指标卡片 -->
<div class="dashboard-card metrics-card">
<h3>关键绩效指标</h3>
<div class="metrics-grid">
<div class="metric-item">
<div class="metric-value" id="total-orders">0</div>
<div class="metric-label">总订单数</div>
</div>
<div class="metric-item">
<div class="metric-value" id="pending-orders">0</div>
<div class="metric-label">待处理订单</div>
</div>
<div class="metric-item">
<div class="metric-value" id="on-time-delivery">0%</div>
<div class="metric-label">准时交付率</div>
</div>
<div class="metric-item">
<div class="metric-value" id="inventory-alerts">0</div>
<div class="metric-label">库存预警</div>
</div>
</div>
</div>
<!-- 订单状态图表 -->
<div class="dashboard-card chart-card">
<h3>订单状态分布</h3>
<canvas id="order-status-chart" width="400" height="300"></canvas>
</div>
<!-- 库存水平图表 -->
<div class="dashboard-card chart-card">
<h3>库存水平监控</h3>
<canvas id="inventory-chart" width="400" height="300"></canvas>
</div>
<!-- 供应商绩效表格 -->
<div class="dashboard-card table-card">
<h3>供应商绩效排名</h3>
<table id="supplier-performance-table">
<thead>
<tr>
<th>供应商</th>
<th>订单完成率</th>
<th>准时率</th>
<th>质量评分</th>
<th>状态</th>
</tr>
</thead>
<tbody id="supplier-table-body">
<!-- 数据将通过AJAX加载 -->
</tbody>
</table>
</div>
<!-- 实时订单列表 -->
<div class="dashboard-card orders-card">
<h3>近期订单状态</h3>
<div class="orders-list" id="recent-orders">
<!-- 订单数据将通过AJAX加载 -->
</div>
</div>
</div>
</div>
<?php get_footer(); ?>
<?php
/**
* 供应链可视化看板模板
* Template Name: 供应链可视化看板
*/
get_header(); ?>
<div class="supply-chain-dashboard">
<div class="dashboard-header">
<h1>柔性供应链可视化看板</h1>
<div class="last-updated">最后更新: <span id="update-time"><?php echo current_time('Y-m-d H:i:s'); ?></span></div>
<button class="refresh-btn" onclick="refreshDashboard()">刷新数据</button>
</div>
<div class="dashboard-grid">
<!-- 关键指标卡片 -->
<div class="dashboard-card metrics-card">
<h3>关键绩效指标</h3>
<div class="metrics-grid">
<div class="metric-item">
<div class="metric-value" id="total-orders">0</div>
<div class="metric-label">总订单数</div>
</div>
<div class="metric-item">
<div class="metric-value" id="pending-orders">0</div>
<div class="metric-label">待处理订单</div>
</div>
<div class="metric-item">
<div class="metric-value" id="on-time-delivery">0%</div>
<div class="metric-label">准时交付率</div>
</div>
<div class="metric-item">
<div class="metric-value" id="inventory-alerts">0</div>
<div class="metric-label">库存预警</div>
</div>
</div>
</div>
<!-- 订单状态图表 -->
<div class="dashboard-card chart-card">
<h3>订单状态分布</h3>
<canvas id="order-status-chart" width="400" height="300"></canvas>
</div>
<!-- 库存水平图表 -->
<div class="dashboard-card chart-card">
<h3>库存水平监控</h3>
<canvas id="inventory-chart" width="400" height="300"></canvas>
</div>
<!-- 供应商绩效表格 -->
<div class="dashboard-card table-card">
<h3>供应商绩效排名</h3>
<table id="supplier-performance-table">
<thead>
<tr>
<th>供应商</th>
<th>订单完成率</th>
<th>准时率</th>
<th>质量评分</th>
<th>状态</th>
</tr>
</thead>
<tbody id="supplier-table-body">
<!-- 数据将通过AJAX加载 -->
</tbody>
</table>
</div>
<!-- 实时订单列表 -->
<div class="dashboard-card orders-card">
<h3>近期订单状态</h3>
<div class="orders-list" id="recent-orders">
<!-- 订单数据将通过AJAX加载 -->
</div>
</div>
</div>
</div>
<?php get_footer(); ?>
/* 供应链看板样式 */
.supply-chain-dashboard {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.dashboard-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid #e0e6ed;
}
.dashboard-header h1 {
color: #2c3e50;
margin: 0;
}
.last-updated {
color: #7f8c8d;
font-size: 14px;
}
.refresh-btn {
background-color: #3498db;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
.refresh-btn:hover {
background-color: #2980b9;
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 20px;
}
.dashboard-card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.dashboard-card h3 {
margin-top: 0;
color: #34495e;
border-bottom: 1px solid #ecf0f1;
padding-bottom: 10px;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
}
.metric-item {
text-align: center;
padding: 15px;
background-color: #f8f9fa;
border-radius: 6px;
}
.metric-value {
font-size: 28px;
font-weight: bold;
color: #2c3e50;
}
.metric-label {
font-size: 14px;
color: #7f8c8d;
margin-top: 5px;
}
.orders-list {
max-height: 300px;
overflow-y: auto;
}
.order-item {
padding: 10px;
border-bottom: 1px solid #ecf0f1;
display: flex;
justify-content: space-between;
}
.order-item:last-child {
border-bottom: none;
}
.order-status {
padding: 3px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
}
.status-pending { background-color: #f39c12; color: white; }
.status-production { background-color: #3498db; color: white; }
.status-shipping { background-color: #9b59b6; color: white; }
.status-completed { background-color: #2ecc71; color: white; }
#supplier-performance-table {
width: 100%;
border-collapse: collapse;
}
#supplier-performance-table th,
#supplier-performance-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
#supplier-performance-table th {
background-color: #f2f6fc;
font-weight: bold;
}
/* 供应链看板样式 */
.supply-chain-dashboard {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
.dashboard-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid #e0e6ed;
}
.dashboard-header h1 {
color: #2c3e50;
margin: 0;
}
.last-updated {
color: #7f8c8d;
font-size: 14px;
}
.refresh-btn {
background-color: #3498db;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
.refresh-btn:hover {
background-color: #2980b9;
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 20px;
}
.dashboard-card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.dashboard-card h3 {
margin-top: 0;
color: #34495e;
border-bottom: 1px solid #ecf0f1;
padding-bottom: 10px;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
}
.metric-item {
text-align: center;
padding: 15px;
background-color: #f8f9fa;
border-radius: 6px;
}
.metric-value {
font-size: 28px;
font-weight: bold;
color: #2c3e50;
}
.metric-label {
font-size: 14px;
color: #7f8c8d;
margin-top: 5px;
}
.orders-list {
max-height: 300px;
overflow-y: auto;
}
.order-item {
padding: 10px;
border-bottom: 1px solid #ecf0f1;
display: flex;
justify-content: space-between;
}
.order-item:last-child {
border-bottom: none;
}
.order-status {
padding: 3px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
}
.status-pending { background-color: #f39c12; color: white; }
.status-production { background-color: #3498db; color: white; }
.status-shipping { background-color: #9b59b6; color: white; }
.status-completed { background-color: #2ecc71; color: white; }
#supplier-performance-table {
width: 100%;
border-collapse: collapse;
}
#supplier-performance-table th,
#supplier-performance-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
#supplier-performance-table th {
background-color: #f2f6fc;
font-weight: bold;
}
<?php
/**
* 注册供应链数据API端点
*/
function register_supply_chain_api() {
register_rest_route('supply-chain/v1', '/dashboard-data', array(
'methods' => 'GET',
'callback' => 'get_dashboard_data',
'permission_callback' => function() {
return current_user_can('edit_posts'); // 仅限有编辑权限的用户
}
));
register_rest_route('supply-chain/v1', '/refresh-data', array(
'methods' => 'POST',
'callback' => 'refresh_dashboard_data',
'permission_callback' => function() {
return current_user_can('edit_posts');
}
));
}
add_action('rest_api_init', 'register_supply_chain_api');
/**
* 获取看板数据
*/
function get_dashboard_data() {
$data = array();
// 获取订单统计数据
$order_stats = get_order_statistics();
$data['order_stats'] = $order_stats;
// 获取库存数据
$inventory_data = get_inventory_data();
$data['inventory'] = $inventory_data;
// 获取供应商绩效数据
$supplier_performance = get_supplier_performance();
$data['suppliers'] = $supplier_performance;
// 获取最近订单
$recent_orders = get_recent_orders(10);
$data['recent_orders'] = $recent_orders;
// 计算关键指标
$data['metrics'] = calculate_key_metrics($order_stats, $inventory_data);
return rest_ensure_response($data);
}
/**
* 获取订单统计数据
*/
function get_order_statistics() {
$statuses = array('pending', 'production', 'shipping', 'completed');
$stats = array();
foreach ($statuses as $status) {
$args = array(
'post_type' => 'supply_order',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'order_status',
'value' => $status,
'compare' => '='
)
)
);
$query = new WP_Query($args);
$stats[$status] = $query->found_posts;
}
return $stats;
}
/**
* 获取库存数据
*/
function get_inventory_data() {
$inventory = array();
$args = array(
'post_type' => 'supply_product',
'posts_per_page' => -1,
);
$query = new WP_Query($args);
while ($query->have_posts()) {
$query->the_post();
$product_id = get_the_ID();
$current_stock = get_field('current_stock', $product_id);
$safety_stock = get_field('safety_stock_level', $product_id);
$inventory[] = array(
'product_name' => get_the_title(),
'current_stock' => $current_stock ?: 0,
'safety_stock' => $safety_stock ?: 10,
'status' => $current_stock <= $safety_stock ? 'low' : 'normal'
);
}
wp_reset_postdata();
return $inventory;
}
?>
<?php
/**
* 注册供应链数据API端点
*/
function register_supply_chain_api() {
register_rest_route('supply-chain/v1', '/dashboard-data', array(
'methods' => 'GET',
'callback' => 'get_dashboard_data',
'permission_callback' => function() {
return current_user_can('edit_posts'); // 仅限有编辑权限的用户
}
));
register_rest_route('supply-chain/v1', '/refresh-data', array(
'methods' => 'POST',
'callback' => 'refresh_dashboard_data',
'permission_callback' => function() {
return current_user_can('edit_posts');
}
));
}
add_action('rest_api_init', 'register_supply_chain_api');
/**
* 获取看板数据
*/
function get_dashboard_data() {
$data = array();
// 获取订单统计数据
$order_stats = get_order_statistics();
$data['order_stats'] = $order_stats;
// 获取库存数据
$inventory_data = get_inventory_data();
$data['inventory'] = $inventory_data;
// 获取供应商绩效数据
$supplier_performance = get_supplier_performance();
$data['suppliers'] = $supplier_performance;
// 获取最近订单
$recent_orders = get_recent_orders(10);
$data['recent_orders'] = $recent_orders;
// 计算关键指标
$data['metrics'] = calculate_key_metrics($order_stats, $inventory_data);
return rest_ensure_response($data);
}
/**
* 获取订单统计数据
*/
function get_order_statistics() {
$statuses = array('pending', 'production', 'shipping', 'completed');
$stats = array();
foreach ($statuses as $status) {
$args = array(
'post_type' => 'supply_order',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'order_status',
'value' => $status,
'compare' => '='
)
)
);
$query = new WP_Query($args);
$stats[$status] = $query->found_posts;
}
return $stats;
}
/**
* 获取库存数据
*/
function get_inventory_data() {
$inventory = array();
$args = array(
'post_type' => 'supply_product',
'posts_per_page' => -1,
);
$query = new WP_Query($args);
while ($query->have_posts()) {
$query->the_post();
$product_id = get_the_ID();
$current_stock = get_field('current_stock', $product_id);
$safety_stock = get_field('safety_stock_level', $product_id);
$inventory[] = array(
'product_name' => get_the_title(),
'current_stock' => $current_stock ?: 0,
'safety_stock' => $safety_stock ?: 10,
'status' => $current_stock <= $safety_stock ? 'low' : 'normal'
);
}
wp_reset_postdata();
return $inventory;
}
?>
/**
* 供应链看板数据交互脚本
*/
document.addEventListener('DOMContentLoaded', function() {
// 初始化看板
loadDashboardData();
// 设置自动刷新(每5分钟)
setInterval(loadDashboardData, 300000);
});
/**
* 加载看板数据
*/
function loadDashboardData() {
// 显示加载状态
document.getElementById('update-time').textContent = '加载中...';
// 获取API数据
fetch('/wp-json/supply-chain/v1/dashboard-data')
.then(response => response.json())
.then(data => {
updateDashboard(data);
updateCharts(data);
updateTables(data);
// 更新最后刷新时间
const now = new Date();
document.getElementById('update-time').textContent =
now.toLocaleDateString() + ' ' + now.toLocaleTimeString();
})
.catch(error => {
console.error('加载数据失败:', error);
document.getElementById('update-time').textContent = '加载失败';
});
}
/**
* 更新关键指标
*/
function updateDashboard(data) {
const metrics = data.metrics;
document.getElementById('total-orders').textContent = metrics.total_orders;
document.getElementById('pending-orders').textContent = metrics.pending_orders;
document.getElementById('on-time-delivery').textContent = metrics.on_time_delivery + '%';
document.getElementById('inventory-alerts').textContent = metrics.inventory_alerts;
}
/**
* 更新图表
*/
function updateCharts(data) {
// 订单状态图表
const orderCtx = document.getElementById('order-status-chart').getContext('2d');
const orderChart = new Chart(orderCtx, {
type: 'doughnut',
data: {
labels: ['待处理', '生产中', '运输中', '已完成'],
datasets: [{
data: [
data.order_stats.pending,
data.order_stats.production,
data.order_stats.shipping,
data.order_stats.completed
],
backgroundColor: [
'#f39c12',
'#3498db',
'#9b59b6',
'#2ecc71'
]
}]
},
options: {
responsive: true,
maintainAspectRatio: false
}
});
// 库存水平图表
const inventoryCtx = document.getElementById('inventory-chart').getContext('2d');
const productNames = data.inventory.map(item => item.product_name);
const currentStock = data.inventory.map(item => item.current_stock);
const safetyStock = data.inventory.map(item => item.safety_stock);
const inventoryChart = new Chart(inventoryCtx, {
type: 'bar',
data: {
labels: productNames,
datasets: [
{
label: '当前库存',
data: currentStock,
backgroundColor: '#3498db'
},
{
label: '安全库存',
data: safetyStock,
backgroundColor: '#e74c3c',
type: 'line',
fill: false
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});
}
/**
* 更新供应商表格
*/
function updateTables(data) {
// 更新供应商绩效表格
const supplierTableBody = document.getElementById('supplier-table-body');
supplierTableBody.innerHTML = '';
data.suppliers.forEach(supplier => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${supplier.name}</td>
<td>${supplier.completion_rate}%</td>
<td>${supplier.quality_score}/10</td>
<td><span class="status-badge ${supplier.status}">${supplier.status_text}</span></td>
`;
supplierTableBody.appendChild(row);
});
// 更新近期订单列表
const recentOrdersContainer = document.getElementById('recent-orders');
recentOrdersContainer.innerHTML = '';
data.recent_orders.forEach(order => {
const orderItem = document.createElement('div');
orderItem.className = 'order-item';
orderItem.innerHTML = `
<div class="order-info">
<strong>${order.product_name}</strong>
<div class="order-meta">订单号: ${order.order_number}</div>
</div>
<div class="order-status-info">
<span class="order-status status-${order.status}">${order.status_text}</span>
<div class="order-date">${order.delivery_date}</div>
</div>
`;
recentOrdersContainer.appendChild(orderItem);
});
}
/**
* 手动刷新看板
*/
function refreshDashboard() {
const refreshBtn = document.querySelector('.refresh-btn');
const originalText = refreshBtn.textContent;
refreshBtn.textContent = '刷新中...';
refreshBtn.disabled = true;
loadDashboardData();
setTimeout(() => {
refreshBtn.textContent = originalText;
refreshBtn.disabled = false;
}, 1000);
}
/**
* 供应链看板数据交互脚本
*/
document.addEventListener('DOMContentLoaded', function() {
// 初始化看板
loadDashboardData();
// 设置自动刷新(每5分钟)
setInterval(loadDashboardData, 300000);
});
/**
* 加载看板数据
*/
function loadDashboardData() {
// 显示加载状态
document.getElementById('update-time').textContent = '加载中...';
// 获取API数据
fetch('/wp-json/supply-chain/v1/dashboard-data')
.then(response => response.json())
.then(data => {
updateDashboard(data);
updateCharts(data);
updateTables(data);
// 更新最后刷新时间
const now = new Date();
document.getElementById('update-time').textContent =
now.toLocaleDateString() + ' ' + now.toLocaleTimeString();
})
.catch(error => {
console.error('加载数据失败:', error);
document.getElementById('update-time').textContent = '加载失败';
});
}
/**
* 更新关键指标
*/
function updateDashboard(data) {
const metrics = data.metrics;
document.getElementById('total-orders').textContent = metrics.total_orders;
document.getElementById('pending-orders').textContent = metrics.pending_orders;
document.getElementById('on-time-delivery').textContent = metrics.on_time_delivery + '%';
document.getElementById('inventory-alerts').textContent = metrics.inventory_alerts;
}
/**
* 更新图表
*/
function updateCharts(data) {
// 订单状态图表
const orderCtx = document.getElementById('order-status-chart').getContext('2d');
const orderChart = new Chart(orderCtx, {
type: 'doughnut',
data: {
labels: ['待处理', '生产中', '运输中', '已完成'],
datasets: [{
data: [
data.order_stats.pending,
data.order_stats.production,
data.order_stats.shipping,
data.order_stats.completed
],
backgroundColor: [
'#f39c12',
'#3498db',
'#9b59b6',
'#2ecc71'
]
}]
},
options: {
responsive: true,
maintainAspectRatio: false
}
});
// 库存水平图表
const inventoryCtx = document.getElementById('inventory-chart').getContext('2d');
const productNames = data.inventory.map(item => item.product_name);
const currentStock = data.inventory.map(item => item.current_stock);
const safetyStock = data.inventory.map(item => item.safety_stock);
const inventoryChart = new Chart(inventoryCtx, {
type: 'bar',
data: {
labels: productNames,
datasets: [
{
label: '当前库存',
data: currentStock,
backgroundColor: '#3498db'
},
{
label: '安全库存',
data: safetyStock,
backgroundColor: '#e74c3c',
type: 'line',
fill: false
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});
}
/**
* 更新供应商表格
*/
function updateTables(data) {
// 更新供应商绩效表格
const supplierTableBody = document.getElementById('supplier-table-body');
supplierTableBody.innerHTML = '';
data.suppliers.forEach(supplier => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${supplier.name}</td>
<td>${supplier.completion_rate}%</td>
<td>${supplier.quality_score}/10</td>
<td><span class="status-badge ${supplier.status}">${supplier.status_text}</span></td>
`;
supplierTableBody.appendChild(row);
});
// 更新近期订单列表
const recentOrdersContainer = document.getElementById('recent-orders');
recentOrdersContainer.innerHTML = '';
data.recent_orders.forEach(order => {
const orderItem = document.createElement('div');
orderItem.className = 'order-item';
orderItem.innerHTML = `
<div class="order-info">
<strong>${order.product_name}</strong>
<div class="order-meta">订单号: ${order.order_number}</div>
</div>
<div class="order-status-info">
<span class="order-status status-${order.status}">${order.status_text}</span>
<div class="order-date">${order.delivery_date}</div>
</div>
`;
recentOrdersContainer.appendChild(orderItem);
});
}
/**
* 手动刷新看板
*/
function refreshDashboard() {
const refreshBtn = document.querySelector('.refresh-btn');
const originalText = refreshBtn.textContent;
refreshBtn.textContent = '刷新中...';
refreshBtn.disabled = true;
loadDashboardData();
setTimeout(() => {
refreshBtn.textContent = originalText;
refreshBtn.disabled = false;
}, 1000);
}
<?php
/**
* 供应链预警系统
*/
class SupplyChainAlertSystem {
/**
* 检查库存预警
*/
public static function check_inventory_alerts() {
$alerts = array();
$products = get_posts(array(
'post_type' => 'supply_product',
'posts_per_page' => -1,
));
foreach ($products as $product) {
$current_stock = get_field('current_stock', $product->ID);
$safety_stock = get_field('safety_stock_level', $product->ID);
$product_name = get_the_title($product->ID);
if ($current_stock <= $safety_stock) {
$alerts[] = array(
'type' => 'inventory',
'level' => $current_stock == 0 ? 'critical' : 'warning',
'message' => sprintf(
'产品 "%s" 库存不足!当前库存:%d,安全库存:%d',
$product_name,
$current_stock,
$safety_stock
),
'product_id' => $product->ID,
'timestamp' => current_time('mysql')
);
}
}
return $alerts;
}
/**
* 检查订单延迟
*/
public static function check_order_delays() {
$alerts = array();
$today = current_time('Y-m-d');
$orders = get_posts(array(
'post_type' => 'supply_order',
'posts_per_page' => -1,
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'order_status',
'value' => 'completed',
'compare' => '!='
),
array(
'key' => 'estimated_delivery_date',
'value' => $today,
'compare' => '<',
'type' => 'DATE'
)
)
));
foreach ($orders as $order) {
$estimated_date = get_field('estimated_delivery_date', $order->ID);
$product_id = get_field('related_product', $order->ID);
$product_name = get_the_title($product_id);
$alerts[] = array(
'type' => 'order_delay',
'level' => 'warning',
'message' => sprintf(
'订单 #%s (%s) 预计交付日期已过:%s',
$order->ID,
$product_name,
$estimated_date
),
'order_id' => $order->ID,
'timestamp' => current_time('mysql')
);
}
return $alerts;
}
/**
* 获取所有预警
*/
public static function get_all_alerts() {
$inventory_alerts = self::check_inventory_alerts();
$order_alerts = self::check_order_delays();
return array_merge($inventory_alerts, $order_alerts);
}
}
/**
* 注册预警API端点
*/
function register_alert_api() {
register_rest_route('supply-chain/v1', '/alerts', array(
'methods' => 'GET',
'callback' => 'get_supply_chain_alerts',
'permission_callback' => function() {
return current_user_can('edit_posts');
}
));
}
add_action('rest_api_init', 'register_alert_api');
function get_supply_chain_alerts() {
$alerts = SupplyChainAlertSystem::get_all_alerts();
return rest_ensure_response($alerts);
}
?>
<?php
/**
* 供应链预警系统
*/
class SupplyChainAlertSystem {
/**
* 检查库存预警
*/
public static function check_inventory_alerts() {
$alerts = array();
$products = get_posts(array(
'post_type' => 'supply_product',
'posts_per_page' => -1,
));
foreach ($products as $product) {
$current_stock = get_field('current_stock', $product->ID);
$safety_stock = get_field('safety_stock_level', $product->ID);
$product_name = get_the_title($product->ID);
if ($current_stock <= $safety_stock) {
$alerts[] = array(
'type' => 'inventory',
'level' => $current_stock == 0 ? 'critical' : 'warning',
'message' => sprintf(
'产品 "%s" 库存不足!当前库存:%d,安全库存:%d',
$product_name,
$current_stock,
$safety_stock
),
'product_id' => $product->ID,
'timestamp' => current_time('mysql')
);
}
}
return $alerts;
}
/**
* 检查订单延迟
*/
public static function check_order_delays() {
$alerts = array();
$today = current_time('Y-m-d');
$orders = get_posts(array(
'post_type' => 'supply_order',
'posts_per_page' => -1,
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'order_status',
'value' => 'completed',
'compare' => '!='
),
array(
'key' => 'estimated_delivery_date',
'value' => $today,
'compare' => '<',
'type' => 'DATE'
)
)
));
foreach ($orders as $order) {
$estimated_date = get_field('estimated_delivery_date', $order->ID);
$product_id = get_field('related_product', $order->ID);
$product_name = get_the_title($product_id);
$alerts[] = array(
'type' => 'order_delay',
'level' => 'warning',
'message' => sprintf(
'订单 #%s (%s) 预计交付日期已过:%s',
$order->ID,
$product_name,
$estimated_date
),
'order_id' => $order->ID,
'timestamp' => current_time('mysql')
);
}
return $alerts;
}
/**
* 获取所有预警
*/
public static function get_all_alerts() {
$inventory_alerts = self::check_inventory_alerts();
$order_alerts = self::check_order_delays();
return array_merge($inventory_alerts, $order_alerts);
}
}
/**
* 注册预警API端点
*/
function register_alert_api() {
register_rest_route('supply-chain/v1', '/alerts', array(
'methods' => 'GET',
'callback' => 'get_supply_chain_alerts',
'permission_callback' => function() {
return current_user_can('edit_posts');
}
));
}
add_action('rest_api_init', 'register_alert_api');
function get_supply_chain_alerts() {
$alerts = SupplyChainAlertSystem::get_all_alerts();
return rest_ensure_response($alerts);
}
?>
/**
* 预警通知系统
*/
class AlertSystem {
constructor() {
this.alertContainer = null;
this.init();
}
init() {
this.createAlertContainer();
this.loadAlerts();
setInterval(() => this.loadAlerts(), 60000); // 每分钟检查一次
}
createAlertContainer() {
const container = document.createElement('div');
container.id = 'supply-chain-alerts';
container.className = 'alert-container';
container.innerHTML = `
<div class="alert-header">
<h4>供应链预警</h4>
<button class="alert-toggle">隐藏</button>
</div>
<div class="alert-list" id="alert-list"></div>
`;
document.querySelector('.supply-chain-dashboard').prepend(container);
this.alertContainer = container;
// 添加切换显示/隐藏功能
container.querySelector('.alert-toggle').addEventListener('click', () => {
const list = container.querySelector('.alert-list');
const toggleBtn = container.querySelector('.alert-toggle');
if (list.style.display === 'none') {
list.style.display = 'block';
toggleBtn.textContent = '隐藏';
} else {
list.style.display = 'none';
toggleBtn.textContent = '显示';
}
});
}
async loadAlerts() {
try {
const response = await fetch('/wp-json/supply-chain/v1/alerts');
const alerts = await response.json();
this.displayAlerts(alerts);
} catch (error) {
console.error('加载预警失败:', error);
}
}
displayAlerts(alerts) {
const alertList = document.getElementById('alert-list');
if (alerts.length === 0) {
alertList.innerHTML = '<div class="alert-item no-alerts">暂无预警信息</div>';
return;
}
let alertHTML = '';
alerts.forEach(alert => {
const alertClass = `alert-item alert-${alert.level}`;
const time = new Date(alert.timestamp).toLocaleTimeString();
alertHTML += `
<div class="${alertClass}">
<div class="alert-icon">
${alert.level === 'critical' ? '⚠️' : 'ℹ️'}
</div>
<div class="alert-content">
<div class="alert-message">${alert.message}</div>
<div class="alert-time">${time}</div>
</div>
</div>
`;
});
alertList.innerHTML = alertHTML;
}
}
// 初始化预警系统
document.addEventListener('DOMContentLoaded', () => {
new AlertSystem();
});
/**
* 预警通知系统
*/
class AlertSystem {
constructor() {
this.alertContainer = null;
this.init();
}
init() {
this.createAlertContainer();
this.loadAlerts();
setInterval(() => this.loadAlerts(), 60000); // 每分钟检查一次
}
createAlertContainer() {
const container = document.createElement('div');
container.id = 'supply-chain-alerts';
container.className = 'alert-container';
container.innerHTML = `
<div class="alert-header">
<h4>供应链预警</h4>
<button class="alert-toggle">隐藏</button>
</div>
<div class="alert-list" id="alert-list"></div>
`;
document.querySelector('.supply-chain-dashboard').prepend(container);
this.alertContainer = container;
// 添加切换显示/隐藏功能
container.querySelector('.alert-toggle').addEventListener('click', () => {
const list = container.querySelector('.alert-list');
const toggleBtn = container.querySelector('.alert-toggle');
if (list.style.display === 'none') {
list.style.display = 'block';
toggleBtn.textContent = '隐藏';
} else {
list.style.display = 'none';
toggleBtn.textContent = '显示';
}
});
}
async loadAlerts() {
try {
const response = await fetch('/wp-json/supply-chain/v1/alerts');
const alerts = await response.json();
this.displayAlerts(alerts);
} catch (error) {
console.error('加载预警失败:', error);
}
}
displayAlerts(alerts) {
const alertList = document.getElementById('alert-list');
if (alerts.length === 0) {
alertList.innerHTML = '<div class="alert-item no-alerts">暂无预警信息</div>';
return;
}
let alertHTML = '';
alerts.forEach(alert => {
const alertClass = `alert-item alert-${alert.level}`;
const time = new Date(alert.timestamp).toLocaleTimeString();
alertHTML += `
<div class="${alertClass}">
<div class="alert-icon">
${alert.level === 'critical' ? '⚠️' : 'ℹ️'}
</div>
<div class="alert-content">
<div class="alert-message">${alert.message}</div>
<div class="alert-time">${time}</div>
</div>
</div>
`;
});
alertList.innerHTML = alertHTML;
}
}
// 初始化预警系统
document.addEventListener('DOMContentLoaded', () => {
new AlertSystem();
});
/* 预警系统样式 */
.alert-container {
background: white;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.alert-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
background-color: #f8f9fa;
border-bottom: 1px solid #e9ecef;
}
.alert-header h4 {
margin: 0;
color: #2c3e50;
}
.alert-toggle {
background: none;
border: 1px solid #dee2e6;
padding: 5px 15px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
}
.alert-toggle:hover {
background-color: #e9ecef;
}
.alert-list {
max-height: 300px;
overflow-y: auto;
}
.alert-item {
display: flex;
padding: 12px 20px;
border-bottom: 1px solid #f1f3f4;
align-items: flex-start;
}
.alert-item:last-child {
border-bottom: none;
}
.alert-item.no-alerts {
justify-content: center;
color: #6c757d;
font-style: italic;
}
.alert-item.alert-critical {
background-color: #fff5f5;
border-left: 4px solid #e53e3e;
}
.alert-item.alert-warning {
background-color: #fffaf0;
border-left: 4px solid #dd6b20;
}
.alert-icon {
font-size: 18px;
margin-right: 12px;
margin-top: 2px;
}
.alert-content {
flex: 1;
}
.alert-message {
font-weight: 500;
margin-bottom: 4px;
}
.alert-time {
font-size: 12px;
color: #6c757d;
}
.status-badge {
padding: 4px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
}
.status-badge.active {
background-color: #2ecc71;
color: white;
}
.status-badge.inactive {
background-color: #95a5a6;
color: white;
}
.status-badge.warning {
background-color: #f39c12;
color: white;
}
/* 预警系统样式 */
.alert-container {
background: white;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.alert-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
background-color: #f8f9fa;
border-bottom: 1px solid #e9ecef;
}
.alert-header h4 {
margin: 0;
color: #2c3e50;
}
.alert-toggle {
background: none;
border: 1px solid #dee2e6;
padding: 5px 15px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
}
.alert-toggle:hover {
background-color: #e9ecef;
}
.alert-list {
max-height: 300px;
overflow-y: auto;
}
.alert-item {
display: flex;
padding: 12px 20px;
border-bottom: 1px solid #f1f3f4;
align-items: flex-start;
}
.alert-item:last-child {
border-bottom: none;
}
.alert-item.no-alerts {
justify-content: center;
color: #6c757d;
font-style: italic;
}
.alert-item.alert-critical {
background-color: #fff5f5;
border-left: 4px solid #e53e3e;
}
.alert-item.alert-warning {
background-color: #fffaf0;
border-left: 4px solid #dd6b20;
}
.alert-icon {
font-size: 18px;
margin-right: 12px;
margin-top: 2px;
}
.alert-content {
flex: 1;
}
.alert-message {
font-weight: 500;
margin-bottom: 4px;
}
.alert-time {
font-size: 12px;
color: #6c757d;
}
.status-badge {
padding: 4px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
}
.status-badge.active {
background-color: #2ecc71;
color: white;
}
.status-badge.inactive {
background-color: #95a5a6;
color: white;
}
.status-badge.warning {
background-color: #f39c12;
color: white;
}
<?php
/**
* 数据导出功能
*/
class SupplyChainExporter {
/**
* 导出订单数据为CSV
*/
public static function export_orders_csv($start_date = null, $end_date = null) {
$args = array(
'post_type' => 'supply_order',
'posts_per_page' => -1,
'orderby' => 'date',
'order' => 'DESC'
);
// 添加日期筛选
if ($start_date && $end_date) {
$args['date_query'] = array(
array(
'after' => $start_date,
'before' => $end_date,
'inclusive' => true
)
);
}
$orders = get_posts($args);
// 设置CSV头部
$headers = array(
'订单ID',
'产品名称',
'订单数量',
'订单状态',
'预计交付日期',
'实际交付日期',
'创建时间'
);
$output = fopen('php://output', 'w');
fputcsv($output, $headers);
foreach ($orders as $order) {
$product_id = get_field('related_product', $order->ID);
$product_name = $product_id ? get_the_title($product_id) : 'N/A';
$row = array(
$order->ID,
$product_name,
get_field('order_quantity', $order->ID) ?: 0,
self::get_status_text(get_field('order_status', $order->ID)),
get_field('estimated_delivery_date', $order->ID) ?: '',
get_field('actual_delivery_date', $order->ID) ?: '',
get_the_date('Y-m-d H:i:s', $order->ID)
);
fputcsv($output, $row);
}
fclose($output);
}
/**
* 导出库存报告
*/
public static function export_inventory_report() {
$products = get_posts(array(
'post_type' => 'supply_product',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC'
));
$headers = array(
'产品ID',
'产品名称',
'SKU',
'当前库存',
'安全库存',
'库存状态',
'关联供应商'
);
$output = fopen('php://output', 'w');
fputcsv($output, $headers);
foreach ($products as $product) {
$current_stock = get_field('current_stock', $product->ID) ?: 0;
$safety_stock = get_field('safety_stock_level', $product->ID) ?: 0;
$sku = get_field('product_sku', $product->ID) ?: '';
$supplier_id = get_field('related_supplier', $product->ID);
$supplier_name = $supplier_id ? get_the_title($supplier_id) : 'N/A';
$status = $current_stock <= $safety_stock ? '库存不足' : '正常';
$row = array(
$product->ID,
get_the_title($product->ID),
$sku,
$current_stock,
$safety_stock,
$status,
$supplier_name
);
fputcsv($output, $row);
}
fclose($output);
}
/**
* 获取状态文本
*/
private static function get_status_text($status) {
$status_map = array(
'pending' => '待处理',
'production' => '生产中',
'shipping' => '运输中',
'completed' => '已完成'
);
return $status_map[$status] ?? $status;
}
}
/**
* 注册导出API端点
*/
function register_export_api() {
register_rest_route('supply-chain/v1', '/export/orders', array(
'methods' => 'GET',
'callback' => 'handle_orders_export',
'permission_callback' => function() {
return current_user_can('export');
}
));
register_rest_route('supply-chain/v1', '/export/inventory', array(
'methods' => 'GET',
'callback' => 'handle_inventory_export',
'permission_callback' => function() {
return current_user_can('export');
}
));
}
add_action('rest_api_init', 'register_export_api');
function handle_orders_export($request) {
$start_date = $request->get_param('start_date');
$end_date = $request->get_param('end_date');
// 设置CSV头
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=orders_export_' . date('Y-m-d') . '.csv');
SupplyChainExporter::export_orders_csv($start_date, $end_date);
exit;
}
function handle_inventory_export($request) {
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=inventory_report_' . date('Y-m-d') . '.csv');
SupplyChainExporter::export_inventory_report();
exit;
}
?>
<?php
/**
* 数据导出功能
*/
class SupplyChainExporter {
/**
* 导出订单数据为CSV
*/
public static function export_orders_csv($start_date = null, $end_date = null) {
$args = array(
'post_type' => 'supply_order',
'posts_per_page' => -1,
'orderby' => 'date',
'order' => 'DESC'
);
// 添加日期筛选
if ($start_date && $end_date) {
$args['date_query'] = array(
array(
'after' => $start_date,
'before' => $end_date,
'inclusive' => true
)
);
}
$orders = get_posts($args);
// 设置CSV头部
$headers = array(
'订单ID',
'产品名称',
'订单数量',
'订单状态',
'预计交付日期',
'实际交付日期',
'创建时间'
);
$output = fopen('php://output', 'w');
fputcsv($output, $headers);
foreach ($orders as $order) {
$product_id = get_field('related_product', $order->ID);
$product_name = $product_id ? get_the_title($product_id) : 'N/A';
$row = array(
$order->ID,
$product_name,
get_field('order_quantity', $order->ID) ?: 0,
self::get_status_text(get_field('order_status', $order->ID)),
get_field('estimated_delivery_date', $order->ID) ?: '',
get_field('actual_delivery_date', $order->ID) ?: '',
get_the_date('Y-m-d H:i:s', $order->ID)
);
fputcsv($output, $row);
}
fclose($output);
}
/**
* 导出库存报告
*/
public static function export_inventory_report() {
$products = get_posts(array(
'post_type' => 'supply_product',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC'
));
$headers = array(
'产品ID',
'产品名称',
'SKU',
'当前库存',
'安全库存',
'库存状态',
'关联供应商'
);
$output = fopen('php://output', 'w');
fputcsv($output, $headers);
foreach ($products as $product) {
$current_stock = get_field('current_stock', $product->ID) ?: 0;
$safety_stock = get_field('safety_stock_level', $product->ID) ?: 0;
$sku = get_field('product_sku', $product->ID) ?: '';
$supplier_id = get_field('related_supplier', $product->ID);
$supplier_name = $supplier_id ? get_the_title($supplier_id) : 'N/A';
$status = $current_stock <= $safety_stock ? '库存不足' : '正常';
$row = array(
$product->ID,
get_the_title($product->ID),
$sku,
$current_stock,
$safety_stock,
$status,
$supplier_name
);
fputcsv($output, $row);
}
fclose($output);
}
/**
* 获取状态文本
*/
private static function get_status_text($status) {
$status_map = array(
'pending' => '待处理',
'production' => '生产中',
'shipping' => '运输中',
'completed' => '已完成'
);
return $status_map[$status] ?? $status;
}
}
/**
* 注册导出API端点
*/
function register_export_api() {
register_rest_route('supply-chain/v1', '/export/orders', array(
'methods' => 'GET',
'callback' => 'handle_orders_export',
'permission_callback' => function() {
return current_user_can('export');
}
));
register_rest_route('supply-chain/v1', '/export/inventory', array(
'methods' => 'GET',
'callback' => 'handle_inventory_export',
'permission_callback' => function() {
return current_user_can('export');
}
));
}
add_action('rest_api_init', 'register_export_api');
function handle_orders_export($request) {
$start_date = $request->get_param('start_date');
$end_date = $request->get_param('end_date');
// 设置CSV头
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=orders_export_' . date('Y-m-d') . '.csv');
SupplyChainExporter::export_orders_csv($start_date, $end_date);
exit;
}
function handle_inventory_export($request) {
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=inventory_report_' . date('Y-m-d') . '.csv');
SupplyChainExporter::export_inventory_report();
exit;
}
?>
/**
* 数据导出功能
*/
class DataExporter {
constructor() {
this.initExportButtons();
}
initExportButtons() {
// 创建导出按钮容器
const exportContainer = document.createElement('div');
exportContainer.className = 'export-container';
exportContainer.innerHTML = `
<h4>数据导出</h4>
<div class="export-buttons">
<button class="export-btn" data-type="orders">导出订单数据</button>
<button class="export-btn" data-type="inventory">导出库存报告</button>
</div>
<div class="date-range" id="date-range-container" style="display: none;">
<h5>选择日期范围</h5>
<div class="date-inputs">
<div>
<label>开始日期:</label>
<input type="date" id="start-date">
</div>
<div>
<label>结束日期:</label>
<input type="date" id="end-date">
</div>
</div>
<button class="confirm-export">确认导出</button>
</div>
`;
document.querySelector('.dashboard-header').appendChild(exportContainer);
// 绑定按钮事件
document.querySelectorAll('.export-btn').forEach(button => {
button.addEventListener('click', (e) => {
const exportType = e.target.dataset.type;
this.handleExport(exportType);
});
});
document.querySelector('.confirm-export').addEventListener('click', () => {
this.performExport();
});
}
handleExport(type) {
this.currentExportType = type;
if (type === 'orders') {
// 显示日期选择器
document.getElementById('date-range-container').style.display = 'block';
} else {
// 直接导出库存报告
this.performExport();
}
}
performExport() {
let url = '';
if (this.currentExportType === 'orders') {
const startDate = document.getElementById('start-date').value;
const endDate = document.getElementById('end-date').value;
if (!startDate || !endDate) {
/**
* 数据导出功能
*/
class DataExporter {
constructor() {
this.initExportButtons();
}
initExportButtons() {
// 创建导出按钮容器
const exportContainer = document.createElement('div');
exportContainer.className = 'export-container';
exportContainer.innerHTML = `
<h4>数据导出</h4>
<div class="export-buttons">
<button class="export-btn" data-type="orders">导出订单数据</button>
<button class="export-btn" data-type="inventory">导出库存报告</button>
</div>
<div class="date-range" id="date-range-container" style="display: none;">
<h5>选择日期范围</h5>
<div class="date-inputs">
<div>
<label>开始日期:</label>
<input type="date" id="start-date">
</div>
<div>
<label>结束日期:</label>
<input type="date" id="end-date">
</div>
</div>
<button class="confirm-export">确认导出</button>
</div>
`;
document.querySelector('.dashboard-header').appendChild(exportContainer);
// 绑定按钮事件
document.querySelectorAll('.export-btn').forEach(button => {
button.addEventListener('click', (e) => {
const exportType = e.target.dataset.type;
this.handleExport(exportType);
});
});
document.querySelector('.confirm-export').addEventListener('click', () => {
this.performExport();
});
}
handleExport(type) {
this.currentExportType = type;
if (type === 'orders') {
// 显示日期选择器
document.getElementById('date-range-container').style.display = 'block';
} else {
// 直接导出库存报告
this.performExport();
}
}
performExport() {
let url = '';
if (this.currentExportType === 'orders') {
const startDate = document.getElementById('start-date').value;
const endDate = document.getElementById('end-date').value;
if (!startDate || !endDate) {


