文章目录[隐藏]
WordPress柔性供应链软件开发中的容器化部署教程
引言:为什么需要容器化部署
在当今快速发展的电商环境中,柔性供应链系统需要具备高度可扩展性和弹性。WordPress作为广泛使用的内容管理系统,结合定制化的供应链插件,可以构建强大的电商解决方案。然而,传统的部署方式在面对流量波动、快速迭代和跨环境一致性时面临挑战。
容器化技术通过将应用程序及其依赖项打包到标准化单元中,实现了环境一致性、快速部署和弹性扩展。本教程将详细介绍如何将WordPress柔性供应链软件进行容器化部署。
环境准备与Docker安装
Docker环境配置
首先,我们需要在服务器上安装Docker和Docker Compose。以下是在Ubuntu系统上的安装步骤:
#!/bin/bash
# 更新系统包列表
sudo apt-get update
# 安装必要的依赖包
sudo apt-get install -y
apt-transport-https
ca-certificates
curl
gnupg
lsb-release
# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 设置稳定版仓库
echo
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装Docker引擎
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
# 安装Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-$(uname -s)-$(uname -m)"
-o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 验证安装
docker --version
docker-compose --version
项目结构规划
创建以下项目目录结构:
wordpress-supply-chain/
├── docker-compose.yml
├── nginx/
│ ├── Dockerfile
│ └── nginx.conf
├── wordpress/
│ └── Dockerfile
├── mysql/
│ └── init.sql
├── php/
│ └── custom.ini
└── plugins/
└── supply-chain-manager/
└── (供应链插件文件)
Docker容器配置详解
MySQL数据库配置
创建MySQL初始化脚本,用于设置供应链数据库:
-- mysql/init.sql
-- 创建供应链专用数据库
CREATE DATABASE IF NOT EXISTS supply_chain_db;
USE supply_chain_db;
-- 创建供应商表
CREATE TABLE IF NOT EXISTS suppliers (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
contact_email VARCHAR(255),
phone VARCHAR(50),
address TEXT,
reliability_score DECIMAL(3,2) DEFAULT 0.00,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 创建库存表
CREATE TABLE IF NOT EXISTS inventory (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT NOT NULL,
supplier_id INT,
quantity INT DEFAULT 0,
reorder_level INT DEFAULT 10,
last_restocked DATE,
location VARCHAR(100),
FOREIGN KEY (supplier_id) REFERENCES suppliers(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 创建订单跟踪表
CREATE TABLE IF NOT EXISTS order_tracking (
id INT AUTO_INCREMENT PRIMARY KEY,
order_id VARCHAR(50) NOT NULL,
status ENUM('pending', 'processing', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',
supplier_id INT,
estimated_delivery DATE,
actual_delivery DATE,
tracking_number VARCHAR(100),
notes TEXT,
FOREIGN KEY (supplier_id) REFERENCES suppliers(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入示例数据
INSERT INTO suppliers (name, contact_email, reliability_score) VALUES
('优质供应商A', 'supplierA@example.com', 4.8),
('快速配送B', 'supplierB@example.com', 4.5),
('经济优选C', 'supplierC@example.com', 4.2);
WordPress Dockerfile配置
创建WordPress容器的Dockerfile,集成供应链插件:
# wordpress/Dockerfile
# 使用官方WordPress镜像作为基础
FROM wordpress:6.2-php8.1-apache
# 设置维护者信息
LABEL maintainer="supply-chain-dev@example.com"
# 安装必要的PHP扩展
RUN apt-get update && apt-get install -y
libzip-dev
libpng-dev
libjpeg-dev
libfreetype6-dev
&& docker-php-ext-configure gd --with-freetype --with-jpeg
&& docker-php-ext-install -j$(nproc) gd zip pdo_mysql
# 复制自定义PHP配置
COPY ../php/custom.ini /usr/local/etc/php/conf.d/custom.ini
# 复制供应链插件到WordPress插件目录
COPY ../plugins/supply-chain-manager /var/www/html/wp-content/plugins/supply-chain-manager
# 设置插件目录权限
RUN chown -R www-data:www-data /var/www/html/wp-content/plugins/supply-chain-manager
&& chmod -R 755 /var/www/html/wp-content/plugins/supply-chain-manager
# 创建供应链数据目录
RUN mkdir -p /var/www/html/wp-content/uploads/supply-chain
&& chown -R www-data:www-data /var/www/html/wp-content/uploads/supply-chain
# 暴露Apache端口
EXPOSE 80
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD curl -f http://localhost/ || exit 1
Nginx反向代理配置
创建Nginx配置文件,优化WordPress性能:
# nginx/nginx.conf
events {
worker_connections 1024;
}
http {
# 基础配置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# MIME类型
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志配置
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
# WordPress上游服务器
upstream wordpress {
server wordpress:80;
}
# 主服务器配置
server {
listen 80;
server_name supplychain.example.com;
# 根目录
root /var/www/html;
index index.php index.html index.htm;
# WordPress重写规则
location / {
try_files $uri $uri/ /index.php?$args;
}
# PHP处理
location ~ .php$ {
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 增加超时时间用于供应链数据处理
fastcgi_read_timeout 300;
}
# 静态文件缓存
location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 供应链API端点
location ~ ^/wp-json/supply-chain/ {
# 增加API超时时间
fastcgi_read_timeout 60;
# 允许跨域请求(开发环境)
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
}
# 安全设置
location ~ /.ht {
deny all;
}
}
}
Docker Compose编排配置
创建完整的docker-compose.yml文件,编排所有服务:
# docker-compose.yml
version: '3.8'
services:
# MySQL数据库服务
mysql:
image: mysql:8.0
container_name: supply-chain-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-secure_root_password}
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${DB_PASSWORD:-secure_password}
volumes:
- mysql_data:/var/lib/mysql
- ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- supply-chain-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 20s
retries: 10
# WordPress应用服务
wordpress:
build: ./wordpress
container_name: supply-chain-wordpress
restart: unless-stopped
depends_on:
mysql:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: mysql:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD:-secure_password}
WORDPRESS_DB_NAME: wordpress
WORDPRESS_CONFIG_EXTRA: |
define('WP_DEBUG', ${WP_DEBUG:-false});
define('WP_DEBUG_LOG', ${WP_DEBUG_LOG:-false});
define('SUPPLY_CHAIN_API_KEY', ${SUPPLY_CHAIN_API_KEY:-default_key});
volumes:
- wordpress_data:/var/www/html/wp-content
- ./plugins/supply-chain-manager:/var/www/html/wp-content/plugins/supply-chain-manager
networks:
- supply-chain-network
expose:
- "80"
# Nginx反向代理
nginx:
build: ./nginx
container_name: supply-chain-nginx
restart: unless-stopped
depends_on:
- wordpress
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- wordpress_data:/var/www/html/wp-content
networks:
- supply-chain-network
# 供应链监控服务(可选)
monitor:
image: redis:7-alpine
container_name: supply-chain-monitor
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- supply-chain-network
ports:
- "6379:6379"
# 备份服务
backup:
image: alpine:latest
container_name: supply-chain-backup
restart: on-failure
depends_on:
- mysql
- wordpress
volumes:
- backup_data:/backup
- mysql_data:/var/lib/mysql:ro
- wordpress_data:/var/www/html/wp-content:ro
networks:
- supply-chain-network
command: >
sh -c '
echo "备份服务启动..."
while true; do
# 每天凌晨3点执行备份
if [ $$(date +%H) -eq 03 ]; then
echo "开始备份: $$(date)"
# 备份MySQL数据库
mysqldump -h mysql -u wordpress -p$${DB_PASSWORD:-secure_password} wordpress > /backup/mysql-backup-$$(date +%Y%m%d).sql
# 备份WordPress内容
tar -czf /backup/wordpress-backup-$$(date +%Y%m%d).tar.gz /var/www/html/wp-content
echo "备份完成: $$(date)"
# 删除7天前的备份
find /backup -name "*.sql" -mtime +7 -delete
find /backup -name "*.tar.gz" -mtime +7 -delete
fi
sleep 3600
done
'
# 数据卷定义
volumes:
mysql_data:
name: supply-chain-mysql-data
wordpress_data:
name: supply-chain-wordpress-data
redis_data:
name: supply-chain-redis-data
backup_data:
name: supply-chain-backup-data
# 网络定义
networks:
supply-chain-network:
driver: bridge
name: supply-chain-network
部署与运维脚本
部署脚本
创建自动化部署脚本:
#!/bin/bash
# deploy.sh - WordPress供应链系统容器化部署脚本
set -e # 遇到错误时退出
# 颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
NC='33[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查Docker是否安装
check_docker() {
if ! command -v docker &> /dev/null; then
log_error "Docker未安装,请先安装Docker"
exit 1
fi
if ! command -v docker-compose &> /dev/null; then
log_error "Docker Compose未安装,请先安装Docker Compose"
exit 1
fi
log_info "Docker和Docker Compose已安装"
}
# 创建环境变量文件
setup_env() {
if [ ! -f .env ]; then
log_info "创建环境变量文件..."
cat > .env << EOF
# WordPress数据库配置
DB_ROOT_PASSWORD=$(openssl rand -base64 32)
DB_PASSWORD=$(openssl rand -base64 32)
# WordPress调试设置
WP_DEBUG=false
WP_DEBUG_LOG=false
# 供应链API密钥
SUPPLY_CHAIN_API_KEY=$(openssl rand -base64 32)
# 时区设置
TZ=Asia/Shanghai
EOF
log_info "环境变量文件已创建"
else
log_warn "环境变量文件已存在,跳过创建"
fi
}
# 构建并启动容器
start_containers() {
log_info "开始构建Docker镜像..."
docker-compose build --no-cache
log_info "启动容器..."
docker-compose up -d
# 等待服务启动
log_info "等待服务启动..."
sleep 30
# 检查服务状态
if docker-compose ps | grep -q "Up"; then
log_info "所有服务已成功启动!"
# 显示访问信息
echo "========================================"
echo "WordPress供应链系统已部署完成!"
echo "访问地址: http://localhost"
echo "MySQL端口: 3306"
echo "Redis监控: localhost:6379"
echo "========================================"
else
log_error "部分服务启动失败,请检查日志"
docker-compose logs
exit 1
fi
}
# 执行健康检查
health_check() {
log_info "执行健康检查..."
# 检查WordPress
if curl -f http://localhost > /dev/null 2>&1; then
log_info "WordPress服务正常"
else
log_error "WordPress服务异常"
fi
# 检查MySQL
if docker-compose exec -T mysql mysqladmin ping -h localhost > /dev/null 2>&1; then
log_info "MySQL服务正常"
else
log_error "MySQL服务异常"
fi
}
# 主函数
main() {
log_info "开始部署WordPress供应链系统..."
# 检查依赖
check_docker
# 设置环境变量
setup_env
# 启动容器
start_containers
# 健康检查
health_check
log_info "部署完成!"
}
# 执行主函数
main "$@"
供应链插件示例代码
创建供应链管理插件的核心功能文件:
<?php
/**
* WordPress供应链管理插件
* 文件名: supply-chain-manager.php
* 描述: 柔性供应链核心管理功能
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
/**
* 供应链管理器主类
*/
class SupplyChainManager {
private $db;
private $api_key;
/**
* 构造函数
*/
public function __construct() {
global $wpdb;
$this->db = $wpdb;
$this->api_key = defined('SUPPLY_CHAIN_API_KEY') ? SUPPLY_CHAIN_API_KEY : '';
// 初始化钩子
$this->init_hooks();
}
/**
* 初始化WordPress钩子
*/
private function init_hooks() {
// 添加管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 注册REST API端点
add_action('rest_api_init', array($this, 'register_rest_routes'));
// 注册供应链数据表
register_activation_hook(__FILE__, array($this, 'create_tables'));
// 添加库存检查钩子
add_action('woocommerce_checkout_order_processed', array($this, 'check_inventory'), 10, 3);
// 添加供应商选择短代码
add_shortcode('supplier_selection', array($this, 'supplier_selection_shortcode'));
}
/**
* 创建供应链数据表
*/
public function create_tables() {
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
$charset_collate = $this->db->get_charset_collate();
// 供应商表
$suppliers_table = $this->db->prefix . 'supply_chain_suppliers';
$sql = "CREATE TABLE IF NOT EXISTS $suppliers_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
code varchar(50) NOT NULL UNIQUE,
contact_person varchar(100),
email varchar(100),
phone varchar(50),
address text,
reliability_score decimal(3,2) DEFAULT 0.00,
lead_time_days int DEFAULT 7,
minimum_order decimal(10,2),
payment_terms text,
is_active tinyint(1) DEFAULT 1,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_reliability (reliability_score),
INDEX idx_active (is_active)
) $charset_collate;";
dbDelta($sql);
// 库存表
$inventory_table = $this->db->prefix . 'supply_chain_inventory';
$sql = "CREATE TABLE IF NOT EXISTS $inventory_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
product_id bigint(20) NOT NULL,
supplier_id mediumint(9),
sku varchar(100),
current_stock int DEFAULT 0,
reserved_stock int DEFAULT 0,
available_stock int GENERATED ALWAYS AS (current_stock - reserved_stock) STORED,
reorder_point int DEFAULT 10,
safety_stock int DEFAULT 5,
unit_cost decimal(10,2),
location varchar(100),
batch_number varchar(50),
expiry_date date,
last_updated datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (supplier_id) REFERENCES $suppliers_table(id) ON DELETE SET NULL,
INDEX idx_product (product_id),
INDEX idx_available (available_stock),
INDEX idx_reorder (reorder_point),
UNIQUE KEY unique_product_supplier (product_id, supplier_id)
) $charset_collate;";
dbDelta($sql);
// 采购订单表
$orders_table = $this->db->prefix . 'supply_chain_orders';
$sql = "CREATE TABLE IF NOT EXISTS $orders_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
order_number varchar(50) NOT NULL UNIQUE,
supplier_id mediumint(9) NOT NULL,
status enum('draft','pending','confirmed','shipped','delivered','cancelled') DEFAULT 'draft',
total_amount decimal(10,2) DEFAULT 0.00,
currency varchar(3) DEFAULT 'USD',
order_date datetime DEFAULT CURRENT_TIMESTAMP,
expected_delivery date,
actual_delivery date,
notes text,
created_by bigint(20),
PRIMARY KEY (id),
FOREIGN KEY (supplier_id) REFERENCES $suppliers_table(id),
INDEX idx_status (status),
INDEX idx_delivery (expected_delivery),
INDEX idx_supplier (supplier_id)
) $charset_collate;";
dbDelta($sql);
// 订单项表
$order_items_table = $this->db->prefix . 'supply_chain_order_items';
$sql = "CREATE TABLE IF NOT EXISTS $order_items_table (
id mediumint(9) NOT NULL AUTO_INCREMENT,
order_id mediumint(9) NOT NULL,
product_id bigint(20) NOT NULL,
quantity int NOT NULL,
unit_price decimal(10,2) NOT NULL,
total_price decimal(10,2) GENERATED ALWAYS AS (quantity * unit_price) STORED,
received_quantity int DEFAULT 0,
status enum('pending','partial','completed') DEFAULT 'pending',
PRIMARY KEY (id),
FOREIGN KEY (order_id) REFERENCES $orders_table(id) ON DELETE CASCADE,
INDEX idx_order (order_id),
INDEX idx_product (product_id)
) $charset_collate;";
dbDelta($sql);
}
/**
* 添加管理菜单
*/
public function add_admin_menu() {
add_menu_page(
'供应链管理',
'供应链',
'manage_options',
'supply-chain',
array($this, 'render_dashboard'),
'dashicons-networking',
30
);
add_submenu_page(
'supply-chain',
'供应商管理',
'供应商',
'manage_options',
'supply-chain-suppliers',
array($this, 'render_suppliers_page')
);
add_submenu_page(
'supply-chain',
'库存管理',
'库存',
'manage_options',
'supply-chain-inventory',
array($this, 'render_inventory_page')
);
add_submenu_page(
'supply-chain',
'采购订单',
'采购订单',
'manage_options',
'supply-chain-orders',
array($this, 'render_orders_page')
);
add_submenu_page(
'supply-chain',
'报表分析',
'报表',
'manage_options',
'supply-chain-reports',
array($this, 'render_reports_page')
);
}
/**
* 注册REST API端点
*/
public function register_rest_routes() {
// 供应商API
register_rest_route('supply-chain/v1', '/suppliers', array(
'methods' => 'GET',
'callback' => array($this, 'get_suppliers_api'),
'permission_callback' => array($this, 'check_api_permission')
));
register_rest_route('supply-chain/v1', '/suppliers/(?P<id>d+)', array(
'methods' => 'GET',
'callback' => array($this, 'get_supplier_api'),
'permission_callback' => array($this, 'check_api_permission')
));
// 库存API
register_rest_route('supply-chain/v1', '/inventory', array(
'methods' => 'GET',
'callback' => array($this, 'get_inventory_api'),
'permission_callback' => array($this, 'check_api_permission')
));
register_rest_route('supply-chain/v1', '/inventory/low-stock', array(
'methods' => 'GET',
'callback' => array($this, 'get_low_stock_api'),
'permission_callback' => array($this, 'check_api_permission')
));
// 订单API
register_rest_route('supply-chain/v1', '/orders', array(
'methods' => 'POST',
'callback' => array($this, 'create_order_api'),
'permission_callback' => array($this, 'check_api_permission')
));
}
/**
* API权限检查
*/
public function check_api_permission($request) {
$api_key = $request->get_header('X-API-Key');
// 验证API密钥
if ($api_key === $this->api_key) {
return true;
}
// 检查用户权限
if (current_user_can('manage_options')) {
return true;
}
return new WP_Error('rest_forbidden', '无权访问', array('status' => 403));
}
/**
* 获取供应商列表API
*/
public function get_suppliers_api($request) {
$table_name = $this->db->prefix . 'supply_chain_suppliers';
$page = $request->get_param('page') ? intval($request->get_param('page')) : 1;
$per_page = $request->get_param('per_page') ? intval($request->get_param('per_page')) : 20;
$offset = ($page - 1) * $per_page;
// 构建查询
$sql = "SELECT * FROM $table_name WHERE is_active = 1";
// 添加筛选条件
if ($request->get_param('min_reliability')) {
$min_reliability = floatval($request->get_param('min_reliability'));
$sql .= $this->db->prepare(" AND reliability_score >= %f", $min_reliability);
}
// 添加排序
$orderby = $request->get_param('orderby') ?: 'reliability_score';
$order = $request->get_param('order') ?: 'DESC';
$sql .= " ORDER BY $orderby $order";
// 添加分页
$sql .= $this->db->prepare(" LIMIT %d OFFSET %d", $per_page, $offset);
$suppliers = $this->db->get_results($sql);
// 获取总数
$count_sql = "SELECT COUNT(*) FROM $table_name WHERE is_active = 1";
$total = $this->db->get_var($count_sql);
return rest_ensure_response(array(
'data' => $suppliers,
'pagination' => array(
'page' => $page,
'per_page' => $per_page,
'total' => intval($total),
'total_pages' => ceil($total / $per_page)
)
));
}
/**
* 检查库存
*/
public function check_inventory($order_id, $posted_data, $order) {
$items = $order->get_items();
foreach ($items as $item) {
$product_id = $item->get_product_id();
$quantity = $item->get_quantity();
// 检查库存
$inventory_table = $this->db->prefix . 'supply_chain_inventory';
$sql = $this->db->prepare(
"SELECT available_stock FROM $inventory_table WHERE product_id = %d",
$product_id
);
$available_stock = $this->db->get_var($sql);
if ($available_stock < $quantity) {
// 库存不足,触发补货逻辑
$this->trigger_reorder($product_id, $quantity - $available_stock);
// 记录库存预留
$this->reserve_stock($product_id, $available_stock);
// 发送通知
$this->send_low_stock_notification($product_id, $available_stock, $quantity);
} else {
// 预留库存
$this->reserve_stock($product_id, $quantity);
}
}
}
/**
* 触发补货逻辑
*/
private function trigger_reorder($product_id, $required_quantity) {
// 获取最佳供应商
$best_supplier = $this->get_best_supplier($product_id);
if ($best_supplier) {
// 创建采购订单
$order_data = array(
'supplier_id' => $best_supplier->id,
'product_id' => $product_id,
'quantity' => max($required_quantity * 2, 50), // 最少补货50件或需求量的2倍
'unit_price' => $this->get_supplier_price($best_supplier->id, $product_id)
);
$this->create_purchase_order($order_data);
}
}
/**
* 获取最佳供应商
*/
private function get_best_supplier($product_id) {
$suppliers_table = $this->db->prefix . 'supply_chain_suppliers';
$inventory_table = $this->db->prefix . 'supply_chain_inventory';
$sql = $this->db->prepare(
"SELECT s.*, i.unit_price
FROM $suppliers_table s
INNER JOIN $inventory_table i ON s.id = i.supplier_id
WHERE i.product_id = %d
AND s.is_active = 1
ORDER BY s.reliability_score DESC, i.unit_price ASC
LIMIT 1",
$product_id
);
return $this->db->get_row($sql);
}
/**
* 供应商选择短代码
*/
public function supplier_selection_shortcode($atts) {
$atts = shortcode_atts(array(
'product_id' => 0,
'show_prices' => true
), $atts);
if (!$atts['product_id']) {
return '<p>请指定产品ID</p>';
}
ob_start();
?>
<div class="supplier-selection-widget">
<h3>选择供应商</h3>
<div class="supplier-options">
<?php
$suppliers = $this->get_product_suppliers($atts['product_id']);
foreach ($suppliers as $supplier) {
?>
<div class="supplier-option">
<input type="radio"
name="supplier_<?php echo $atts['product_id']; ?>"
value="<?php echo $supplier->id; ?>"
data-price="<?php echo $supplier->unit_price; ?>"
data-lead-time="<?php echo $supplier->lead_time_days; ?>">
<label>
<strong><?php echo esc_html($supplier->name); ?></strong>
<?php if ($atts['show_prices']): ?>
<span class="price">$<?php echo number_format($supplier->unit_price, 2); ?></span>
<?php endif; ?>
<span class="lead-time">交货期: <?php echo $supplier->lead_time_days; ?>天</span>
<span class="reliability">可靠度: <?php echo $supplier->reliability_score; ?>/5</span>
</label>
</div>
<?php
}
?>
</div>
</div>
<style>
.supplier-selection-widget {
border: 1px solid #ddd;
padding: 20px;
margin: 20px 0;
border-radius: 5px;
}
.supplier-option {
margin: 10px 0;
padding: 10px;
border: 1px solid #eee;
border-radius: 3px;
}
.supplier-option:hover {
background-color: #f9f9f9;
}
.supplier-option label {
display: block;
margin-left: 25px;
cursor: pointer;
}
.supplier-option .price {
color: #0073aa;
font-weight: bold;
margin-left: 15px;
}
.supplier-option .lead-time {
color: #666;
margin-left: 15px;
font-size: 0.9em;
}
.supplier-option .reliability {
color: #46b450;
margin-left: 15px;
font-size: 0.9em;
}
</style>
<script>
jQuery(document).ready(function($) {
$('.supplier-option input').on('change', function() {
var price = $(this).data('price');
var leadTime = $(this).data('lead-time');
// 更新产品价格和交货时间显示
$('.product-price').text('$' + price.toFixed(2));
$('.delivery-time').text('预计' + leadTime + '天内发货');
// 发送AJAX请求更新购物车
$.ajax({
url: '<?php echo rest_url('supply-chain/v1/update-cart'); ?>',
method: 'POST',
data: {
product_id: <?php echo $atts['product_id']; ?>,
supplier_id: $(this).val(),
price: price
}
});
});
});
</script>
<?php
return ob_get_clean();
}
/**
* 获取产品供应商
*/
private function get_product_suppliers($product_id) {
$suppliers_table = $this->db->prefix . 'supply_chain_suppliers';
$inventory_table = $this->db->prefix . 'supply_chain_inventory';
$sql = $this->db->prepare(
"SELECT s.*, i.unit_price
FROM $suppliers_table s
INNER JOIN $inventory_table i ON s.id = i.supplier_id
WHERE i.product_id = %d
AND s.is_active = 1
AND i.available_stock > 0
ORDER BY s.reliability_score DESC, i.unit_price ASC",
$product_id
);
return $this->db->get_results($sql);
}
/**
* 渲染仪表板
*/
public function render_dashboard() {
?>
<div class="wrap supply-chain-dashboard">
<h1>供应链仪表板</h1>
<div class="dashboard-stats">
<div class="stat-card">
<h3>活跃供应商</h3>
<p class="stat-number"><?php echo $this->get_supplier_count(); ?></p>
</div>
<div class="stat-card">
<h3>低库存产品</h3>
<p class="stat-number"><?php echo $this->get_low_stock_count(); ?></p>
</div
