文章目录[隐藏]
WordPress柔性供应链软件的跨平台数据同步技术教程
引言:柔性供应链与数据同步的重要性
在当今全球化的商业环境中,柔性供应链管理系统已成为企业保持竞争力的关键。WordPress作为全球最流行的内容管理系统,其强大的扩展性使其成为构建供应链管理平台的理想选择。然而,随着业务在多平台(Web、移动端、桌面应用)的扩展,数据同步问题成为柔性供应链软件必须解决的核心挑战。
本文将详细介绍如何为WordPress柔性供应链软件实现跨平台数据同步,涵盖技术架构设计、API开发、数据同步策略以及完整代码实现。
技术架构设计
整体架构概述
我们的跨平台数据同步系统采用RESTful API作为核心通信机制,结合WebSocket实现实时数据更新。系统架构分为三个主要层次:
- 数据层:WordPress数据库(MySQL)作为主数据存储
- API层:自定义REST API端点处理数据请求
- 同步层:负责数据变更检测和跨平台同步
数据库设计考虑
为了实现高效同步,我们需要在标准供应链数据表基础上添加同步元数据:
-- 示例:供应链产品表结构
CREATE TABLE wp_flexible_supply_products (
product_id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
product_name VARCHAR(200) NOT NULL,
sku VARCHAR(100) UNIQUE NOT NULL,
current_stock INT DEFAULT 0,
reorder_level INT DEFAULT 10,
supplier_id BIGINT(20) UNSIGNED,
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
sync_version INT DEFAULT 1,
sync_status ENUM('pending', 'synced', 'conflict') DEFAULT 'synced',
platform_source VARCHAR(50) DEFAULT 'web'
);
RESTful API开发
创建自定义API端点
在WordPress中创建自定义REST API端点来处理供应链数据:
<?php
/**
* WordPress柔性供应链API端点
* 文件名: flexible-supply-api.php
*/
// 注册供应链产品API路由
add_action('rest_api_init', function () {
// 获取产品列表
register_rest_route('flexible-supply/v1', '/products', [
'methods' => 'GET',
'callback' => 'get_supply_products',
'permission_callback' => 'check_supply_api_permission'
]);
// 同步产品数据
register_rest_route('flexible-supply/v1', '/products/sync', [
'methods' => 'POST',
'callback' => 'sync_products_data',
'permission_callback' => 'check_supply_api_permission'
]);
// 获取同步状态
register_rest_route('flexible-supply/v1', '/sync/status', [
'methods' => 'GET',
'callback' => 'get_sync_status',
'permission_callback' => 'check_supply_api_permission'
]);
});
/**
* 权限检查函数
*/
function check_supply_api_permission($request) {
// 检查API密钥或用户权限
$api_key = $request->get_header('X-API-Key');
if (!empty($api_key)) {
// 验证API密钥
$valid_keys = get_option('supply_api_keys', []);
return in_array($api_key, $valid_keys);
}
// 或者检查用户权限
return current_user_can('manage_options');
}
/**
* 获取产品列表
*/
function get_supply_products($request) {
global $wpdb;
$page = $request->get_param('page') ?: 1;
$per_page = $request->get_param('per_page') ?: 20;
$offset = ($page - 1) * $per_page;
// 获取需要同步的产品(基于版本控制)
$min_version = $request->get_param('min_version') ?: 0;
$products = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}flexible_supply_products
WHERE sync_version > %d
ORDER BY last_modified DESC
LIMIT %d OFFSET %d",
$min_version, $per_page, $offset
));
// 获取总数用于分页
$total = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->prefix}flexible_supply_products
WHERE sync_version > %d",
$min_version
));
return [
'data' => $products,
'pagination' => [
'page' => (int)$page,
'per_page' => (int)$per_page,
'total' => (int)$total,
'total_pages' => ceil($total / $per_page)
],
'current_sync_version' => get_max_sync_version()
];
}
/**
* 获取最大同步版本号
*/
function get_max_sync_version() {
global $wpdb;
return $wpdb->get_var(
"SELECT MAX(sync_version) FROM {$wpdb->prefix}flexible_supply_products"
) ?: 0;
}
?>
数据同步策略实现
增量同步与冲突解决
实现智能同步机制,减少数据传输量并处理数据冲突:
<?php
/**
* 同步产品数据
* 处理来自其他平台的数据同步请求
*/
function sync_products_data($request) {
global $wpdb;
$platform = $request->get_param('platform') ?: 'unknown';
$sync_data = $request->get_json_params();
$results = [
'success' => [],
'updated' => [],
'conflicts' => [],
'failed' => []
];
if (empty($sync_data['products'])) {
return new WP_REST_Response(['error' => '无同步数据'], 400);
}
foreach ($sync_data['products'] as $product) {
try {
// 检查产品是否存在
$existing = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}flexible_supply_products
WHERE sku = %s",
$product['sku']
));
if ($existing) {
// 冲突检测:检查版本
if ($product['sync_version'] <= $existing->sync_version) {
// 数据过期,跳过
continue;
}
// 检查是否有未解决的冲突
if ($existing->sync_status === 'conflict') {
$results['conflicts'][] = [
'sku' => $product['sku'],
'message' => '存在数据冲突需要手动解决'
];
continue;
}
// 更新现有产品
$wpdb->update(
"{$wpdb->prefix}flexible_supply_products",
[
'product_name' => $product['product_name'],
'current_stock' => $product['current_stock'],
'reorder_level' => $product['reorder_level'],
'last_modified' => current_time('mysql'),
'sync_version' => $product['sync_version'] + 1,
'sync_status' => 'synced',
'platform_source' => $platform
],
['sku' => $product['sku']]
);
$results['updated'][] = $product['sku'];
} else {
// 插入新产品
$wpdb->insert(
"{$wpdb->prefix}flexible_supply_products",
[
'product_name' => $product['product_name'],
'sku' => $product['sku'],
'current_stock' => $product['current_stock'],
'reorder_level' => $product['reorder_level'],
'last_modified' => current_time('mysql'),
'sync_version' => 1,
'sync_status' => 'synced',
'platform_source' => $platform
]
);
$results['success'][] = $product['sku'];
}
} catch (Exception $e) {
$results['failed'][] = [
'sku' => $product['sku'] ?? 'unknown',
'error' => $e->getMessage()
];
}
}
// 触发同步完成钩子
do_action('flexible_supply_sync_completed', $results, $platform);
return [
'result' => $results,
'sync_timestamp' => current_time('mysql'),
'server_version' => get_max_sync_version()
];
}
?>
实时同步与WebSocket集成
WebSocket服务器实现
对于需要实时更新的场景(如库存预警、订单状态变更),我们集成WebSocket:
// WebSocket客户端示例 - 用于移动端或桌面应用
class SupplyChainWebSocket {
constructor(options = {}) {
this.wsUrl = options.wsUrl || 'wss://yourdomain.com/ws/supplychain';
this.reconnectInterval = options.reconnectInterval || 5000;
this.ws = null;
this.listeners = new Map();
this.isConnected = false;
this.connect();
}
connect() {
try {
this.ws = new WebSocket(this.wsUrl);
this.ws.onopen = () => {
console.log('供应链WebSocket连接已建立');
this.isConnected = true;
this.emit('connected', { timestamp: new Date() });
// 发送认证信息
this.send({
type: 'auth',
apiKey: this.apiKey,
platform: 'mobile' // 或 'desktop', 'tablet'
});
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleMessage(data);
};
this.ws.onclose = () => {
console.log('WebSocket连接已关闭');
this.isConnected = false;
this.emit('disconnected');
// 尝试重新连接
setTimeout(() => this.connect(), this.reconnectInterval);
};
this.ws.onerror = (error) => {
console.error('WebSocket错误:', error);
this.emit('error', error);
};
} catch (error) {
console.error('连接WebSocket失败:', error);
}
}
handleMessage(data) {
switch (data.type) {
case 'stock_update':
this.emit('stockUpdate', data.payload);
break;
case 'order_status':
this.emit('orderStatus', data.payload);
break;
case 'sync_request':
this.handleSyncRequest(data.payload);
break;
case 'auth_response':
if (data.success) {
console.log('WebSocket认证成功');
} else {
console.error('WebSocket认证失败:', data.message);
}
break;
}
}
handleSyncRequest(payload) {
// 向服务器请求同步数据
fetch('/wp-json/flexible-supply/v1/products', {
headers: {
'X-API-Key': this.apiKey
}
})
.then(response => response.json())
.then(data => {
// 处理获取的数据
this.emit('dataSynced', data);
});
}
send(data) {
if (this.ws && this.isConnected) {
this.ws.send(JSON.stringify(data));
}
}
on(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event).push(callback);
}
emit(event, data) {
const callbacks = this.listeners.get(event);
if (callbacks) {
callbacks.forEach(callback => callback(data));
}
}
}
// 使用示例
const supplySocket = new SupplyChainWebSocket({
wsUrl: 'wss://supply.yourdomain.com/ws'
});
supplySocket.on('stockUpdate', (data) => {
console.log('库存更新:', data);
// 更新本地UI
updateStockDisplay(data.productId, data.newStock);
});
supplySocket.on('orderStatus', (data) => {
console.log('订单状态更新:', data);
// 通知用户
showNotification(`订单 ${data.orderId} 状态已更新为: ${data.status}`);
});
移动端同步适配器
React Native示例
// React Native数据同步管理器
import AsyncStorage from '@react-native-async-storage/async-storage';
import NetInfo from '@react-native-community/netinfo';
class MobileSyncManager {
constructor() {
this.baseUrl = 'https://yourwordpresssite.com/wp-json/flexible-supply/v1';
this.apiKey = 'YOUR_API_KEY';
this.isSyncing = false;
this.syncQueue = [];
this.setupNetworkListener();
}
setupNetworkListener() {
// 监听网络状态变化
NetInfo.addEventListener(state => {
if (state.isConnected && !this.isSyncing) {
this.processSyncQueue();
}
});
}
async syncProducts() {
if (this.isSyncing) return;
this.isSyncing = true;
try {
// 获取本地最后同步版本
const lastSyncVersion = await AsyncStorage.getItem('last_sync_version') || 0;
// 从服务器获取更新
const response = await fetch(
`${this.baseUrl}/products?min_version=${lastSyncVersion}`,
{
headers: {
'X-API-Key': this.apiKey
}
}
);
const data = await response.json();
if (data.data && data.data.length > 0) {
// 保存到本地存储
await this.saveProductsLocally(data.data);
// 更新同步版本
await AsyncStorage.setItem(
'last_sync_version',
data.current_sync_version.toString()
);
console.log(`同步完成,更新了 ${data.data.length} 条记录`);
}
return data;
} catch (error) {
console.error('同步失败:', error);
throw error;
} finally {
this.isSyncing = false;
}
}
async saveProductsLocally(products) {
try {
// 将产品数据保存到本地存储
const localProducts = {};
products.forEach(product => {
localProducts[product.sku] = {
...product,
last_synced: new Date().toISOString()
};
});
await AsyncStorage.setItem(
'local_products',
JSON.stringify(localProducts)
);
return true;
} catch (error) {
console.error('保存本地数据失败:', error);
return false;
}
}
async queueForSync(productData) {
// 将数据加入同步队列(用于离线操作)
this.syncQueue.push({
...productData,
timestamp: Date.now(),
sync_version: await this.getNextLocalVersion()
});
await AsyncStorage.setItem('sync_queue', JSON.stringify(this.syncQueue));
// 如果在线,立即同步
const netState = await NetInfo.fetch();
if (netState.isConnected) {
this.processSyncQueue();
}
}
async processSyncQueue() {
if (this.syncQueue.length === 0 || this.isSyncing) return;
this.isSyncing = true;
try {
const queueToProcess = [...this.syncQueue];
const response = await fetch(`${this.baseUrl}/products/sync`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey
},
body: JSON.stringify({
products: queueToProcess,
platform: 'mobile'
})
});
const result = await response.json();
if (result.result) {
// 从队列中移除已同步的项目
this.syncQueue = this.syncQueue.filter(item =>
!queueToProcess.some(q => q.timestamp === item.timestamp)
);
await AsyncStorage.setItem('sync_queue', JSON.stringify(this.syncQueue));
}
return result;
} catch (error) {
console.error('处理同步队列失败:', error);
} finally {
this.isSyncing = false;
}
}
async getNextLocalVersion() {
const current = await AsyncStorage.getItem('local_sync_version') || 0;
const next = parseInt(current) + 1;
await AsyncStorage.setItem('local_sync_version', next.toString());
return next;
}
}
// 使用示例
const syncManager = new MobileSyncManager();
// 定期同步
setInterval(() => {
syncManager.syncProducts();
}, 300000); // 每5分钟同步一次
安全与性能优化
安全措施实现
<?php
/**
* 供应链API安全增强
*/
// 1. API请求限流
add_filter('rest_pre_dispatch', 'supply_api_rate_limit', 10, 3);
function supply_api_rate_limit($result, $server, $request) {
$route = $request->get_route();
// 检查是否是供应链API
if (strpos($route, '/flexible-supply/') === 0) {
$client_ip = $_SERVER['REMOTE_ADDR'];
$api_key = $request->get_header('X-API-Key');
// 基于API密钥或IP的限流
$identifier = $api_key ?: $client_ip;
$transient_name = 'supply_api_limit_' . md5($identifier);
$requests = get_transient($transient_name) ?: 0;
if ($requests > 100) { // 每分钟100次请求限制
return new WP_Error(
'rate_limit_exceeded',
'API请求频率过高,请稍后再试',
['status' => 429]
);
}
// 增加计数
set_transient($transient_name, $requests + 1, 60);
}
return $result;
}
// 2. 数据加密传输
function encrypt_supply_data($data, $platform) {
// 使用平台特定的加密密钥
$platform_keys = [
'mobile' => defined('MOBILE_ENCRYPTION_KEY') ? MOBILE_ENCRYPTION_KEY : '',
'desktop' => defined('DESKTOP_ENCRYPTION_KEY') ? DESKTOP_ENCRYPTION_KEY : '',
'web' => defined('WEB_ENCRYPTION_KEY') ? WEB_ENCRYPTION_KEY : ''
];
$key = $platform_keys[$platform] ?? '';
if (empty($key)) {
return $data; // 退回不加密
}
// 使用OpenSSL加密
$iv_length = openssl_cipher_iv_length('AES-256-CBC');
$iv = openssl_random_pseudo_bytes($iv_length);
$encrypted = openssl_encrypt(
json_encode($data),
'AES-256-CBC',
$key,
OPENSSL_RAW_DATA,
$iv
);
return base64_encode($iv . $encrypted);
}
// 3. 数据完整性验证
function verify_data_signature($data, $signature, $api_key) {
$secret = get_api_key_secret($api_key);
if (!$secret) {
return false;
}
$expected_signature = hash_hmac('sha256', json_encode($data), $secret);
return hash_equals($expected_signature, $signature);
}
?>
性能优化策略
<?php
/**
* 供应链数据同步性能优化
*/
// 1. 数据库查询优化
add_action('init', 'register_supply_data_cache');
function register_supply_data_cache() {
// 注册数据缓存组
wp_cache_add_global_groups(['supply_chain_data']);
}
function get_cached_products($min_version = 0, $force_refresh = false) {
$cache_key = 'products_v' . $min_version;
// 尝试从缓存获取
$cached = wp_cache_get($cache_key, 'supply_chain_data');
if ($cached !== false && !$force_refresh) {
return $cached;
}
global $wpdb;
// 优化查询:使用索引和分页
$products = $wpdb->get_results($wpdb->prepare(
"SELECT SQL_CALC_FOUND_ROWS
product_id, product_name, sku, current_stock,
reorder_level, sync_version, last_modified
FROM {$wpdb->prefix}flexible_supply_products
WHERE sync_version > %d
AND sync_status != 'pending'
ORDER BY last_modified DESC
LIMIT 100",
$min_version
));
// 获取总数
$total = $wpdb->get_var("SELECT FOUND_ROWS()");
$result = [
'products' => $products,
'total' => $total,
'timestamp' => time()
];
// 缓存结果(5分钟)
wp_cache_set($cache_key, $result, 'supply_chain_data', 300);
return $result;
}
// 2. 批量操作优化
function batch_sync_products($products_data) {
global $wpdb;
if (empty($products_data)) {
return false;
}
// 使用事务确保数据一致性
$wpdb->query('START TRANSACTION');
try {
$placeholders = [];
$values = [];
// 准备批量插入/更新
foreach ($products_data as $product) {
$placeholders[] = "(%s, %s, %d, %d, %d, %s)";
$values = array_merge($values, [
$product['sku'],
$product['product_name'],
$product['current_stock'],
$product['reorder_level'],
$product['sync_version'],
current_time('mysql')
]);
}
// 使用ON DUPLICATE KEY UPDATE实现upsert
$sql = "INSERT INTO {$wpdb->prefix}flexible_supply_products
(sku, product_name, current_stock, reorder_level, sync_version, last_modified)
VALUES " . implode(', ', $placeholders) . "
ON DUPLICATE KEY UPDATE
product_name = VALUES(product_name),
current_stock = VALUES(current_stock),
reorder_level = VALUES(reorder_level),
sync_version = VALUES(sync_version),
last_modified = VALUES(last_modified)";
$wpdb->query($wpdb->prepare($sql, $values));
// 清除相关缓存
wp_cache_delete('products_v0', 'supply_chain_data');
$wpdb->query('COMMIT');
return true;
} catch (Exception $e) {
$wpdb->query('ROLLBACK');
error_log('批量同步失败: ' . $e->getMessage());
return false;
}
}
// 3. 异步处理机制
add_action('wp_ajax_nopriv_process_async_sync', 'handle_async_sync_request');
add_action('wp_ajax_process_async_sync', 'handle_async_sync_request');
function handle_async_sync_request() {
// 验证请求
if (!wp_verify_nonce($_POST['nonce'], 'async_sync_action')) {
wp_die('非法请求');
}
// 立即返回响应,让客户端知道请求已接收
header('Content-Type: application/json');
echo json_encode(['status' => 'processing', 'job_id' => uniqid()]);
// 关闭连接,继续在后台处理
fastcgi_finish_request();
// 实际处理同步任务
$sync_data = json_decode(file_get_contents('php://input'), true);
process_background_sync($sync_data);
exit;
}
function process_background_sync($sync_data) {
// 这里执行耗时的同步操作
// 例如:大数据量处理、外部API调用等
// 记录处理状态
update_option('last_sync_job_status', [
'completed_at' => current_time('mysql'),
'processed_items' => count($sync_data['products'] ?? []),
'status' => 'completed'
]);
}
?>
监控与日志系统
同步状态监控
<?php
/**
* 供应链同步监控系统
*/
class SupplySyncMonitor {
private static $instance;
private $log_table;
private function __construct() {
global $wpdb;
$this->log_table = $wpdb->prefix . 'supply_sync_logs';
$this->create_log_table();
}
public static function get_instance() {
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function create_log_table() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS {$this->log_table} (
log_id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
sync_type VARCHAR(50) NOT NULL,
platform_source VARCHAR(50) NOT NULL,
items_count INT DEFAULT 0,
success_count INT DEFAULT 0,
failed_count INT DEFAULT 0,
conflict_count INT DEFAULT 0,
start_time DATETIME DEFAULT CURRENT_TIMESTAMP,
end_time DATETIME NULL,
duration FLOAT NULL,
status ENUM('running', 'completed', 'failed') DEFAULT 'running',
error_message TEXT NULL,
sync_data LONGTEXT NULL,
INDEX idx_platform (platform_source),
INDEX idx_status (status),
INDEX idx_time (start_time)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
public function log_sync_start($type, $platform, $data = null) {
global $wpdb;
$wpdb->insert(
$this->log_table,
[
'sync_type' => $type,
'platform_source' => $platform,
'start_time' => current_time('mysql'),
'status' => 'running',
'sync_data' => $data ? json_encode($data) : null
]
);
return $wpdb->insert_id;
}
public function log_sync_complete($log_id, $results) {
global $wpdb;
$end_time = current_time('mysql');
$start_time = $wpdb->get_var($wpdb->prepare(
"SELECT start_time FROM {$this->log_table} WHERE log_id = %d",
$log_id
));
$duration = strtotime($end_time) - strtotime($start_time);
$wpdb->update(
$this->log_table,
[
'end_time' => $end_time,
'duration' => $duration,
'status' => 'completed',
'items_count' => count($results['success']) +
count($results['updated']) +
count($results['failed']) +
count($results['conflicts']),
'success_count' => count($results['success']),
'failed_count' => count($results['failed']),
'conflict_count' => count($results['conflicts'])
],
['log_id' => $log_id]
);
}
public function get_sync_stats($period = 'day') {
global $wpdb;
$time_condition = '';
switch ($period) {
case 'hour':
$time_condition = "AND start_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR)";
break;
case 'day':
$time_condition = "AND start_time >= DATE_SUB(NOW(), INTERVAL 1 DAY)";
break;
case 'week':
$time_condition = "AND start_time >= DATE_SUB(NOW(), INTERVAL 1 WEEK)";
break;
}
$stats = $wpdb->get_results($wpdb->prepare(
"SELECT
platform_source,
COUNT(*) as total_syncs,
AVG(duration) as avg_duration,
SUM(success_count) as total_success,
SUM(failed_count) as total_failed,
SUM(conflict_count) as total_conflicts
FROM {$this->log_table}
WHERE status = 'completed'
{$time_condition}
GROUP BY platform_source
ORDER BY total_syncs DESC"
));
return $stats;
}
public function send_alert_on_failure($log_id, $error) {
$alert_settings = get_option('supply_sync_alerts', []);
if (empty($alert_settings['enabled'])) {
return;
}
// 发送邮件通知
if (!empty($alert_settings['email'])) {
$subject = '供应链同步失败警报';
$message = "同步任务 #{$log_id} 失败n";
$message .= "错误信息: {$error}n";
$message .= "时间: " . current_time('mysql') . "n";
wp_mail($alert_settings['email'], $subject, $message);
}
// 发送Webhook通知
if (!empty($alert_settings['webhook_url'])) {
$payload = [
'log_id' => $log_id,
'error' => $error,
'timestamp' => time(),
'system' => 'wordpress_supply_chain'
];
wp_remote_post($alert_settings['webhook_url'], [
'body' => json_encode($payload),
'headers' => ['Content-Type' => 'application/json']
]);
}
}
}
// 使用监控系统
$monitor = SupplySyncMonitor::get_instance();
// 在同步开始时记录
$log_id = $monitor->log_sync_start('full_sync', 'mobile', [
'item_count' => count($products),
'user_agent' => $_SERVER['HTTP_USER_AGENT']
]);
try {
// 执行同步操作
$results = sync_products_data($request);
// 记录成功完成
$monitor->log_sync_complete($log_id, $results);
} catch (Exception $e) {
// 记录失败
$monitor->send_alert_on_failure($log_id, $e->getMessage());
throw $e;
}
?>
部署与维护
Docker部署配置
# docker-compose.yml - WordPress供应链系统
version: '3.8'
services:
wordpress:
image: wordpress:php8.0-apache
container_name: supply-chain-wp
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_USER: supply_user
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DB_NAME: supply_chain
WORDPRESS_DEBUG: 1
WORDPRESS_CONFIG_EXTRA: |
define('WP_CACHE', true);
define('SUPPLY_API_KEYS', '${API_KEYS}');
define('MOBILE_ENCRYPTION_KEY', '${MOBILE_KEY}');
define('DESKTOP_ENCRYPTION_KEY', '${DESKTOP_KEY}');
volumes:
- ./wordpress:/var/www/html
- ./plugins:/var/www/html/wp-content/plugins/supply-chain
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
depends_on:
- mysql
- redis
mysql:
image: mysql:8.0
container_name: supply-chain-db
environment:
MYSQL_DATABASE: supply_chain
MYSQL_USER: supply_user
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
volumes:
- mysql_data:/var/lib/mysql
- ./mysql-config.cnf:/etc/mysql/conf.d/config.cnf
redis:
image: redis:alpine
container_name: supply-chain-cache
command: redis-server --appendonly yes
volumes:
- redis_data:/data
websocket:
build: ./websocket-server
container_name: supply-websocket
ports:
- "3000:3000"
environment:
REDIS_URL: redis://redis:6379
WP_API_URL: http://wordpress
depends_on:
- redis
- wordpress
sync-worker:
build: ./sync-worker
container_name: supply-sync-worker
environment:
REDIS_URL: redis://redis:6379
DATABASE_URL: mysql://supply_user:${DB_PASSWORD}@mysql/supply_chain
depends_on:
- redis
- mysql
volumes:
- ./sync-logs:/app/logs
volumes:
mysql_data:
redis_data:
自动化测试脚本
// test/sync-api.test.js - API测试套件
const request = require('supertest');
const { createTestData, cleanupTestData } = require('./test-helpers');
describe('供应链同步API测试', () => {
const API_BASE = 'http://localhost:8080/wp-json/flexible-supply/v1';
const API_KEY = 'test-api-key-123';
beforeAll(async () => {
await createTestData();
});
afterAll(async () => {
await cleanupTestData();
});
test('GET /products 应返回产品列表', async () => {
const response = await request(API_BASE)
.get('/products')
.set('X-API-Key', API_KEY)
.expect('Content-Type', /json/)
.expect(200);
expect(response.body).toHaveProperty('data');
expect(response.body).toHaveProperty('pagination');
expect(Array.isArray(response.body.data)).toBe(true);
});
test('POST /products/sync 应处理数据同步', async () => {
const syncData = {
products: [
{
sku: 'TEST-001',
product_name: '测试产品',
current_stock: 100,
reorder_level: 20,
sync_version: 1
}
],
platform: 'mobile'
};
const response = await request(API_BASE)
.post('/products/sync')
.set('X-API-Key', API_KEY)
.set('Content-Type', 'application/json')
.send(syncData)
.expect(200);
expect(response.body).toHaveProperty('result');
expect(response.body.result).toHaveProperty('success');
expect(response.body.result.success).toContain('TEST-001');
});
test('同步应处理版本冲突', async () => {
// 先插入一个低版本
await request(API_BASE)
.post('/products/sync')
.set('X-API-Key', API_KEY)
.send({
products: [{
sku: 'CONFLICT-001',
product_name: '冲突测试',
current_stock: 50,
sync_version: 1
}]
});
// 尝试用相同版本同步
const response = await request(API_BASE)
.post('/products/sync')
.set('X-API-Key', API_KEY)
.send({
products: [{
sku: 'CONFLICT-001',
product_name: '更新后的名称',
current_stock: 30,
sync_version: 1 // 相同版本,应被忽略
}]
});
// 验证没有更新发生
const getResponse = await request(API_BASE)
.get('/products?sku=CONFLICT-001')
.set('X-API-Key', API_KEY);
expect(getResponse.body.data[0].product_name).toBe('冲突测试');
