首页 / 跨境电商轻量软件 / 实操指南:连接ERP系统数据接口的5个实施要点

实操指南:连接ERP系统数据接口的5个实施要点

实操指南:连接ERP系统数据接口的5个实施要点

引言:为什么WordPress开发者需要了解ERP集成

在当今数字化商业环境中,企业资源规划(ERP)系统已成为企业管理核心。对于WordPress开发者而言,将网站与ERP系统连接不仅能提升网站价值,还能为企业创造无缝的线上线下体验。无论是电子商务网站需要同步库存和订单,还是企业官网需要展示实时业务数据,ERP集成都是实现这些功能的关键。

本指南将基于WordPress开源系统,详细讲解连接ERP数据接口的5个核心实施要点,帮助行业新人和程序员掌握这一重要技能。我们将从基础概念入手,逐步深入到具体代码实现,确保您能够理解并应用这些知识。

要点一:理解ERP接口类型与通信协议

1.1 常见的ERP接口类型

在开始集成之前,首先需要了解ERP系统通常提供的接口类型:

RESTful API:现代ERP系统(如Odoo、SAP S/4HANA Cloud)普遍提供RESTful接口,使用HTTP方法(GET、POST、PUT、DELETE)进行数据操作。这种接口易于理解和使用,是WordPress集成的首选。

SOAP Web服务:较老的ERP系统(如SAP ECC)可能主要提供SOAP接口,使用XML格式和WSDL描述。虽然较为复杂,但在企业环境中仍广泛使用。

文件传输接口:一些系统通过SFTP/FTP服务器交换CSV、XML或JSON文件,适合批量数据同步。

数据库直连:直接连接ERP数据库(如MySQL、SQL Server),但通常不推荐,因为可能绕过业务逻辑和安全控制。

1.2 通信协议与安全考虑

HTTPS与SSL/TLS:所有外部通信必须使用HTTPS,确保数据传输安全。在WordPress中,确保wp_remote_get()wp_remote_post()函数使用正确的SSL验证。

认证与授权

  • API密钥:简单的静态令牌
  • OAuth 2.0:更安全的授权框架,适合用户级权限控制
  • 基本认证:用户名密码Base64编码,仅限HTTPS环境下使用
  • JWT(JSON Web Tokens):无状态令牌,适合微服务架构

1.3 WordPress中的HTTP请求处理

WordPress提供了安全的HTTP请求函数,应优先使用这些内置函数而非直接调用cURL:

// 使用wp_remote_get获取数据
$response = wp_remote_get('https://erp.example.com/api/products', array(
    'headers' => array(
        'Authorization' => 'Bearer ' . $api_token,
        'Content-Type' => 'application/json',
    ),
    'timeout' => 30,
    'sslverify' => true, // 生产环境应为true
));

// 检查响应
if (is_wp_error($response)) {
    $error_message = $response->get_error_message();
    // 错误处理
} else {
    $body = wp_remote_retrieve_body($response);
    $data = json_decode($body, true);
    // 处理数据
}

// 使用wp_remote_post发送数据
$response = wp_remote_post('https://erp.example.com/api/orders', array(
    'headers' => array(
        'Authorization' => 'Bearer ' . $api_token,
        'Content-Type' => 'application/json',
    ),
    'body' => json_encode(array(
        'order_id' => 1001,
        'customer' => 'John Doe',
        'items' => array(...)
    )),
    'timeout' => 30,
    'sslverify' => true,
));

要点二:设计稳健的数据同步架构

2.1 同步模式选择

实时同步:用户操作时立即与ERP通信。适合库存检查、价格查询等需要即时数据的场景。

// 实时检查库存示例
function check_real_time_stock($product_id) {
    $api_url = get_option('erp_api_url') . '/inventory';
    $api_key = get_option('erp_api_key');
    
    $response = wp_remote_get($api_url . '?product_id=' . $product_id, array(
        'headers' => array('API-Key' => $api_key),
        'timeout' => 5, // 短超时,避免影响用户体验
    ));
    
    if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
        $stock_data = json_decode(wp_remote_retrieve_body($response), true);
        return $stock_data['quantity'] ?? 0;
    }
    
    // 失败时返回缓存值或默认值
    return get_transient('cached_stock_' . $product_id) ?? 0;
}

