首页 / 教程文章 / WordPress小批量定制插件实现原材料溯源管理的教程

WordPress小批量定制插件实现原材料溯源管理的教程

WordPress小批量定制插件实现原材料溯源管理的教程

引言:为什么需要原材料溯源管理?

在当今注重产品质量和安全的市场环境中,原材料溯源管理变得至关重要。无论是食品行业、化妆品生产还是制造业,能够追踪原材料从采购到成品的全过程,不仅能提高产品质量控制能力,还能增强消费者信任,满足法规要求。

对于中小型企业来说,昂贵的专业溯源系统往往难以承受。本教程将指导您如何通过WordPress定制插件,以较低成本实现小批量的原材料溯源管理功能。

系统设计与功能规划

1.1 核心功能需求分析

我们的原材料溯源管理系统需要包含以下核心功能:

  • 原材料信息录入与管理
  • 供应商信息管理
  • 生产批次追踪
  • 扫码查询功能
  • 数据可视化报表

1.2 数据库结构设计

我们将创建以下数据表来存储溯源信息:

  1. 原材料表 (raw_materials)
  2. 供应商表 (suppliers)
  3. 入库记录表 (inventory_records)
  4. 生产批次表 (production_batches)
  5. 产品表 (products)

插件开发环境搭建

2.1 创建插件基础结构

首先,在WordPress的wp-content/plugins目录下创建新文件夹"material-traceability",然后创建主插件文件:

<?php
/**
 * Plugin Name: 原材料溯源管理系统
 * Plugin URI: https://yourwebsite.com/
 * Description: 用于管理原材料溯源的小批量定制插件
 * Version: 1.0.0
 * Author: 您的名称
 * License: GPL v2 or later
 * Text Domain: material-traceability
 */

// 防止直接访问
if (!defined('ABSPATH')) {
    exit;
}

// 定义插件常量
define('MT_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('MT_PLUGIN_URL', plugin_dir_url(__FILE__));
define('MT_VERSION', '1.0.0');

// 初始化插件
require_once MT_PLUGIN_PATH . 'includes/class-init.php';
require_once MT_PLUGIN_PATH . 'includes/class-database.php';
require_once MT_PLUGIN_PATH . 'includes/class-admin.php';
require_once MT_PLUGIN_PATH . 'includes/class-public.php';

// 激活和停用钩子
register_activation_hook(__FILE__, array('MT_Database', 'create_tables'));
register_deactivation_hook(__FILE__, array('MT_Database', 'drop_tables'));

// 初始化插件类
function mt_init_plugin() {
    $init = new MT_Init();
    $init->run();
}
add_action('plugins_loaded', 'mt_init_plugin');
?>

2.2 创建数据库管理类

<?php
/**
 * 数据库管理类
 * 处理插件的数据库表创建和更新
 */

class MT_Database {
    
    /**
     * 创建插件所需的数据表
     */
    public static function create_tables() {
        global $wpdb;
        
        $charset_collate = $wpdb->get_charset_collate();
        
        // 原材料表
        $table_materials = $wpdb->prefix . 'mt_materials';
        $sql_materials = "CREATE TABLE IF NOT EXISTS $table_materials (
            id INT(11) NOT NULL AUTO_INCREMENT,
            material_code VARCHAR(50) NOT NULL,
            material_name VARCHAR(255) NOT NULL,
            material_type VARCHAR(100) NOT NULL,
            supplier_id INT(11) NOT NULL,
            unit VARCHAR(20) NOT NULL,
            safety_standard TEXT,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            UNIQUE KEY material_code (material_code)
        ) $charset_collate;";
        
        // 供应商表
        $table_suppliers = $wpdb->prefix . 'mt_suppliers';
        $sql_suppliers = "CREATE TABLE IF NOT EXISTS $table_suppliers (
            id INT(11) NOT NULL AUTO_INCREMENT,
            supplier_code VARCHAR(50) NOT NULL,
            supplier_name VARCHAR(255) NOT NULL,
            contact_person VARCHAR(100),
            phone VARCHAR(50),
            email VARCHAR(100),
            address TEXT,
            qualification_cert TEXT,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            UNIQUE KEY supplier_code (supplier_code)
        ) $charset_collate;";
        
        // 入库记录表
        $table_inventory = $wpdb->prefix . 'mt_inventory';
        $sql_inventory = "CREATE TABLE IF NOT EXISTS $table_inventory (
            id INT(11) NOT NULL AUTO_INCREMENT,
            material_id INT(11) NOT NULL,
            batch_number VARCHAR(100) NOT NULL,
            quantity DECIMAL(10,2) NOT NULL,
            unit_price DECIMAL(10,2),
            storage_location VARCHAR(255),
            production_date DATE,
            expiry_date DATE,
            inspector VARCHAR(100),
            qr_code_path VARCHAR(500),
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            KEY material_id (material_id),
            KEY batch_number (batch_number)
        ) $charset_collate;";
        
        // 生产批次表
        $table_batches = $wpdb->prefix . 'mt_batches';
        $sql_batches = "CREATE TABLE IF NOT EXISTS $table_batches (
            id INT(11) NOT NULL AUTO_INCREMENT,
            batch_number VARCHAR(100) NOT NULL,
            product_id INT(11) NOT NULL,
            production_date DATE NOT NULL,
            quantity INT(11) NOT NULL,
            used_materials TEXT,
            operator VARCHAR(100),
            quality_check VARCHAR(50),
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            UNIQUE KEY batch_number (batch_number)
        ) $charset_collate;";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        
        dbDelta($sql_materials);
        dbDelta($sql_suppliers);
        dbDelta($sql_inventory);
        dbDelta($sql_batches);
        
        // 添加默认数据(可选)
        self::add_default_data();
    }
    
    /**
     * 添加默认数据
     */
    private static function add_default_data() {
        // 这里可以添加一些默认的供应商或材料类型
    }
    
    /**
     * 删除数据表(插件停用时)
     */
    public static function drop_tables() {
        global $wpdb;
        
        $tables = array(
            $wpdb->prefix . 'mt_materials',
            $wpdb->prefix . 'mt_suppliers',
            $wpdb->prefix . 'mt_inventory',
            $wpdb->prefix . 'mt_batches'
        );
        
        foreach ($tables as $table) {
            $wpdb->query("DROP TABLE IF EXISTS $table");
        }
    }
}
?>

