文章目录[隐藏]
WordPress小批量定制插件实现智能生产排程的详细教程
概述
在当今制造业数字化转型的浪潮中,智能生产排程系统成为提升生产效率的关键工具。对于中小型企业而言,直接购买大型ERP系统往往成本过高,而WordPress作为全球最流行的内容管理系统,通过定制插件的方式可以实现经济高效的智能生产排程解决方案。本教程将详细介绍如何开发一个WordPress插件,实现小批量生产的智能排程功能。
环境准备与插件基础结构
首先,我们需要创建一个标准的WordPress插件结构。在WordPress的wp-content/plugins/目录下创建新文件夹smart-production-scheduler。
<?php
/**
* Plugin Name: 智能生产排程系统
* Plugin URI: https://yourwebsite.com/
* Description: 为小批量生产定制的智能排程插件
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('SPS_VERSION', '1.0.0');
define('SPS_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('SPS_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
class SmartProductionScheduler {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->init_hooks();
}
private function init_hooks() {
// 激活/停用钩子
register_activation_hook(__FILE__, array($this, 'activate'));
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
// 管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 加载脚本和样式
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
// AJAX处理
add_action('wp_ajax_sps_process_schedule', array($this, 'process_schedule_ajax'));
}
public function activate() {
$this->create_tables();
$this->insert_default_data();
}
public function deactivate() {
// 清理临时数据
}
}
// 初始化插件
SmartProductionScheduler::get_instance();
?>
数据库设计与数据模型
智能排程系统需要存储订单、机器、工序等关键数据。我们在插件激活时创建必要的数据库表。
<?php
// 在SmartProductionScheduler类中添加以下方法
private function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 订单表
$orders_table = $wpdb->prefix . 'sps_orders';
$sql_orders = "CREATE TABLE IF NOT EXISTS $orders_table (
id INT(11) NOT NULL AUTO_INCREMENT,
order_number VARCHAR(50) NOT NULL,
product_name VARCHAR(255) NOT NULL,
quantity INT(11) NOT NULL,
priority TINYINT(1) DEFAULT 1 COMMENT '1-低, 2-中, 3-高',
due_date DATE NOT NULL,
status VARCHAR(20) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY order_number (order_number)
) $charset_collate;";
// 机器资源表
$machines_table = $wpdb->prefix . 'sps_machines';
$sql_machines = "CREATE TABLE IF NOT EXISTS $machines_table (
id INT(11) NOT NULL AUTO_INCREMENT,
machine_name VARCHAR(100) NOT NULL,
machine_type VARCHAR(50) NOT NULL,
capacity_per_hour INT(11) NOT NULL,
maintenance_schedule TEXT,
status VARCHAR(20) DEFAULT 'active',
PRIMARY KEY (id)
) $charset_collate;";
// 工序表
$processes_table = $wpdb->prefix . 'sps_processes';
$sql_processes = "CREATE TABLE IF NOT EXISTS $processes_table (
id INT(11) NOT NULL AUTO_INCREMENT,
order_id INT(11) NOT NULL,
process_name VARCHAR(100) NOT NULL,
machine_id INT(11) NOT NULL,
sequence INT(11) NOT NULL,
estimated_hours DECIMAL(5,2) NOT NULL,
actual_hours DECIMAL(5,2) DEFAULT NULL,
start_time DATETIME DEFAULT NULL,
end_time DATETIME DEFAULT NULL,
status VARCHAR(20) DEFAULT 'pending',
FOREIGN KEY (order_id) REFERENCES $orders_table(id) ON DELETE CASCADE,
FOREIGN KEY (machine_id) REFERENCES $machines_table(id),
PRIMARY KEY (id)
) $charset_collate;";
// 排程结果表
$schedules_table = $wpdb->prefix . 'sps_schedules';
$sql_schedules = "CREATE TABLE IF NOT EXISTS $schedules_table (
id INT(11) NOT NULL AUTO_INCREMENT,
schedule_date DATE NOT NULL,
machine_id INT(11) NOT NULL,
process_id INT(11) NOT NULL,
time_slot_start TIME NOT NULL,
time_slot_end TIME NOT NULL,
utilization_rate DECIMAL(5,2) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (machine_id) REFERENCES $machines_table(id),
FOREIGN KEY (process_id) REFERENCES $processes_table(id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql_orders);
dbDelta($sql_machines);
dbDelta($sql_processes);
dbDelta($sql_schedules);
}
private function insert_default_data() {
global $wpdb;
$machines_table = $wpdb->prefix . 'sps_machines';
// 插入默认机器数据
$default_machines = array(
array('machine_name' => 'CNC-01', 'machine_type' => 'cnc', 'capacity_per_hour' => 10),
array('machine_name' => '注塑机-01', 'machine_type' => 'injection', 'capacity_per_hour' => 15),
array('machine_name' => '装配线-01', 'machine_type' => 'assembly', 'capacity_per_hour' => 20),
);
foreach ($default_machines as $machine) {
$wpdb->insert($machines_table, $machine);
}
}
?>
智能排程算法实现
核心的排程算法采用基于优先规则和约束规划的启发式方法。
<?php
// 在SmartProductionScheduler类中添加排程算法
public function generate_schedule($start_date, $end_date) {
global $wpdb;
$orders_table = $wpdb->prefix . 'sps_orders';
$processes_table = $wpdb->prefix . 'sps_processes';
$machines_table = $wpdb->prefix . 'sps_machines';
$schedules_table = $wpdb->prefix . 'sps_schedules';
// 1. 获取待排程的订单和工序
$pending_orders = $wpdb->get_results("
SELECT o.*, p.id as process_id, p.process_name, p.machine_id,
p.sequence, p.estimated_hours, m.machine_name, m.capacity_per_hour
FROM $orders_table o
JOIN $processes_table p ON o.id = p.order_id
JOIN $machines_table m ON p.machine_id = m.id
WHERE o.status = 'pending' AND p.status = 'pending'
ORDER BY
o.priority DESC,
o.due_date ASC,
p.sequence ASC
");
// 2. 初始化时间槽(以30分钟为单位)
$time_slots = $this->generate_time_slots($start_date, $end_date);
// 3. 机器可用性映射
$machine_availability = array();
$machines = $wpdb->get_results("SELECT id FROM $machines_table WHERE status = 'active'");
foreach ($machines as $machine) {
$machine_availability[$machine->id] = $time_slots;
}
// 4. 智能排程算法
$schedule_results = array();
foreach ($pending_orders as $order_process) {
$machine_id = $order_process->machine_id;
$required_slots = ceil($order_process->estimated_hours * 2); // 转换为30分钟槽
// 寻找可用的连续时间槽
$allocated_slots = $this->find_available_slots(
$machine_availability[$machine_id],
$required_slots,
$order_process->priority
);
if (!empty($allocated_slots)) {
// 分配时间槽
foreach ($allocated_slots as $slot) {
$schedule_data = array(
'schedule_date' => $slot['date'],
'machine_id' => $machine_id,
'process_id' => $order_process->process_id,
'time_slot_start' => $slot['start_time'],
'time_slot_end' => $slot['end_time'],
'utilization_rate' => ($order_process->capacity_per_hour > 0) ?
min(100, ($order_process->estimated_hours / $required_slots * 50)) : 0
);
$wpdb->insert($schedules_table, $schedule_data);
// 更新机器可用性
$machine_availability[$machine_id] = array_filter(
$machine_availability[$machine_id],
function($s) use ($slot) {
return !($s['date'] == $slot['date'] &&
$s['start_time'] == $slot['start_time']);
}
);
}
// 更新工序状态
$wpdb->update($processes_table,
array('status' => 'scheduled'),
array('id' => $order_process->process_id)
);
$schedule_results[] = array(
'order' => $order_process->order_number,
'process' => $order_process->process_name,
'machine' => $order_process->machine_name,
'slots_allocated' => count($allocated_slots)
);
}
}
return $schedule_results;
}
/**
* 生成时间槽数组
* @param string $start_date 开始日期
* @param string $end_date 结束日期
* @return array 时间槽数组
*/
private function generate_time_slots($start_date, $end_date) {
$slots = array();
$current_date = new DateTime($start_date);
$end_date_obj = new DateTime($end_date);
// 工作时间:8:00-12:00, 13:00-17:00
$work_periods = array(
array('start' => '08:00:00', 'end' => '12:00:00'),
array('start' => '13:00:00', 'end' => '17:00:00')
);
while ($current_date <= $end_date_obj) {
$date_str = $current_date->format('Y-m-d');
foreach ($work_periods as $period) {
$start_time = new DateTime($date_str . ' ' . $period['start']);
$end_time = new DateTime($date_str . ' ' . $period['end']);
while ($start_time < $end_time) {
$slot_end = clone $start_time;
$slot_end->modify('+30 minutes');
if ($slot_end <= $end_time) {
$slots[] = array(
'date' => $date_str,
'start_time' => $start_time->format('H:i:s'),
'end_time' => $slot_end->format('H:i:s'),
'allocated' => false
);
}
$start_time->modify('+30 minutes');
}
}
$current_date->modify('+1 day');
}
return $slots;
}
/**
* 寻找可用时间槽
* @param array $available_slots 可用时间槽
* @param int $required_slots 所需时间槽数量
* @param int $priority 优先级
* @return array 分配的时间槽
*/
private function find_available_slots($available_slots, $required_slots, $priority) {
$allocated_slots = array();
$consecutive_count = 0;
// 根据优先级调整搜索策略
$max_gap = ($priority == 3) ? 0 : (($priority == 2) ? 1 : 2);
$current_gap = 0;
foreach ($available_slots as $slot) {
if (!$slot['allocated']) {
if ($consecutive_count == 0 ||
($this->is_consecutive_slot(end($allocated_slots), $slot) && $current_gap <= $max_gap)) {
$allocated_slots[] = $slot;
$consecutive_count++;
$current_gap = 0;
if ($consecutive_count >= $required_slots) {
return $allocated_slots;
}
} else {
$current_gap++;
if ($current_gap > $max_gap) {
// 重置搜索
$allocated_slots = array();
$consecutive_count = 0;
$current_gap = 0;
}
}
}
}
return array(); // 没有找到足够的连续时间槽
}
/**
* 检查时间槽是否连续
*/
private function is_consecutive_slot($prev_slot, $current_slot) {
if (!$prev_slot) return true;
if ($prev_slot['date'] == $current_slot['date']) {
$prev_end = new DateTime($prev_slot['date'] . ' ' . $prev_slot['end_time']);
$current_start = new DateTime($current_slot['date'] . ' ' . $current_slot['start_time']);
return $prev_end == $current_start;
}
return false;
}
?>
管理界面与可视化展示
创建用户友好的管理界面,展示排程结果。
<?php
// 在SmartProductionScheduler类中添加管理界面方法
public function add_admin_menu() {
add_menu_page(
'智能生产排程',
'生产排程',
'manage_options',
'smart-production-scheduler',
array($this, 'render_main_page'),
'dashicons-calendar-alt',
30
);
add_submenu_page(
'smart-production-scheduler',
'订单管理',
'订单管理',
'manage_options',
'sps-orders',
array($this, 'render_orders_page')
);
add_submenu_page(
'smart-production-scheduler',
'机器管理',
'机器管理',
'manage_options',
'sps-machines',
array($this, 'render_machines_page')
);
add_submenu_page(
'smart-production-scheduler',
'排程结果',
'排程结果',
'manage_options',
'sps-schedule',
array($this, 'render_schedule_page')
);
}
public function render_main_page() {
?>
<div class="wrap">
<h1>智能生产排程系统</h1>
<div class="sps-dashboard">
<div class="sps-card">
<h3>快速排程</h3>
<form method="post" action="<?php echo admin_url('admin-ajax.php'); ?>">
<input type="hidden" name="action" value="sps_process_schedule">
<?php wp_nonce_field('sps_schedule_nonce', 'sps_nonce'); ?>
<p>
<label>开始日期:</label>
<input type="date" name="start_date" value="<?php echo date('Y-m-d'); ?>" required>
</p>
<p>
<label>结束日期:</label>
<input type="date" name="end_date" value="<?php echo date('Y-m-d', strtotime('+7 days')); ?>" required>
</p>
<p>
<label>排程策略:</label>
<select name="strategy">
<option value="due_date">按交货期优先</option>
<option value="priority">按订单优先级</option>
<option value="balanced">平衡负载</option>
</select>
</p>
<p>
<button type="submit" class="button button-primary">生成排程</button>
</p>
</form>
</div>
<div class="sps-card">
<h3>今日生产概览</h3>
<div id="sps-today-overview">
<!-- 通过AJAX加载 -->
</div>
</div>
<div class="sps-card">
<h3>机器利用率</h3>
<canvas id="sps-utilization-chart" width="400" height="200"></canvas>
</div>
</div>
</div>
<style>
.sps-dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
margin-top: 20px;
}
.sps-card {
background: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.sps-card h3 {
margin-top: 0;
border-bottom: 2px solid #0073aa;
padding-bottom: 10px;
}
</style>
<script>
jQuery(document).ready(function($) {
// 加载今日概览
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'sps_get_today_overview'
},
success: function(response) {
$('#sps-today-overview').html(response);
}
});
// 排程表单提交
$('form').on('submit', function(e) {
e.preventDefault();
$.ajax({
url: ajaxurl,
type: 'POST',
data: $(this).serialize(),
beforeSend: function() {
$('button[type="submit"]').prop('disabled', true).text('排程中...');
},
success: function(response) {
alert('排程生成成功!');
location.reload();
},
error: function() {
alert('排程生成失败,请重试。');
$('button[type="submit"]').prop('disabled', false).text('生成排程');
}
});
});
});
</script>
<?php
}
public function render_schedule_page() {
global $wpdb;
$schedules_table = $wpdb->prefix . 'sps_schedules';
$machines_table = $wpdb->prefix . 'sps_machines';
$processes_table = $wpdb->prefix . 'sps_processes';
$orders_table = $wpdb->prefix . 'sps_orders';
// 获取排程数据
$schedules = $wpdb->get_results("
SELECT s.*, m.machine_name, p.process_name, o.order_number, o.product_name
FROM $schedules_table s
JOIN $machines_table m ON s.machine_id = m.id
JOIN $processes_table p ON s.process_id = p.id
JOIN $orders_table o ON p.order_id = o.id
WHERE s.schedule_date >= CURDATE()
ORDER BY s.schedule_date, s.time_slot_start, m.machine_name
");
// 按日期和机器分组
$grouped_schedules = array();
foreach ($schedules as $schedule) {
$date = $schedule->schedule_date;
$machine = $schedule->machine_name;
if (!isset($grouped_schedules[$date])) {
$grouped_schedules[$date] = array();
}
if (!isset($grouped_schedules[$date][$machine])) {
$grouped_schedules[$date][$machine] = array();
}
$grouped_schedules[$date][$machine][] = $schedule;
}
?>
<div class="wrap">
<h1>生产排程结果</h1>
<div class="sps-schedule-view">
<?php if (empty($grouped_schedules)): ?>
<p>暂无排程数据,请先生成排程。</p>
<?php else: ?>
<?php foreach ($grouped_schedules as $date => $machines): ?>
<div class="sps-date-section">
<h2><?php echo date('Y年m月d日', strtotime($date)); ?> (<?php echo date('D', strtotime($date)); ?>)</h2>
<?php foreach ($machines as $machine_name => $slots): ?>
<div class="sps-machine-schedule">
<h3><?php echo $machine_name; ?></h3>
<div class="sps-time-slots">
<?php foreach ($slots as $slot): ?>
<div class="sps-slot"
style="width: <?php echo $this->calculate_slot_width($slot->time_slot_start, $slot->time_slot_end); ?>%;
background-color: <?php echo $this->get_priority_color($slot->utilization_rate); ?>;">
<div class="sps-slot-content">
<strong><?php echo $slot->order_number; ?></strong><br>
<?php echo $slot->product_name; ?><br>
<?php echo substr($slot->time_slot_start, 0, 5); ?>-<?php echo substr($slot->time_slot_end, 0, 5); ?><br>
<small><?php echo $slot->process_name; ?></small>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<style>
.sps-schedule-view {
margin-top: 20px;
}
.sps-date-section {
background: #fff;
padding: 20px;
margin-bottom: 20px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.sps-machine-schedule {
margin: 15px 0;
padding: 10px;
border: 1px solid #ddd;
border-radius: 3px;
}
.sps-time-slots {
display: flex;
gap: 2px;
margin-top: 10px;
overflow-x: auto;
}
.sps-slot {
min-width: 120px;
padding: 8px;
border-radius: 3px;
color: #fff;
text-align: center;
font-size: 12px;
}
.sps-slot-content {
line-height: 1.3;
}
</style>
<?php
}
private function calculate_slot_width($start_time, $end_time) {
$start = strtotime($start_time);
$end = strtotime($end_time);
$duration = ($end - $start) / 3600; // 小时数
// 每个小时占10%宽度
return min(100, $duration * 10);
}
private function get_priority_color($utilization_rate) {
if ($utilization_rate >= 90) {
return '#e74c3c'; // 红色 - 高负荷
} elseif ($utilization_rate >= 70) {
return '#f39c12'; // 橙色 - 中等负荷
} else {
return '#2ecc71'; // 绿色 - 正常负荷
}
}
?>
AJAX处理与数据交互
实现前后端数据交互,提供实时更新功能。
<?php
// 在SmartProductionScheduler类中添加AJAX处理方法
public function process_schedule_ajax() {
// 验证nonce
if (!wp_verify_nonce($_POST['sps_nonce'], 'sps_schedule_nonce')) {
wp_die('安全验证失败');
}
// 验证权限
if (!current_user_can('manage_options')) {
wp_die('权限不足');
}
$start_date = sanitize_text_field($_POST['start_date']);
$end_date = sanitize_text_field($_POST['end_date']);
$strategy = sanitize_text_field($_POST['strategy']);
try {
// 根据策略调整排序
$this->apply_scheduling_strategy($strategy);
// 生成排程
$results = $this->generate_schedule($start_date, $end_date);
// 记录操作日志
$this->log_scheduling_action($start_date, $end_date, $strategy, count($results));
wp_send_json_success(array(
'message' => '排程生成成功',
'scheduled_count' => count($results),
'results' => $results
));
} catch (Exception $e) {
wp_send_json_error(array(
'message' => '排程生成失败: ' . $e->getMessage()
));
}
}
private function apply_scheduling_strategy($strategy) {
global $wpdb;
$orders_table = $wpdb->prefix . 'sps_orders';
switch ($strategy) {
case 'due_date':
// 按交货期排序(默认)
break;
case 'priority':
// 按优先级排序
$wpdb->query("ALTER TABLE $orders_table ORDER BY priority DESC, due_date ASC");
break;
case 'balanced':
// 平衡负载策略
$this->apply_balanced_strategy();
break;
}
}
private function apply_balanced_strategy() {
global $wpdb;
$orders_table = $wpdb->prefix . 'sps_orders';
$processes_table = $wpdb->prefix . 'sps_processes';
// 获取所有待排程订单
$orders = $wpdb->get_results("
SELECT o.*, SUM(p.estimated_hours) as total_hours
FROM $orders_table o
JOIN $processes_table p ON o.id = p.order_id
WHERE o.status = 'pending'
GROUP BY o.id
ORDER BY o.priority DESC, total_hours ASC
");
// 重新排序订单ID
$order_ids = array_map(function($order) {
return $order->id;
}, $orders);
// 更新订单排序(通过临时字段)
foreach ($order_ids as $index => $order_id) {
$wpdb->update($orders_table,
array('custom_order' => $index + 1),
array('id' => $order_id)
);
}
}
private function log_scheduling_action($start_date, $end_date, $strategy, $count) {
global $wpdb;
$logs_table = $wpdb->prefix . 'sps_logs';
// 创建日志表(如果不存在)
if ($wpdb->get_var("SHOW TABLES LIKE '$logs_table'") != $logs_table) {
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $logs_table (
id INT(11) NOT NULL AUTO_INCREMENT,
user_id INT(11) NOT NULL,
action_type VARCHAR(50) NOT NULL,
parameters TEXT,
result TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
// 记录日志
$wpdb->insert($logs_table, array(
'user_id' => get_current_user_id(),
'action_type' => 'schedule_generation',
'parameters' => json_encode(array(
'start_date' => $start_date,
'end_date' => $end_date,
'strategy' => $strategy
)),
'result' => json_encode(array(
'scheduled_count' => $count,
'timestamp' => current_time('mysql')
))
));
}
// 添加更多AJAX处理
add_action('wp_ajax_sps_get_today_overview', array($this, 'get_today_overview_ajax'));
public function get_today_overview_ajax() {
global $wpdb;
$schedules_table = $wpdb->prefix . 'sps_schedules';
$machines_table = $wpdb->prefix . 'sps_machines';
$today = date('Y-m-d');
// 获取今日排程统计
$stats = $wpdb->get_row("
SELECT
COUNT(DISTINCT s.machine_id) as active_machines,
COUNT(s.id) as total_slots,
AVG(s.utilization_rate) as avg_utilization
FROM $schedules_table s
WHERE s.schedule_date = '$today'
");
// 获取机器详情
$machines = $wpdb->get_results("
SELECT m.machine_name,
COUNT(s.id) as scheduled_slots,
AVG(s.utilization_rate) as machine_utilization
FROM $machines_table m
LEFT JOIN $schedules_table s ON m.id = s.machine_id AND s.schedule_date = '$today'
WHERE m.status = 'active'
GROUP BY m.id
");
ob_start();
?>
<div class="sps-overview-stats">
<p>活跃机器: <strong><?php echo $stats->active_machines ?? 0; ?></strong> 台</p>
<p>排程任务: <strong><?php echo $stats->total_slots ?? 0; ?></strong> 个</p>
<p>平均利用率: <strong><?php echo round($stats->avg_utilization ?? 0, 1); ?>%</strong></p>
</div>
<h4>机器状态</h4>
<ul>
<?php foreach ($machines as $machine): ?>
<li>
<?php echo $machine->machine_name; ?>:
<?php echo $machine->scheduled_slots; ?> 个任务,
利用率 <?php echo round($machine->machine_utilization, 1); ?>%
</li>
<?php endforeach; ?>
</ul>
<?php
wp_die();
}
?>
高级功能:约束优化与冲突解决
<?php
// 在SmartProductionScheduler类中添加高级功能
/**
* 优化现有排程,解决冲突
*/
public function optimize_schedule($schedule_ids = array()) {
global $wpdb;
$schedules_table = $wpdb->prefix . 'sps_schedules';
// 获取需要优化的排程
if (empty($schedule_ids)) {
$schedule_ids = $wpdb->get_col("
SELECT id FROM $schedules_table
WHERE schedule_date >= CURDATE()
ORDER BY schedule_date, time_slot_start
");
}
$optimizations = array();
foreach ($schedule_ids as $schedule_id) {
$schedule = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $schedules_table WHERE id = %d", $schedule_id
));
// 检查冲突
$conflicts = $this->detect_conflicts($schedule);
if (!empty($conflicts)) {
// 解决冲突
$resolution = $this->resolve_conflict($schedule, $conflicts);
if ($resolution['resolved']) {
// 更新排程
$wpdb->update($schedules_table,
array(
'time_slot_start' => $resolution['new_start'],
'time_slot_end' => $resolution['new_end']
),
array('id' => $schedule_id)
);
$optimizations[] = array(
'schedule_id' => $schedule_id,
'original' => $schedule->time_slot_start . '-' . $schedule->time_slot_end,
'optimized' => $resolution['new_start'] . '-' . $resolution['new_end'],
'reason' => $resolution['reason']
);
}
}
}
return $optimizations;
}
/**
* 检测排程冲突
*/
private function detect_conflicts($schedule) {
global $wpdb;
$schedules_table = $wpdb->prefix . 'sps_schedules';
$conflicts = $wpdb->get_results($wpdb->prepare("
SELECT s2.*
FROM $schedules_table s1
JOIN $schedules_table s2 ON s1.machine_id = s2.machine_id
AND s1.schedule_date = s2.schedule_date
AND s1.id != s2.id
WHERE s1.id = %d
AND (
(s1.time_slot_start < s2.time_slot_end AND s1.time_slot_end > s2.time_slot_start)
OR ABS(TIMESTAMPDIFF(MINUTE, s1.time_slot_start, s2.time_slot_start)) < 30
)
", $schedule->id));
return $conflicts;
}
/**
* 解决冲突
*/
private function resolve_conflict($schedule, $conflicts) {
global $wpdb;
$schedules_table = $wpdb->prefix . 'sps_schedules';
// 尝试将任务移动到相邻时间槽
$time_slots = $this->get_available_slots_for_machine(
$schedule->machine_id,
$schedule->schedule_date,
$schedule->id
);
$required_duration = strtotime($schedule->time_slot_end) - strtotime($schedule->time_slot_start);
foreach ($time_slots as $slot) {
$slot_duration = strtotime($slot['end']) - strtotime($slot['start']);
if ($slot_duration >= $required_duration) {
return array(
'resolved' => true,
'new_start' => $slot['start'],
'new_end' => date('H:i:s', strtotime($slot['start']) + $required_duration),
'reason' => '避免机器冲突'
);
}
}
// 如果无法解决,返回原始时间
return array(
'resolved' => false,
'reason' => '无可用时间槽'
);
}
/**
* 获取机器可用时间槽
*/
private function get_available_slots_for_machine($machine_id, $date, $exclude_schedule_id) {
global $wpdb;
$schedules_table = $wpdb->prefix . 'sps_schedules';
// 获取该机器当天的所有排程
$existing_schedules = $wpdb->get_results($wpdb->prepare("
SELECT time_slot_start, time_slot_end
FROM $schedules_table
WHERE machine_id = %d
AND schedule_date = %s
AND id != %d
ORDER BY time_slot_start
", $machine_id, $date, $exclude_schedule_id));