定时批处理:使用WordPress Cron定时同步数据。适合产品目录、客户信息等不常变化的数据。

// 注册定时任务
add_action('init', function() {
    if (!wp_next_scheduled('erp_daily_sync')) {
        wp_schedule_event(time(), 'daily', 'erp_daily_sync');
    }
});

// 产品同步处理
add_action('erp_daily_sync', 'sync_products_from_erp');
function sync_products_from_erp() {
    $last_sync = get_option('erp_last_product_sync', 0);
    $api_url = get_option('erp_api_url') . '/products/updated-since/' . $last_sync;
    
    $response = wp_remote_get($api_url, array(
        'headers' => array('API-Key' => get_option('erp_api_key')),
        'timeout' => 60,
    ));
    
    if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
        $products = json_decode(wp_remote_retrieve_body($response), true);
        
        foreach ($products as $product) {
            // 创建或更新WordPress产品(假设使用WooCommerce)
            sync_single_product($product);
        }
        
        update_option('erp_last_product_sync', time());
    }
}

事件驱动同步:ERP系统通过Webhook通知WordPress数据变化。这是最有效的同步方式,但需要ERP系统支持。

2.2 数据映射与转换

ERP系统和WordPress通常使用不同的数据模型,需要进行字段映射:

// ERP产品到WooCommerce产品的映射示例
function map_erp_to_woocommerce_product($erp_product) {
    $wc_product = array(
        'name' => $erp_product['description'] ?? '',
        'sku' => $erp_product['item_code'] ?? '',
        'regular_price' => $erp_product['price'] ?? 0,
        'description' => $erp_product['long_description'] ?? '',
        'short_description' => $erp_product['short_description'] ?? '',
        'manage_stock' => true,
        'stock_quantity' => $erp_product['available_quantity'] ?? 0,
        'stock_status' => ($erp_product['available_quantity'] > 0) ? 'instock' : 'outofstock',
        // 分类映射
        'category_ids' => map_erp_categories($erp_product['categories']),
        // 自定义字段
        'meta_data' => array(
            array('key' => '_erp_id', 'value' => $erp_product['id']),
            array('key' => '_erp_last_updated', 'value' => $erp_product['updated_at']),
        )
    );
    
    return $wc_product;
}

// 分类映射辅助函数
function map_erp_categories($erp_categories) {
    $category_ids = array();
    foreach ($erp_categories as $erp_cat) {
        $term = get_term_by('name', $erp_cat['name'], 'product_cat');
        if (!$term) {
            // 创建不存在的分类
            $term = wp_insert_term($erp_cat['name'], 'product_cat');
            if (!is_wp_error($term)) {
                $category_ids[] = $term['term_id'];
            }
        } else {
            $category_ids[] = $term->term_id;
        }
    }
    return $category_ids;
}

2.3 错误处理与重试机制

稳健的集成必须包含完善的错误处理:

class ERP_Sync_Handler {
    private $max_retries = 3;
    private $retry_delay = 5; // 秒
    
    public function sync_with_retry($data, $endpoint) {
        $retry_count = 0;
        
        while ($retry_count <= $this->max_retries) {
            try {
                $result = $this->call_erp_api($data, $endpoint);
                
                if ($result['success']) {
                    return $result;
                } else {
                    // 记录错误但可重试
                    $this->log_error('ERP API调用失败但可重试: ' . $result['message']);
                    $retry_count++;
                    
                    if ($retry_count <= $this->max_retries) {
                        sleep($this->retry_delay * $retry_count); // 递增延迟
                    }
                }
            } catch (Exception $e) {
                // 不可重试的错误
                $this->log_error('ERP API调用异常: ' . $e->getMessage());
                throw $e;
            }
        }
        
        // 达到最大重试次数
        $this->log_error("ERP API调用失败,已达到最大重试次数: {$endpoint}");
        return array(
            'success' => false,
            'message' => 'Maximum retry attempts reached'
        );
    }
    
    private function call_erp_api($data, $endpoint) {
        // API调用实现
    }
    
    private function log_error($message) {
        // 记录到WordPress日志或专用日志表
        error_log('[ERP Sync] ' . $message);
        
        // 可选的数据库日志
        global $wpdb;
        $wpdb->insert(
            $wpdb->prefix . 'erp_sync_logs',
            array(
                'level' => 'error',
                'message' => $message,
                'endpoint' => $endpoint,
                'created_at' => current_time('mysql')
            )
        );
    }
}