后台管理界面开发

3.1 创建管理菜单和页面

<?php
/**
 * 后台管理类
 * 处理插件在WordPress后台的管理界面
 */

class MT_Admin {
    
    private $page_hook;
    
    public function __construct() {
        add_action('admin_menu', array($this, 'add_admin_menu'));
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
    }
    
    /**
     * 添加管理菜单
     */
    public function add_admin_menu() {
        $this->page_hook = add_menu_page(
            '原材料溯源管理',          // 页面标题
            '溯源管理',                // 菜单标题
            'manage_options',          // 权限
            'material-traceability',   // 菜单slug
            array($this, 'render_dashboard'), // 回调函数
            'dashicons-database',      // 图标
            30                         // 位置
        );
        
        // 添加子菜单
        add_submenu_page(
            'material-traceability',
            '原材料管理',
            '原材料管理',
            'manage_options',
            'mt-materials',
            array($this, 'render_materials_page')
        );
        
        add_submenu_page(
            'material-traceability',
            '供应商管理',
            '供应商管理',
            'manage_options',
            'mt-suppliers',
            array($this, 'render_suppliers_page')
        );
        
        add_submenu_page(
            'material-traceability',
            '入库记录',
            '入库记录',
            'manage_options',
            'mt-inventory',
            array($this, 'render_inventory_page')
        );
        
        add_submenu_page(
            'material-traceability',
            '生产批次',
            '生产批次',
            'manage_options',
            'mt-batches',
            array($this, 'render_batches_page')
        );
        
        add_submenu_page(
            'material-traceability',
            '溯源查询',
            '溯源查询',
            'manage_options',
            'mt-trace',
            array($this, 'render_trace_page')
        );
    }
    