要点三:安全实施与访问控制

3.1 安全存储凭证

绝对不要在代码中硬编码API密钥或密码:

// 错误做法 - 硬编码凭证
define('ERP_API_KEY', 'my_secret_key_here');

// 正确做法 - 使用WordPress选项或常量
class ERP_Config {
    const SETTINGS_GROUP = 'erp_integration_settings';
    
    public static function get_api_key() {
        // 首先检查常量(适合不同环境配置)
        if (defined('ERP_API_KEY')) {
            return ERP_API_KEY;
        }
        
        // 然后检查数据库选项
        $api_key = get_option('erp_api_key');
        
        if (empty($api_key)) {
            // 记录错误但返回空值
            error_log('ERP API密钥未配置');
        }
        
        return $api_key;
    }
    
    public static function get_api_url() {
        $url = get_option('erp_api_url');
        
        if (empty($url)) {
            // 默认值或错误处理
            $url = 'https://erp.example.com/api';
        }
        
        return trailingslashit($url);
    }
}

// 在wp-config.php中定义环境特定常量(可选)
// define('ERP_API_KEY', 'production_key_here');
// define('ERP_API_URL', 'https://erp.production.com/api');

3.2 创建安全的设置页面

为管理员提供安全的配置界面:

// 添加ERP设置页面
add_action('admin_menu', function() {
    add_options_page(
        'ERP集成设置',
        'ERP集成',
        'manage_options',
        'erp-integration',
        'erp_settings_page'
    );
});

function erp_settings_page() {
    // 权限检查
    if (!current_user_can('manage_options')) {
        wp_die('您没有权限访问此页面');
    }
    
    // 保存设置
    if (isset($_POST['submit_erp_settings']) && check_admin_referer('erp_settings_nonce')) {
        update_option('erp_api_url', sanitize_url($_POST['erp_api_url']));
        
        // 如果密码字段不为空,则更新
        if (!empty($_POST['erp_api_key'])) {
            update_option('erp_api_key', $_POST['erp_api_key']);
        }
        
        update_option('erp_sync_frequency', sanitize_text_field($_POST['sync_frequency']));
        
        echo '<div class="notice notice-success"><p>设置已保存</p></div>';
    }
    
    // 获取当前值
    $api_url = get_option('erp_api_url', '');
    $sync_frequency = get_option('erp_sync_frequency', 'daily');
    ?>
    <div class="wrap">
        <h1>ERP系统集成设置</h1>
        <form method="post" action="">
            <?php wp_nonce_field('erp_settings_nonce'); ?>
            <table class="form-table">
                <tr>
                    <th scope="row"><label for="erp_api_url">ERP API地址</label></th>
                    <td>
                        <input type="url" id="erp_api_url" name="erp_api_url" 
                               value="<?php echo esc_attr($api_url); ?>" 
                               class="regular-text" required>
                        <p class="description">ERP系统的API基础地址,例如: https://erp.example.com/api</p>
                    </td>
                </tr>
                <tr>
                    <th scope="row"><label for="erp_api_key">API密钥</label></th>
                    <td>
                        <input type="password" id="erp_api_key" name="erp_api_key" 
                               value="" class="regular-text">
                        <p class="description">留空以保持当前密钥不变</p>
                    </td>
                </tr>
                <tr>
                    <th scope="row"><label for="sync_frequency">数据同步频率</label></th>
                    <td>
                        <select id="sync_frequency" name="sync_frequency">
                            <option value="hourly" <?php selected($sync_frequency, 'hourly'); ?>>每小时</option>
                            <option value="twicedaily" <?php selected($sync_frequency, 'twicedaily'); ?>>每12小时</option>
                            <option value="daily" <?php selected($sync_frequency, 'daily'); ?>>每天</option>
                            <option value="weekly" <?php selected($sync_frequency, 'weekly'); ?>>每周</option>
                        </select>
                    </td>
                </tr>
            </table>
            <p class="submit">
                <input type="submit" name="submit_erp_settings" 
                       class="button button-primary" value="保存设置">
            </p>
        </form>
        
        <h2>连接测试</h2>
        <button id="test-erp-connection" class="button">测试ERP连接</button>
        <div id="test-result" style="margin-top: 10px;"></div>
        
        <script>
        jQuery(document).ready(function($) {
            $('#test-erp-connection').click(function() {
                $('#test-result').html('<p>测试中...</p>');
                
                $.post(ajaxurl, {
                    action: 'test_erp_connection',
                    nonce: '<?php echo wp_create_nonce("test_erp_connection"); ?>'
                }, function(response) {
                    $('#test-result').html('<p>' + response.data.message + '</p>');
                }).fail(function() {
                    $('#test-result').html('<p>测试请求失败</p>');
                });
            });
        });
        </script>
    </div>
    <?php
}

// AJAX连接测试
add_action('wp_ajax_test_erp_connection', function() {
    check_ajax_referer('test_erp_connection', 'nonce');
    
    if (!current_user_can('manage_options')) {
        wp_die('权限不足');
    }
    
    $api_url = get_option('erp_api_url');
    $api_key = get_option('erp_api_key');
    
    if (empty($api_url) || empty($api_key)) {
        wp_send_json_error(array('message' => 'API地址或密钥未配置'));
        return;
    }
    
    // 测试连接
    $response = wp_remote_get($api_url . '/health', array(
        'headers' => array('API-Key' => $api_key),
        'timeout' => 10,
    ));
    
    if (is_wp_error($response)) {
        wp_send_json_error(array('message' => '连接失败: ' . $response->get_error_message()));
    } elseif (wp_remote_retrieve_response_code($response) === 200) {
        wp_send_json_success(array('message' => '连接成功! ERP系统正常响应'));
    } else {
        wp_send_json_error(array(
            'message' => 'ERP系统返回错误: HTTP ' . wp_remote_retrieve_response_code($response)
        ));
    }
});

3.3 输入验证与输出转义

防止注入攻击和数据污染:

// 处理ERP Webhook的示例
add_action('rest_api_init', function() {
    register_rest_route('erp/v1', '/webhook/order', array(
        'methods' => 'POST',
        'callback' => 'handle_erp_webhook',
        'permission_callback' => 'verify_erp_webhook',
    ));
});

function verify_erp_webhook($request) {
    // 验证Webhook签名
    $signature = $request->get_header('X-ERP-Signature');
    $payload = $request->get_body();
    $expected_signature = hash_hmac('sha256', $payload, get_option('erp_webhook_secret'));
    
    return hash_equals($expected_signature, $signature);
}

function handle_erp_webhook($request) {
    // 验证和清理输入数据
    $params = $request->get_json_params();
    
    // 验证必要字段
    $required_fields = ['order_id', 'status', 'customer_email'];
    foreach ($required_fields as $field) {
        if (!isset($params[$field])) {
            return new WP_Error('missing_field', "缺少必要字段: {$field}", array('status' => 400));
        }
    }
    
    // 清理和验证数据
    $order_id = intval($params['order_id']);
    $status = sanitize_text_field($params['status']);
    $customer_email = sanitize_email($params['customer_email']);
    
    // 验证订单状态是否有效
    $valid_statuses = ['pending', 'processing', 'completed', 'cancelled'];
    if (!in_array($status, $valid_statuses)) {
        return new WP_Error('invalid_status', "无效的订单状态: {$status}", array('status' => 400));
    }
    
    // 查找对应的WooCommerce订单
    $order = wc_get_order($order_id);
    if (!$order) {
        return new WP_Error('order_not_found', "订单不存在: {$order_id}", array('status' => 404));
    }
    
    // 更新订单状态
    $order->update_status($status, 'ERP系统同步更新');
    
    // 记录同步日志
    $log_data = array(
        'order_id' => $order_id,
        'status' => $status,
        'sync_time' => current_time('mysql'),
        'source' => 'erp_webhook'
    );
    
    // 安全地存储日志
    global $wpdb;
    $wpdb->insert(
        $wpdb->prefix . 'erp_sync_logs',
        $log_data
    );
    
    return rest_ensure_response(array(
        'success' => true,
        'message' => '订单状态已更新',
        'order_id' => $order_id,
        'new_status' => $status
    ));
}

要点四:性能优化与缓存策略

4.1 实施多级缓存机制