    /**
     * 加载后台脚本和样式
     */
    public function enqueue_admin_scripts($hook) {
        if ($hook != $this->page_hook && strpos($hook, 'material-traceability') === false) {
            return;
        }
        
        wp_enqueue_style(
            'mt-admin-style',
            MT_PLUGIN_URL . 'assets/css/admin-style.css',
            array(),
            MT_VERSION
        );
        
        wp_enqueue_script(
            'mt-admin-script',
            MT_PLUGIN_URL . 'assets/js/admin-script.js',
            array('jquery'),
            MT_VERSION,
            true
        );
        
        // 本地化脚本,传递数据到JavaScript
        wp_localize_script('mt-admin-script', 'mt_ajax', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('mt_ajax_nonce')
        ));
    }
    
    /**
     * 渲染仪表板页面
     */
    public function render_dashboard() {
        global $wpdb;
        
        // 获取统计数据
        $materials_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}mt_materials");
        $suppliers_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}mt_suppliers");
        $inventory_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}mt_inventory");
        $batches_count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}mt_batches");
        
        ?>
        <div class="wrap mt-dashboard">
            <h1>原材料溯源管理系统</h1>
            
            <div class="mt-stats-container">
                <div class="mt-stat-card">
                    <h3>原材料种类</h3>
                    <p class="stat-number"><?php echo $materials_count; ?></p>
                </div>
                
                <div class="mt-stat-card">
                    <h3>供应商数量</h3>
                    <p class="stat-number"><?php echo $suppliers_count; ?></p>
                </div>
                
                <div class="mt-stat-card">
                    <h3>入库记录</h3>
                    <p class="stat-number"><?php echo $inventory_count; ?></p>
                </div>
                
                <div class="mt-stat-card">
                    <h3>生产批次</h3>
                    <p class="stat-number"><?php echo $batches_count; ?></p>
                </div>
            </div>
            
            <div class="mt-quick-actions">
                <h2>快速操作</h2>
                <div class="action-buttons">
                    <a href="<?php echo admin_url('admin.php?page=mt-materials&action=add'); ?>" class="button button-primary">
                        添加新材料
                    </a>
                    <a href="<?php echo admin_url('admin.php?page=mt-inventory&action=add'); ?>" class="button button-primary">
                        添加入库记录
                    </a>
                    <a href="<?php echo admin_url('admin.php?page=mt-batches&action=add'); ?>" class="button button-primary">
                        添加生产批次
                    </a>
                    <a href="<?php echo admin_url('admin.php?page=mt-trace'); ?>" class="button">
                        溯源查询
                    </a>
                </div>
            </div>
            
            <div class="mt-recent-activity">
                <h2>最近活动</h2>
                <?php $this->display_recent_activity(); ?>
            </div>
        </div>
        <?php
    }
    
    /**
     * 显示最近活动
     */
    private function display_recent_activity() {
        global $wpdb;
        
        // 获取最近的入库记录
        $recent_inventory = $wpdb->get_results(
            "SELECT i.*, m.material_name 
             FROM {$wpdb->prefix}mt_inventory i
             LEFT JOIN {$wpdb->prefix}mt_materials m ON i.material_id = m.id
             ORDER BY i.created_at DESC LIMIT 10"
        );
        
        if ($recent_inventory) {
            echo '<table class="wp-list-table widefat fixed striped">';
            echo '<thead><tr>
                    <th>批次号</th>
                    <th>原材料</th>
                    <th>数量</th>
                    <th>入库时间</th>
                  </tr></thead>';
            echo '<tbody>';
            
            foreach ($recent_inventory as $item) {
                echo '<tr>';
                echo '<td>' . esc_html($item->batch_number) . '</td>';
                echo '<td>' . esc_html($item->material_name) . '</td>';
                echo '<td>' . esc_html($item->quantity) . '</td>';
                echo '<td>' . esc_html($item->created_at) . '</td>';
                echo '</tr>';
            }
            
            echo '</tbody></table>';
        } else {
            echo '<p>暂无活动记录</p>';
        }
    }
    
    /**
     * 渲染原材料管理页面
     */
    public function render_materials_page() {
        // 这里实现原材料管理页面的代码
        echo '<div class="wrap"><h1>原材料管理</h1></div>';
    }
    
    // 其他页面渲染方法...
}
?>

前端查询功能实现

4.1 创建短代码用于前端查询

<?php
/**
 * 前端公共类
 * 处理插件在前端的显示和功能
 */

class MT_Public {
    
    public function __construct() {
        add_shortcode('material_trace', array($this, 'trace_shortcode'));
        add_action('wp_enqueue_scripts', array($this, 'enqueue_public_scripts'));
        add_action('wp_ajax_mt_trace_query', array($this, 'ajax_trace_query'));
        add_action('wp_ajax_nopriv_mt_trace_query', array($this, 'ajax_trace_query'));
    }
    