class ERP_Cache_Manager {
    private $cache_group = 'erp_data';
    private $cache_expiration = 3600; // 1小时
    
    public function get_product_data($product_id, $force_refresh = false) {
        $cache_key = 'product_' . $product_id;
        
        // 检查内存缓存(WordPress对象缓存)
        $cached_data = wp_cache_get($cache_key, $this->cache_group);
        
        if ($cached_data !== false && !$force_refresh) {
            return $cached_data;
        }
        
        // 检查数据库缓存(transients)
        $transient_key = 'erp_product_' . md5($product_id);
        $cached_data = get_transient($transient_key);
        
        if ($cached_data !== false && !$force_refresh) {
            // 同时更新内存缓存
            wp_cache_set($cache_key, $cached_data, $this->cache_group, $this->cache_expiration);
            return $cached_data;
        }
        
        // 从ERP API获取数据
        $api_data = $this->fetch_product_from_erp($product_id);
        
        if ($api_data) {
            // 更新所有缓存层
            wp_cache_set($cache_key, $api_data, $this->cache_group, $this->cache_expiration);
            set_transient($transient_key, $api_data, $this->cache_expiration);
            
            // 可选:存储到自定义数据库表进行长期缓存
            $this->store_in_database_cache($product_id, $api_data);
        }
        
        return $api_data;
    }
    
    public function invalidate_product_cache($product_id) {
        // 清除所有缓存层
        $cache_key = 'product_' . $product_id;
        wp_cache_delete($cache_key, $this->cache_group);
        
        $transient_key = 'erp_product_' . md5($product_id);
        delete_transient($transient_key);
        
        // 清除数据库缓存
        $this->delete_database_cache($product_id);
    }
    
    private function fetch_product_from_erp($product_id) {
        // 实际的API调用
        $api_url = ERP_Config::get_api_url() . 'products/' . $product_id;
        
        $response = wp_remote_get($api_url, array(
            'headers' => array('API-Key' => ERP_Config::get_api_key()),
            'timeout' => 10,
        ));
        
        if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
            // 如果API失败,尝试返回过期的缓存数据
            $stale_data = $this->get_stale_cache($product_id);
            if ($stale_data) {
                // 记录降级使用
                error_log('使用过期的产品缓存数据: ' . $product_id);
                return $stale_data;
            }
            return false;
        }
        
        return json_decode(wp_remote_retrieve_body($response), true);
    }
}

4.2 批量处理与请求优化

class ERP_Batch_Processor {
    public function sync_products_in_batches($product_ids, $batch_size = 50) {
        $results = array(
            'success' => array(),
            'failed' => array(),
            'total' => count($product_ids)
        );
        
        // 分批处理
        $batches = array_chunk($product_ids, $batch_size);
        
        foreach ($batches as $batch_index => $batch) {
            // 构建批量请求
            $batch_request = array(
                'action' => 'get_products',
                'product_ids' => $batch,
                'fields' => array('id', 'name', 'price', 'stock', 'sku')
            );
            
            $response = $this->call_erp_batch_api($batch_request);
            
            if ($response && $response['success']) {
                foreach ($response['data'] as $product_data) {
                    $this->process_single_product($product_data);
                    $results['success'][] = $product_data['id'];
                }
            } else {
                // 批量失败,回退到单个请求
                foreach ($batch as $product_id) {
                    $single_result = $this->sync_single_product($product_id);
                    if ($single_result) {
                        $results['success'][] = $product_id;
                    } else {
                        $results['failed'][] = $product_id;
                    }
                }
            }
            
            // 避免触发API速率限制
            if ($batch_index < count($batches) - 1) {
                sleep(1); // 批次间暂停
            }
        }
        
        return $results;
    }
    
    private function call_erp_batch_api($batch_data) {
        $api_url = ERP_Config::get_api_url() . 'batch';
        
        $response = wp_remote_post($api_url, array(
            'headers' => array(
                'API-Key' => ERP_Config::get_api_key(),
                'Content-Type' => 'application/json'
            ),
            'body' => json_encode($batch_data),
            'timeout' => 30,
        ));
        
        if (is_wp_error($response)) {
            error_log('批量API调用失败: ' . $response->get_error_message());
            return false;
        }
        
        $status_code = wp_remote_retrieve_response_code($response);
        if ($status_code !== 200) {
            error_log("批量API返回错误状态码: {$status_code}");
            return false;
        }
        
        return json_decode(wp_remote_retrieve_body($response), true);
    }
}