    /**
     * 加载前端脚本和样式
     */
    public function enqueue_public_scripts() {
        wp_enqueue_style(
            'mt-public-style',
            MT_PLUGIN_URL . 'assets/css/public-style.css',
            array(),
            MT_VERSION
        );
        
        wp_enqueue_script(
            'mt-public-script',
            MT_PLUGIN_URL . 'assets/js/public-script.js',
            array('jquery'),
            MT_VERSION,
            true
        );
        
        wp_localize_script('mt-public-script', 'mt_public_ajax', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('mt_public_ajax_nonce')
        ));
    }
    
    /**
     * 溯源查询短代码
     */
    public function trace_shortcode($atts) {
        ob_start();
        ?>
        <div class="mt-trace-container">
            <h2>原材料溯源查询</h2>
            <p>请输入批次号或扫描二维码查询原材料来源信息</p>
            
            <div class="mt-search-box">
                <input type="text" id="mt-batch-number" placeholder="输入批次号" class="mt-input">
                <button id="mt-trace-btn" class="mt-button">查询</button>
                <div class="mt-qr-scanner">
                    <button id="mt-scan-btn" class="mt-button secondary">扫码查询</button>
                    <div id="mt-qr-reader" style="display:none;"></div>
                </div>
            </div>
            
            <div id="mt-trace-results" class="mt-results-container" style="display:none;">
                <!-- 查询结果将在这里显示 -->
            </div>
            
            <div id="mt-loading" class="mt-loading" style="display:none;">
                查询中...
            </div>
        </div>
        <?php
        return ob_get_clean();
    }
    
    /**
     * AJAX溯源查询处理
     */
    public function ajax_trace_query() {
        // 验证nonce
        if (!wp_verify_nonce($_POST['nonce'], 'mt_public_ajax_nonce')) {
            wp_die('安全验证失败');
        }
        
        $batch_number = sanitize_text_field($_POST['batch_number']);
        
        if (empty($batch_number)) {
            wp_send_json_error('请输入批次号');
        }
        
        global $wpdb;
        
        // 查询入库记录
        $inventory_record = $wpdb->get_row($wpdb->prepare(
            "SELECT i.*, m.material_name, m.material_code, s.supplier_name
             FROM {$wpdb->prefix}mt_inventory i
             LEFT JOIN {$wpdb->prefix}mt_materials m ON i.material_id = m.id
             LEFT JOIN {$wpdb->prefix}mt_suppliers s ON m.supplier_id = s.id
             WHERE i.batch_number = %s",
            $batch_number
        ));
        
        if (!$inventory_record) {
            // 尝试查询生产批次
            $production_batch = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}mt_batches WHERE batch_number = %s",
                $batch_number
            ));
            
            if ($production_batch) {
                $response = array(
                    'type' => 'production',

data' => $production_batch,

                'used_materials' => json_decode($production_batch->used_materials, true)
            );
            wp_send_json_success($response);
        } else {
            wp_send_json_error('未找到相关批次信息');
        }
    } else {
        // 查询该原材料的所有生产批次
        $production_batches = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}mt_batches 
             WHERE used_materials LIKE %s",
            '%"' . $inventory_record->material_id . '"%'
        ));
        
        $response = array(
            'type' => 'material',
            'data' => $inventory_record,
            'production_batches' => $production_batches
        );
        wp_send_json_success($response);
    }
}

}
?>


### 4.2 前端JavaScript处理

/**

  • 前端JavaScript处理
  • 处理用户交互和AJAX请求
    */

jQuery(document).ready(function($) {


// 溯源查询按钮点击事件
$('#mt-trace-btn').on('click', function() {
    var batchNumber = $('#mt-batch-number').val().trim();
    
    if (!batchNumber) {
        alert('请输入批次号');
        return;
    }
    
    performTraceQuery(batchNumber);
});

// 回车键触发查询
$('#mt-batch-number').on('keypress', function(e) {
    if (e.which === 13) {
        $('#mt-trace-btn').click();
    }
});

// 扫码查询功能
$('#mt-scan-btn').on('click', function() {
    if (typeof Html5QrcodeScanner === 'undefined') {
        alert('请确保已加载二维码扫描库');
        return;
    }
    
    const qrScanner = new Html5QrcodeScanner(
        "mt-qr-reader",
        { fps: 10, qrbox: 250 }
    );
    
    $('#mt-qr-reader').show();
    
    qrScanner.render(
        function(decodedText) {
            $('#mt-batch-number').val(decodedText);
            $('#mt-qr-reader').hide();
            qrScanner.clear();
            performTraceQuery(decodedText);
        },
        function(errorMessage) {
            console.error(errorMessage);
        }
    );
});

/**
 * 执行溯源查询
 */
function performTraceQuery(batchNumber) {
    $('#mt-loading').show();
    $('#mt-trace-results').hide().empty();
    
    $.ajax({
        url: mt_public_ajax.ajax_url,
        type: 'POST',
        data: {
            action: 'mt_trace_query',
            nonce: mt_public_ajax.nonce,
            batch_number: batchNumber
        },
        success: function(response) {
            $('#mt-loading').hide();
            
            if (response.success) {
                displayTraceResults(response.data);
            } else {
                $('#mt-trace-results')
                    .html('<div class="mt-error">' + response.data + '</div>')
                    .show();
            }
        },
        error: function() {
            $('#mt-loading').hide();
            $('#mt-trace-results')
                .html('<div class="mt-error">查询失败,请稍后重试</div>')
                .show();
        }
    });
}

/**
 * 显示查询结果
 */
function displayTraceResults(data) {
    var html = '';
    
    if (data.type === 'material') {
        html = `
            <div class="mt-result-card material">
                <h3>原材料溯源信息</h3>
                <div class="mt-info-grid">
                    <div class="mt-info-item">
                        <strong>批次号:</strong>${data.data.batch_number}
                    </div>
                    <div class="mt-info-item">
                        <strong>原材料:</strong>${data.data.material_name}
                    </div>
                    <div class="mt-info-item">
                        <strong>原材料编码:</strong>${data.data.material_code}
                    </div>
                    <div class="mt-info-item">
                        <strong>供应商:</strong>${data.data.supplier_name}
                    </div>
                    <div class="mt-info-item">
                        <strong>入库数量:</strong>${data.data.quantity}
                    </div>
                    <div class="mt-info-item">
                        <strong>生产日期:</strong>${data.data.production_date}
                    </div>
                    <div class="mt-info-item">
                        <strong>检验员:</strong>${data.data.inspector || '未记录'}
                    </div>
                </div>
        `;
        
        if (data.production_batches && data.production_batches.length > 0) {
            html += `
                <h4>使用该原材料的生产批次</h4>
                <table class="mt-production-table">
                    <thead>
                        <tr>
                            <th>生产批次号</th>
                            <th>生产日期</th>
                            <th>产量</th>
                            <th>质检状态</th>
                        </tr>
                    </thead>
                    <tbody>
            `;
            
            data.production_batches.forEach(function(batch) {
                html += `
                    <tr>
                        <td>${batch.batch_number}</td>
                        <td>${batch.production_date}</td>
                        <td>${batch.quantity}</td>
                        <td>${batch.quality_check}</td>
                    </tr>
                `;
            });
            
            html += `</tbody></table>`;
        }
        
        html += `</div>`;
        
    } else if (data.type === 'production') {
        html = `
            <div class="mt-result-card production">
                <h3>生产批次信息</h3>
                <div class="mt-info-grid">
                    <div class="mt-info-item">
                        <strong>生产批次号:</strong>${data.data.batch_number}
                    </div>
                    <div class="mt-info-item">
                        <strong>生产日期:</strong>${data.data.production_date}
                    </div>
                    <div class="mt-info-item">
                        <strong>产量:</strong>${data.data.quantity}
                    </div>
                    <div class="mt-info-item">
                        <strong>操作员:</strong>${data.data.operator}
                    </div>
                    <div class="mt-info-item">
                        <strong>质检状态:</strong>${data.data.quality_check}
                    </div>
                </div>
        `;
        
        if (data.used_materials && data.used_materials.length > 0) {
            html += `
                <h4>使用的原材料</h4>
                <div class="mt-materials-list">
            `;
            
            data.used_materials.forEach(function(materialId) {
                // 这里可以添加获取原材料详情的AJAX调用
                html += `<span class="mt-material-tag">原材料ID: ${materialId}</span>`;
            });
            
            html += `</div>`;
        }
        
        html += `</div>`;
    }
    
    $('#mt-trace-results')
        .html(html)
        .show();
}

});


## 二维码生成与扫描功能

### 5.1 二维码生成类

<?php
/**

  • 二维码生成类
  • 使用PHP QR Code库生成批次二维码
    */