4.3 异步处理与队列系统

class ERP_Async_Processor {
    public function enqueue_sync_task($task_type, $data) {
        // 使用WordPress的Cron系统作为简单队列
        $task_id = wp_generate_uuid4();
        $task_data = array(
            'task_id' => $task_id,
            'type' => $task_type,
            'data' => $data,
            'created_at' => time(),
            'status' => 'pending'
        );
        
        // 存储任务到选项表
        $tasks = get_option('erp_pending_tasks', array());
        $tasks[$task_id] = $task_data;
        update_option('erp_pending_tasks', $tasks);
        
        // 调度处理
        if (!wp_next_scheduled('process_erp_tasks')) {
            wp_schedule_single_event(time() + 60, 'process_erp_tasks');
        }
        
        return $task_id;
    }
    
    public function process_tasks() {
        $tasks = get_option('erp_pending_tasks', array());
        
        // 每次处理最多5个任务
        $processed = 0;
        $max_per_run = 5;
        
        foreach ($tasks as $task_id => $task) {
            if ($task['status'] === 'pending' && $processed < $max_per_run) {
                // 更新状态为处理中
                $tasks[$task_id]['status'] = 'processing';
                $tasks[$task_id]['started_at'] = time();
                update_option('erp_pending_tasks', $tasks);
                
                // 执行任务
                $result = $this->execute_task($task);
                
                // 更新任务状态
                $tasks[$task_id]['status'] = $result['success'] ? 'completed' : 'failed';
                $tasks[$task_id]['completed_at'] = time();
                $tasks[$task_id]['result'] = $result;
                
                $processed++;
            }
        }
        
        update_option('erp_pending_tasks', $tasks);
        
        // 如果还有待处理任务,重新调度
        $remaining = count(array_filter($tasks, function($task) {
            return $task['status'] === 'pending';
        }));
        
        if ($remaining > 0) {
            wp_schedule_single_event(time() + 60, 'process_erp_tasks');
        }
    }
    
    private function execute_task($task) {
        switch ($task['type']) {
            case 'sync_product':
                return $this->sync_product_task($task['data']);
            case 'sync_order':
                return $this->sync_order_task($task['data']);
            case 'sync_customer':
                return $this->sync_customer_task($task['data']);
            default:
                return array('success' => false, 'message' => '未知任务类型');
        }
    }
}

要点五:监控、日志与故障排除

5.1 实现全面的日志系统

class ERP_Logger {
    const LOG_LEVEL_DEBUG = 1;
    const LOG_LEVEL_INFO = 2;
    const LOG_LEVEL_WARNING = 3;
    const LOG_LEVEL_ERROR = 4;
    
    private $log_table;
    private $min_log_level;
    
    public function __construct() {
        global $wpdb;
        $this->log_table = $wpdb->prefix . 'erp_logs';
        $this->min_log_level = defined('ERP_LOG_LEVEL') ? ERP_LOG_LEVEL : self::LOG_LEVEL_INFO;
        
        // 确保日志表存在
        $this->create_log_table();
    }
    