class MT_QRCode {


/**
 * 生成批次二维码
 * @param string $batchNumber 批次号
 * @param string $type 类型:material或production
 * @return string 二维码图片路径
 */
public static function generate_batch_qr($batchNumber, $type = 'material') {
    // 确保二维码库已加载
    if (!class_exists('QRcode')) {
        require_once MT_PLUGIN_PATH . 'includes/libs/phpqrcode/qrlib.php';
    }
    
    // 创建二维码存储目录
    $upload_dir = wp_upload_dir();
    $qr_dir = $upload_dir['basedir'] . '/material-traceability-qr/';
    
    if (!file_exists($qr_dir)) {
        wp_mkdir_p($qr_dir);
    }
    
    // 生成文件名
    $filename = $type . '_' . $batchNumber . '_' . time() . '.png';
    $filepath = $qr_dir . $filename;
    
    // 二维码内容:包含批次号和查询URL
    $site_url = get_site_url();
    $qr_content = $site_url . '/trace?batch=' . urlencode($batchNumber) . '&type=' . $type;
    
    // 生成二维码
    QRcode::png($qr_content, $filepath, 'L', 10, 2);
    
    // 返回URL路径
    return $upload_dir['baseurl'] . '/material-traceability-qr/' . $filename;
}

/**
 * 为入库记录生成二维码
 */
public static function generate_for_inventory($inventory_id) {
    global $wpdb;
    
    $inventory = $wpdb->get_row($wpdb->prepare(
        "SELECT batch_number FROM {$wpdb->prefix}mt_inventory WHERE id = %d",
        $inventory_id
    ));
    
    if (!$inventory) {
        return false;
    }
    
    $qr_url = self::generate_batch_qr($inventory->batch_number, 'material');
    
    // 更新数据库记录
    $wpdb->update(
        $wpdb->prefix . 'mt_inventory',
        array('qr_code_path' => $qr_url),
        array('id' => $inventory_id),
        array('%s'),
        array('%d')
    );
    
    return $qr_url;
}

/**
 * 获取二维码图片
 */
public static function get_qr_image($batchNumber, $type = 'material') {
    global $wpdb;
    
    if ($type === 'material') {
        $record = $wpdb->get_row($wpdb->prepare(
            "SELECT qr_code_path FROM {$wpdb->prefix}mt_inventory WHERE batch_number = %s",
            $batchNumber
        ));
        
        if ($record && $record->qr_code_path) {
            return $record->qr_code_path;
        }
    }
    
    // 如果不存在,生成新的二维码
    return self::generate_batch_qr($batchNumber, $type);
}

}
?>


## 数据导入导出功能

### 6.1 批量导入类

<?php
/**

  • 数据导入导出类
  • 处理Excel/CSV格式的数据导入导出
    */