    private function create_log_table() {
        global $wpdb;
        
        $charset_collate = $wpdb->get_charset_collate();
        
        $sql = "CREATE TABLE IF NOT EXISTS {$this->log_table} (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            level tinyint(1) NOT NULL,
            module varchar(50) NOT NULL,
            message text NOT NULL,
            context longtext,
            user_id bigint(20) DEFAULT NULL,
            ip_address varchar(45) DEFAULT NULL,
            created_at datetime DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            KEY level (level),
            KEY module (module),
            KEY created_at (created_at)
        ) {$charset_collate};";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql);
    }
    
    public function log($level, $module, $message, $context = array()) {
        if ($level < $this->min_log_level) {
            return;
        }
        
        global $wpdb;
        
        // 添加上下文信息
        $context['wp_debug'] = defined('WP_DEBUG') && WP_DEBUG;
        $context['php_version'] = PHP_VERSION;
        $context['wordpress_version'] = get_bloginfo('version');
        
        // 获取当前用户
        $user_id = get_current_user_id();
        $user_id = $user_id ?: null;
        
        // 获取IP地址
        $ip_address = $this->get_client_ip();
        
        $wpdb->insert(
            $this->log_table,
            array(
                'level' => $level,
                'module' => $module,
                'message' => $message,
                'context' => json_encode($context),
                'user_id' => $user_id,
                'ip_address' => $ip_address
            ),
            array('%d', '%s', '%s', '%s', '%d', '%s')
        );
        
        // 同时输出到WordPress调试日志
        if (defined('WP_DEBUG') && WP_DEBUG) {
            $level_name = $this->get_level_name($level);
            error_log("[ERP {$level_name}] {$module}: {$message}");
        }
    }
    
    public function get_logs($filters = array(), $limit = 100, $offset = 0) {
        global $wpdb;
        
        $where = array('1=1');
        $params = array();
        
        if (!empty($filters['level'])) {
            $where[] = 'level = %d';
            $params[] = $filters['level'];
        }
        
        if (!empty($filters['module'])) {
            $where[] = 'module = %s';
            $params[] = $filters['module'];
        }
        
        if (!empty($filters['start_date'])) {
            $where[] = 'created_at >= %s';
            $params[] = $filters['start_date'];
        }
        
        if (!empty($filters['end_date'])) {
            $where[] = 'created_at <= %s';
            $params[] = $filters['end_date'];
        }
        
        $where_clause = implode(' AND ', $where);
        
        if (!empty($params)) {
            $where_clause = $wpdb->prepare($where_clause, $params);
        }
        
        $query = "SELECT * FROM {$this->log_table} 
                  WHERE {$where_clause} 
                  ORDER BY created_at DESC 
                  LIMIT %d OFFSET %d";
        
        return $wpdb->get_results(
            $wpdb->prepare($query, $limit, $offset)
        );
    }
    
    public function cleanup_old_logs($days_to_keep = 30) {
        global $wpdb;
        
        $cutoff_date = date('Y-m-d H:i:s', strtotime("-{$days_to_keep} days"));
        
        $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$this->log_table} WHERE created_at < %s",
                $cutoff_date
            )
        );
        
        return $wpdb->rows_affected;
    }
}

5.2 创建监控仪表板

class ERP_Monitor_Dashboard {
    public function add_admin_page() {
        add_menu_page(
            'ERP监控',
            'ERP监控',
            'manage_options',
            'erp-monitor',
            array($this, 'render_dashboard'),
            'dashicons-dashboard',
            30
        );
    }
    
    public function render_dashboard() {
        ?>
        <div class="wrap">
            <h1>ERP系统集成监控</h1>
            
            <div class="erp-monitor-stats">
                <div class="stat-card">
                    <h3>API响应时间</h3>
                    <div class="stat-value"><?php echo $this->get_avg_response_time(); ?>ms</div>
                    <div class="stat-trend">最近24小时</div>
                </div>
                
                <div class="stat-card">
                    <h3>同步成功率</h3>
                    <div class="stat-value"><?php echo $this->get_sync_success_rate(); ?>%</div>
                    <div class="stat-trend">最近7天</div>
                </div>
                
                <div class="stat-card">
                    <h3>待处理任务</h3>
                    <div class="stat-value"><?php echo $this->get_pending_tasks_count(); ?></div>
                    <div class="stat-trend">需要处理</div>
                </div>
            </div>
            
            <h2>最近错误日志</h2>
            <?php $this->render_error_logs(); ?>
            
            <h2>同步状态</h2>
            <?php $this->render_sync_status(); ?>
            
            <h2>手动操作</h2>
            <div class="manual-actions">
                <button class="button button-primary" onclick="clearErpCache()">清除缓存</button>
                <button class="button" onclick="forceFullSync()">强制全量同步</button>
                <button class="button" onclick="testAllConnections()">测试所有连接</button>
            </div>
        </div>
        
        <style>
        .erp-monitor-stats {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }
        .stat-card {
            background: white;
            border: 1px solid #ccd0d4;
            padding: 20px;
            border-radius: 4px;
            text-align: center;
        }
        .stat-value {
            font-size: 2em;
            font-weight: bold;
            margin: 10px 0;
        }
        .stat-trend {
            color: #666;
            font-size: 0.9em;
        }
        </style>
        
        <script>
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/220.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

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