class MT_ImportExport {


/**
 * 导入原材料数据
 */
public static function import_materials($file_path) {
    global $wpdb;
    
    // 检查文件类型
    $file_ext = pathinfo($file_path, PATHINFO_EXTENSION);
    
    if ($file_ext === 'csv') {
        return self::import_csv_materials($file_path);
    } elseif (in_array($file_ext, ['xls', 'xlsx'])) {
        return self::import_excel_materials($file_path);
    } else {
        return new WP_Error('invalid_format', '不支持的文件格式');
    }
}

/**
 * 导入CSV格式的原材料数据
 */
private static function import_csv_materials($file_path) {
    global $wpdb;
    
    $handle = fopen($file_path, 'r');
    if (!$handle) {
        return new WP_Error('file_error', '无法打开文件');
    }
    
    $headers = fgetcsv($handle);
    $imported = 0;
    $errors = array();
    
    // 验证CSV头部
    $required_headers = ['material_code', 'material_name', 'material_type', 'supplier_code'];
    foreach ($required_headers as $required) {
        if (!in_array($required, $headers)) {
            fclose($handle);
            return new WP_Error('missing_header', 'CSV文件缺少必要列: ' . $required);
        }
    }
    
    $row_number = 1;
    while (($row = fgetcsv($handle)) !== false) {
        $row_number++;
        
        // 跳过空行
        if (empty(array_filter($row))) {
            continue;
        }
        
        // 将行数据转换为关联数组
        $data = array_combine($headers, $row);
        
        // 验证数据
        if (empty($data['material_code']) || empty($data['material_name'])) {
            $errors[] = "第{$row_number}行: 材料编码和名称不能为空";
            continue;
        }
        
        // 查找供应商ID
        $supplier_id = $wpdb->get_var($wpdb->prepare(
            "SELECT id FROM {$wpdb->prefix}mt_suppliers WHERE supplier_code = %s",
            $data['supplier_code']
        ));
        
        if (!$supplier_id) {
            $errors[] = "第{$row_number}行: 供应商编码不存在 - " . $data['supplier_code'];
            continue;
        }
        
        // 准备插入数据
        $insert_data = array(
            'material_code' => sanitize_text_field($data['material_code']),
            'material_name' => sanitize_text_field($data['material_name']),
            'material_type' => sanitize_text_field($data['material_type']),
            'supplier_id' => $supplier_id,
            'unit' => isset($data['unit']) ? sanitize_text_field($data['unit']) : '件',
            'safety_standard' => isset($data['safety_standard']) ? sanitize_textarea_field($data['safety_standard']) : ''
        );
        
        // 检查是否已存在
        $exists = $wpdb->get_var($wpdb->prepare(
            "SELECT id FROM {$wpdb->prefix}mt_materials WHERE material_code = %s",
            $insert_data['material_code']
        ));
        
        if ($exists) {
            // 更新现有记录
            $wpdb->update(
                $wpdb->prefix . 'mt_materials',
                $insert_data,
                array('id' => $exists),
                array('%s', '%s', '%s', '%d', '%s', '%s'),
                array('%d')
            );
        } else {
            // 插入新记录
            $wpdb->insert(
                $wpdb->prefix . 'mt_materials',
                $insert_data,
                array('%s', '%s', '%s', '%d', '%s', '%s')
            );
        }
        
        $imported++;
    }
    
    fclose($handle);
    
    return array(
        'imported' => $imported,
        'errors' => $errors
    );
}

/**
 * 导出原材料数据为CSV
 */
public static function export_materials() {
    global $wpdb;
    
    // 获取所有原材料数据
    $materials = $wpdb->get_results("
        SELECT m.*, s.supplier_code, s.supplier_name
        FROM {$wpdb->prefix}mt_materials m
        LEFT JOIN {$wpdb->prefix}mt_suppliers s ON m.supplier_id = s.id
        ORDER BY m.created_at DESC
    ");
    
    if (empty($materials)) {
        return false;
    }
    
    // 设置CSV头部
    $headers = array(
        '材料编码',
        '材料名称',
        '材料类型',
        '供应商编码',
        '供应商名称',
        '单位',
        '安全标准',
        '创建时间',
        '更新时间'
    );
    
    // 生成文件名
    $filename = 'materials_export_' . date('Ymd_His') . '.csv';
    
    // 设置HTTP头
    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename=' . $filename);
    
    // 输出CSV文件
    $output = fopen('php://output', 'w');
    fputcsv($output, $headers);
    
    foreach ($materials as $material) {
        $row = array(
            $material->material_code,
            $material->material_name,
            $material->material_type,
            $material->supplier_code,
            $material->supplier_name,
            $material->unit,
            $material->safety_standard,
            $material->created_at,
            $material->updated_at
        );
        
        fputcsv($output, $row);
    }
    
    fclose($output);
    exit;
}

}
?>


## 插件优化与安全考虑

### 7.1 安全防护措施

<?php
/**

  • 安全防护类
  • 处理插件安全相关功能
    */

class MT_Security {


/**
 * 验证用户权限
 */
public static function check_permission($capability = 'manage_options') {
    if (!current_user_can($capability)) {
        wp_die('您没有权限执行此操作');
    }
}

/**
 * 清理和验证输入数据
 */
public static function sanitize_input($data, $type = 'text') {
    switch ($type) {
        case 'email':
            return sanitize_email($data);
        case 'url':
            return esc_url_raw($data);
        case 'textarea':
            return sanitize_textarea_field($data);
        case 'int':
            return intval($data);
        case 'float':
            return floatval($data);
        case 'html':
            return wp_kses_post($data);
        default:
            return sanitize_text_field($data);
    }
}

/**
 * 防止SQL注入
 */
public static function prepare_query($query, $args) {
    global $wpdb;
    return $wpdb->prepare($query, $args);
}

/**
 * 验证批次号格式
 */
public static function validate_batch_number($batch_number) {
    // 批次号格式:至少包含字母和数字,长度6-20位
    if (!preg_match('/^[A-Za-z0-9]{6,20}$/', $batch_number)) {
        return new WP_Error('invalid_batch', '批次号格式不正确');
    }
    return $batch_number;
}

/**
 * 记录操作日志
 */
public static function log_operation($user_id, $operation, $details =
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/6359.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

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