文章目录
-
- 在现代生产管理中,实时了解生产进度对于提高效率和及时调整生产计划至关重要。本教程将指导您如何为WordPress创建一个定制插件,实现小批量生产进度的可视化展示。这个插件特别适合小型制造企业、手工作坊或任何需要跟踪多任务进度的场景。
- 我们的生产进度可视化插件将包含以下核心功能: 生产任务管理(创建、编辑、删除任务) 进度百分比跟踪 可视化进度展示(进度条、图表) 任务状态管理(未开始、进行中、已完成) 数据导出功能
- 首先,在WordPress的wp-content/plugins目录下创建一个新文件夹,命名为production-progress-tracker。在该文件夹中创建主插件文件production-progress-tracker.php: <?php /** * Plugin Name: 生产进度可视化追踪器 * Plugin URI: https://yourwebsite.com/ * Description: 一个小批量生产进度可视化追踪插件 * Version: 1.0.0 * Author: 您的名称 * License: GPL v2 or later * Text Domain: production-progress */ // 防止直接访问 if (!defined('ABSPATH')) { exit; } // 定义插件常量 define('PPT_VERSION', '1.0.0'); define('PPT_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('PPT_PLUGIN_URL', plugin_dir_url(__FILE__)); // 初始化插件 require_once PPT_PLUGIN_DIR . 'includes/class-production-progress.php'; function run_production_progress_tracker() { $plugin = new Production_Progress_Tracker(); $plugin->run(); } run_production_progress_tracker();
- 生产进度数据需要存储在数据库中。创建includes/class-database.php文件来管理数据库表: <?php /** * 数据库处理类 */ class PPT_Database { public function __construct() { // 构造函数 } /** * 创建必要的数据库表 */ public function create_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $table_name = $wpdb->prefix . 'production_tasks'; // 生产任务表SQL $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, task_name varchar(255) NOT NULL, description text, start_date date, due_date date, progress tinyint(3) DEFAULT 0, status varchar(50) DEFAULT 'pending', assigned_to varchar(255), created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } /** * 获取所有生产任务 */ public function get_all_tasks() { global $wpdb; $table_name = $wpdb->prefix . 'production_tasks'; return $wpdb->get_results( "SELECT * FROM $table_name ORDER BY created_at DESC" ); } /** * 添加新任务 */ public function add_task($data) { global $wpdb; $table_name = $wpdb->prefix . 'production_tasks'; $wpdb->insert( $table_name, $data ); return $wpdb->insert_id; } /** * 更新任务进度 */ public function update_progress($task_id, $progress) { global $wpdb; $table_name = $wpdb->prefix . 'production_tasks'; return $wpdb->update( $table_name, array('progress' => $progress), array('id' => $task_id) ); } }
- 创建admin/class-admin.php文件来构建WordPress后台管理界面: <?php /** * 管理界面类 */ class PPT_Admin { private $database; public function __construct($database) { $this->database = $database; add_action('admin_menu', array($this, 'add_admin_menu')); add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts')); } /** * 添加管理菜单 */ public function add_admin_menu() { add_menu_page( '生产进度追踪', // 页面标题 '生产进度', // 菜单标题 'manage_options', // 权限 'production-progress', // 菜单slug array($this, 'display_main_page'), // 回调函数 'dashicons-chart-area', // 图标 30 // 位置 ); add_submenu_page( 'production-progress', '添加新任务', '添加任务', 'manage_options', 'add-production-task', array($this, 'display_add_task_page') ); } /** * 加载管理界面脚本和样式 */ public function enqueue_admin_scripts($hook) { if (strpos($hook, 'production-progress') === false) { return; } // 加载Chart.js用于可视化 wp_enqueue_script( 'chart-js', 'https://cdn.jsdelivr.net/npm/chart.js', array(), '3.7.0', true ); // 加载自定义CSS wp_enqueue_style( 'ppt-admin-style', PPT_PLUGIN_URL . 'assets/css/admin-style.css', array(), PPT_VERSION ); // 加载自定义JS wp_enqueue_script( 'ppt-admin-script', PPT_PLUGIN_URL . 'assets/js/admin-script.js', array('jquery', 'chart-js'), PPT_VERSION, true ); } /** * 显示主页面 */ public function display_main_page() { $tasks = $this->database->get_all_tasks(); echo '<div class="wrap">'; echo '<h1>生产进度可视化面板</h1>'; // 进度概览 echo '<div class="ppt-overview">'; echo '<h2>生产进度概览</h2>'; echo '<canvas id="progressChart" width="400" height="200"></canvas>'; echo '</div>'; // 任务列表 echo '<div class="ppt-task-list">'; echo '<h2>生产任务列表</h2>'; if (empty($tasks)) { echo '<p>暂无生产任务。 <a href="admin.php?page=add-production-task">添加第一个任务</a></p>'; } else { echo '<table class="wp-list-table widefat fixed striped">'; echo '<thead><tr> <th>任务名称</th> <th>进度</th> <th>状态</th> <th>负责人</th> <th>截止日期</th> <th>操作</th> </tr></thead>'; echo '<tbody>'; foreach ($tasks as $task) { $status_class = ''; switch ($task->status) { case 'completed': $status_class = 'status-completed'; break; case 'in_progress': $status_class = 'status-in-progress'; break; default: $status_class = 'status-pending'; } echo '<tr>'; echo '<td>' . esc_html($task->task_name) . '</td>'; echo '<td> <div class="progress-container"> <div class="progress-bar" style="width: ' . esc_attr($task->progress) . '%;"> <span>' . esc_html($task->progress) . '%</span> </div> </div> </td>'; echo '<td><span class="status-badge ' . $status_class . '">' . esc_html($this->get_status_text($task->status)) . '</span></td>'; echo '<td>' . esc_html($task->assigned_to) . '</td>'; echo '<td>' . esc_html($task->due_date) . '</td>'; echo '<td> <button class="button button-small update-progress" data-task-id="' . esc_attr($task->id) . '">更新进度</button> <button class="button button-small delete-task" data-task-id="' . esc_attr($task->id) . '">删除</button> </td>'; echo '</tr>'; } echo '</tbody></table>'; } echo '</div>'; // 结束任务列表 // 添加JavaScript代码初始化图表 echo '<script> document.addEventListener("DOMContentLoaded", function() { var ctx = document.getElementById("progressChart").getContext("2d"); var progressChart = new Chart(ctx, { type: "bar", data: { labels: ' . json_encode(array_map(function($t) { return $t->task_name; }, $tasks)) . ', datasets: [{ label: "任务进度 (%)", data: ' . json_encode(array_map(function($t) { return $t->progress; }, $tasks)) . ', backgroundColor: [ "rgba(54, 162, 235, 0.5)", "rgba(255, 99, 132, 0.5)", "rgba(255, 206, 86, 0.5)", "rgba(75, 192, 192, 0.5)", "rgba(153, 102, 255, 0.5)" ], borderColor: [ "rgba(54, 162, 235, 1)", "rgba(255, 99, 132, 1)", "rgba(255, 206, 86, 1)", "rgba(75, 192, 192, 1)", "rgba(153, 102, 255, 1)" ], borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true, max: 100 } } } }); }); </script>'; echo '</div>'; // 结束wrap } /** * 显示添加任务页面 */ public function display_add_task_page() { echo '<div class="wrap">'; echo '<h1>添加新生产任务</h1>'; echo '<form method="post" action="' . admin_url('admin-post.php') . '">'; echo '<input type="hidden" name="action" value="ppt_add_task">'; wp_nonce_field('ppt_add_task_nonce', 'ppt_nonce'); echo '<table class="form-table"> <tr> <th><label for="task_name">任务名称</label></th> <td><input type="text" id="task_name" name="task_name" class="regular-text" required></td> </tr> <tr> <th><label for="description">任务描述</label></th> <td><textarea id="description" name="description" rows="4" class="large-text"></textarea></td> </tr> <tr> <th><label for="assigned_to">负责人</label></th> <td><input type="text" id="assigned_to" name="assigned_to" class="regular-text"></td> </tr> <tr> <th><label for="start_date">开始日期</label></th> <td><input type="date" id="start_date" name="start_date" class="regular-text"></td> </tr> <tr> <th><label for="due_date">截止日期</label></th> <td><input type="date" id="due_date" name="due_date" class="regular-text"></td> </tr> <tr> <th><label for="initial_progress">初始进度 (%)</label></th> <td><input type="number" id="initial_progress" name="initial_progress" min="0" max="100" value="0" class="small-text"></td> </tr> </table>'; echo '<p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="添加任务"></p>'; echo '</form>'; echo '</div>'; } /** * 获取状态文本 */ private function get_status_text($status) { $statuses = array( 'pending' => '未开始', 'in_progress' => '进行中', 'completed' => '已完成' ); return isset($statuses[$status]) ? $statuses[$status] : $status; } }
- 创建public/class-public.php文件,允许在前端显示生产进度: <?php /** * 前端显示类 */ class PPT_Public { private $database; public function __construct($database) { $this->database = $database; add_shortcode('production_progress', array($this, 'production_progress_shortcode')); add_action('wp_enqueue_scripts', array($this, 'enqueue_public_scripts')); } /** * 加载前端脚本和样式 */ public function enqueue_public_scripts() { wp_enqueue_style( 'ppt-public-style', PPT_PLUGIN_URL . 'assets/css/public-style.css', array(), PPT_VERSION ); } /** * 生产进度短代码 */ public function production_progress_shortcode($atts) { $atts = shortcode_atts(array( 'limit' => 10, 'show_chart' => true ), $atts, 'production_progress'); $tasks = $this->database->get_all_tasks(); $output = ''; if (empty($tasks)) { return '<p>暂无生产任务。</p>'; } $output .= '<div class="ppt-public-container">'; $output .= '<h3>生产进度追踪</h3>'; if ($atts['show_chart']) { $output .= '<div class="ppt-public-chart"> <canvas id="pptPublicChart" width="400" height="200"></canvas> </div>'; } $output .= '<div class="ppt-public-task-list">'; foreach ($tasks as $task) { $output .= '<div class="ppt-task-item">'; $output .= '<h4>' . esc_html($task->task_name) . '</h4>'; $output .= '<div class="progress-container"> <div class="progress-bar" style="width: ' . esc_attr($task->progress) . '%;"> <span>' . esc_html($task->progress) . '%</span> </div> </div>'; $output .= '<div class="task-meta"> <span class="task-assignee">负责人: ' . esc_html($task->assigned_to) . '</span> <span class="task-due">截止: ' . esc_html($task->due_date) . '</span> </div>'; $output .= '</div>'; } $output .= '</div>'; // 结束任务列表 $output .= '</div>'; // 结束容器 // 添加图表脚本 if ($atts['show_chart']) { $output .= '<script> document.addEventListener("DOMContentLoaded", function() { var ctx = document.getElementById("pptPublicChart").getContext("2d"); var chartData = { labels: ' . json_encode(array_map(function($t) { return $t->task_name; }, $tasks)) . ', datasets: [{ label: "进度 (%)", data: ' . json_encode(array_map(function($t) { return $t->progress; }, $tasks)) . ', backgroundColor: "rgba(54, 162, 235, 0.5)", borderColor: "rgba(54, 162, 235, 1)", borderWidth: 1 }] }; new Chart(ctx, { type: "bar", data: chartData, options: { responsive: true, scales: { y: { beginAtZero: true, max: 100 } } } }); }); </script>'; } return $output; } }
- 创建includes/class-production-progress.php文件作为插件主类: <?php /** * 主插件类 */ class Production_Progress_Tracker { private $database; private $admin; private $public; public function __construct() { $this->load_dependencies(); $this->init_hooks(); } /** * 加载依赖文件 */ private function load_dependencies() { require_once PPT_PLUGIN_DIR . 'includes/class-database.php'; require_once PPT_PLUGIN_DIR . 'admin/class-admin.php'; require_once PPT_PLUGIN_DIR . 'public/class-public.php'; } /** * 初始化钩子 */ private function init_hooks() { register_activation_hook(__FILE__, array($this, 'activate')); register_deactivation_hook(__FILE__, array($this, 'deactivate')); add_action('plugins_loaded', array($this, 'init_plugin')); } /** * 插件激活时执行 */ public function activate() { $this->database = new PPT_Database(); $this->database->create_tables(); update_option('ppt_version', PPT_VERSION); flush_rewrite_rules(); } /** * 插件停用时执行 */ public function deactivate() { flush_rewrite_rules(); } /** * 初始化插件 */ public function init_plugin() { $this->database = new PPT_Database(); $this->admin = new PPT_Admin($this->database); $this->public = new PPT_Public($this->database); $this->handle_form_submissions(); $this->add_ajax_handlers(); } /** * 处理表单提交 */ private function handle_form_submissions() { add_action('admin_post_ppt_add_task', array($this, 'handle_add_task')); add_action('admin_post_nopriv_ppt_add_task', array($this, 'handle_add_task')); } /** * 处理添加任务表单 */ public function handle_add_task() { // 验证nonce if (!isset($_POST['ppt_nonce']) || !wp_verify_nonce($_POST['ppt_nonce'], 'ppt_add_task_nonce')) { wp_die('安全验证失败'); } // 验证权限 if (!current_user_can('manage_options')) { wp_die('权限不足'); } // 准备任务数据 $task_data = array( 'task_name' => sanitize_text_field($_POST['task_name']), 'description' => sanitize_textarea_field($_POST['description']), 'assigned_to' => sanitize_text_field($_POST['assigned_to']), 'start_date' => sanitize_text_field($_POST['start_date']), 'due_date' => sanitize_text_field($_POST['due_date']), 'progress' => intval($_POST['initial_progress']), 'status' => intval($_POST['initial_progress']) > 0 ? 'in_progress' : 'pending' ); // 插入数据库 $task_id = $this->database->add_task($task_data); // 重定向回管理页面 if ($task_id) { wp_redirect(admin_url('admin.php?page=production-progress&message=success')); } else { wp_redirect(admin_url('admin.php?page=add-production-task&message=error')); } exit; } /** * 添加AJAX处理器 */ private function add_ajax_handlers() { add_action('wp_ajax_ppt_update_progress', array($this, 'ajax_update_progress')); add_action('wp_ajax_ppt_delete_task', array($this, 'ajax_delete_task')); add_action('wp_ajax_ppt_get_task_stats', array($this, 'ajax_get_task_stats')); } /** * AJAX更新进度 */ public function ajax_update_progress() { // 验证nonce check_ajax_referer('ppt_ajax_nonce', 'security'); // 验证权限 if (!current_user_can('manage_options')) { wp_die('权限不足'); } $task_id = intval($_POST['task_id']); $progress = intval($_POST['progress']); // 验证进度值 if ($progress < 0 || $progress > 100) { wp_send_json_error('进度值必须在0-100之间'); } // 更新进度 $result = $this->database->update_progress($task_id, $progress); if ($result) { // 如果进度为100%,自动标记为完成 if ($progress === 100) { global $wpdb; $table_name = $wpdb->prefix . 'production_tasks'; $wpdb->update( $table_name, array('status' => 'completed'), array('id' => $task_id) ); } wp_send_json_success('进度更新成功'); } else { wp_send_json_error('更新失败'); } } /** * AJAX删除任务 */ public function ajax_delete_task() { // 验证nonce check_ajax_referer('ppt_ajax_nonce', 'security'); // 验证权限 if (!current_user_can('manage_options')) { wp_die('权限不足'); } $task_id = intval($_POST['task_id']); global $wpdb; $table_name = $wpdb->prefix . 'production_tasks'; $result = $wpdb->delete($table_name, array('id' => $task_id)); if ($result) { wp_send_json_success('任务删除成功'); } else { wp_send_json_error('删除失败'); } } /** * AJAX获取任务统计 */ public function ajax_get_task_stats() { // 验证nonce check_ajax_referer('ppt_ajax_nonce', 'security'); $tasks = $this->database->get_all_tasks(); $stats = array( 'total' => count($tasks), 'completed' => 0, 'in_progress' => 0, 'pending' => 0, 'avg_progress' => 0 ); $total_progress = 0; foreach ($tasks as $task) { switch ($task->status) { case 'completed': $stats['completed']++; break; case 'in_progress': $stats['in_progress']++; break; default: $stats['pending']++; } $total_progress += $task->progress; } if ($stats['total'] > 0) { $stats['avg_progress'] = round($total_progress / $stats['total'], 2); } wp_send_json_success($stats); } /** * 运行插件 */ public function run() { // 主插件逻辑已通过钩子初始化 } }
- 创建assets/css/admin-style.css文件: /* 生产进度追踪器 - 管理界面样式 */ .ppt-overview { background: #fff; padding: 20px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } .ppt-task-list { background: #fff; padding: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } .progress-container { width: 100%; background-color: #f0f0f0; border-radius: 10px; overflow: hidden; height: 24px; position: relative; } .progress-bar { height: 100%; background: linear-gradient(90deg, #4CAF50, #8BC34A); border-radius: 10px; transition: width 0.3s ease; position: relative; } .progress-bar span { position: absolute; right: 5px; top: 50%; transform: translateY(-50%); color: #fff; font-size: 12px; font-weight: bold; text-shadow: 1px 1px 1px rgba(0,0,0,0.3); } .status-badge { display: inline-block; padding: 3px 8px; border-radius: 12px; font-size: 12px; font-weight: bold; } .status-pending { background-color: #ff9800; color: white; } .status-in-progress { background-color: #2196F3; color: white; } .status-completed { background-color: #4CAF50; color: white; } /* 模态框样式 */ .ppt-modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); } .ppt-modal-content { background-color: #fff; margin: 10% auto; padding: 20px; width: 80%; max-width: 500px; border-radius: 5px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .ppt-modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .ppt-modal-header h3 { margin: 0; } .ppt-close { font-size: 24px; cursor: pointer; color: #999; } .ppt-close:hover { color: #333; } .ppt-modal-body { margin-bottom: 20px; } .ppt-modal-footer { text-align: right; } 创建assets/css/public-style.css文件: /* 生产进度追踪器 - 前端样式 */ .ppt-public-container { max-width: 1200px; margin: 0 auto; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } .ppt-public-container h3 { color: #333; border-bottom: 2px solid #4CAF50; padding-bottom: 10px; margin-bottom: 20px; } .ppt-public-chart { background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 30px; } .ppt-public-task-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; } .ppt-task-item { background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); transition: transform 0.3s ease, box-shadow 0.3s ease; } .ppt-task-item:hover { transform: translateY(-5px); box-shadow: 0 4px 8px rgba(0,0,0,0.15); } .ppt-task-item h4 { margin-top: 0; color: #333; font-size: 18px; } .task-meta { display: flex; justify-content: space-between; margin-top: 15px; font-size: 14px; color: #666; } .task-assignee, .task-due { display: flex; align-items: center; } .task-assignee::before { content: "👤"; margin-right: 5px; } .task-due::before { content: "📅"; margin-right: 5px; } /* 响应式设计 */ @media (max-width: 768px) { .ppt-public-task-list { grid-template-columns: 1fr; } .task-meta { flex-direction: column; gap: 5px; } }
- 创建assets/js/admin-script.js文件: /** * 生产进度追踪器 - 管理界面脚本 */ jQuery(document).ready(function($) { // 更新进度按钮点击事件 $(document).on('click', '.update-progress', function(e) { e.preventDefault(); var taskId = $(this).data('task-id'); var currentProgress = $(this).closest('tr').find('.progress-bar').width() / $(this).closest('tr').find('.progress-container').width() * 100; // 显示模态框 showProgressModal(taskId, Math.round(currentProgress)); }); // 删除任务按钮点击事件 $(document).on('click', '.delete-task', function(e) { e.preventDefault(); if (!confirm('确定要删除这个任务吗?此操作不可撤销。')) { return; } var taskId = $(this).data('task-id'); var button = $(this); $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'ppt_delete_task', task_id: taskId, security: ppt_ajax.nonce }, beforeSend: function() { button.text('删除中...').prop('disabled', true); }, success: function(response) { if (response.success) { button.closest('tr').fadeOut(300, function() { $(this).remove(); showNotification('任务删除成功', 'success'); }); } else { showNotification(response.data, 'error'); button.text('删除').prop('disabled', false); } }, error: function() { showNotification('请求失败,请重试', 'error'); button.text('删除').prop('disabled', false); } }); }); // 显示进度更新模态框 function showProgressModal(taskId, currentProgress) { var modalHtml = ` <div id="pptProgressModal" class="ppt-modal"> <div class="ppt-modal-content"> <div class="ppt-modal-header"> <h3>更新任务进度</h3> <span class="ppt-close">×</span> </div> <div class="ppt-modal-body"> <p>当前进度: <span id="currentProgressValue">${currentProgress}</span>%</p> <input type="range" id="progressSlider" min="0" max="100" value="${currentProgress}" class="widefat"> <div style="display: flex; justify-content: space-between; margin-top: 5px;"> <span>0%</span> <span>100%</span> </div> </div> <div class="ppt-modal-footer"> <button type="button" class="button" id="pptCancelBtn">取消</button> <button type="button" class="button button-primary" id="pptUpdateBtn">更新</button> </div> </div> </div> `; $('body').append(modalHtml); var modal = $('#pptProgressModal'); modal.fadeIn(200); // 滑块值变化事件 $('#progressSlider').on('input', function() { $('#currentProgressValue').text($(this).val()); }); // 关闭模态框 $('.ppt-close, #pptCancelBtn').on('click', function() { modal.fadeOut(200, function() { $(this).remove(); }); }); // 点击模态框外部关闭 $(window).on('click', function(e) { if ($(e.target).is(modal)) { modal.fadeOut(200, function() { $(this).remove(); }); } }); // 更新按钮点击事件 $('#pptUpdateBtn').on('click', function() { var newProgress = $('#progressSlider').val(); updateTaskProgress(taskId, newProgress); }); } // 更新任务进度 function updateTaskProgress(taskId, progress) { $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'ppt_update_progress', task_id: taskId, progress: progress, security: ppt_ajax.nonce }, beforeSend: function() { $('#pptUpdateBtn').text('更新中...').prop('disabled', true); }, success: function(response) { if (response.success) { // 更新表格中的进度显示 var progressBar = $('button[data-task-id="' + taskId + '"]').closest('tr').find('.progress-bar'); progressBar.css('width', progress + '%').find('span').text(progress + '%'); // 更新状态徽章 if (progress == 100) { var statusBadge = progressBar.closest('tr').find('.status-badge'); statusBadge.removeClass('status-pending status-in-progress').addClass('status-completed').text('已完成'); } else if (progress > 0) { var statusBadge = progressBar.closest('tr').find('.status-badge'); statusBadge.removeClass('status-pending status-completed').addClass('status-in-progress').text('进行中'); } // 关闭模态框 $('#pptProgressModal').fadeOut(200, function() { $(this).remove(); }); showNotification('进度更新成功', 'success'); // 刷新图表 if (typeof progressChart !== 'undefined') { updateChartData(); } } else { showNotification(response.data, 'error'); $('#pptUpdateBtn').text('更新').prop('disabled', false); } }, error: function() { showNotification('请求失败,请重试', 'error'); $('#pptUpdateBtn').text('更新').prop('disabled', false); } }); } // 更新图表数据 function updateChartData() { $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'ppt_get_task_stats', security: ppt_ajax.nonce }, success: function(response) { if (response.success) { // 这里可以更新图表数据 console.log('统计数据:', response.data); } } }); } // 显示通知 function showNotification(message, type) { var notification = $('<div class="notice notice-' + type + ' is-dismissible"><p>' + message + '</p></div>'); $('.wrap h1').after(notification);
在现代生产管理中,实时了解生产进度对于提高效率和及时调整生产计划至关重要。本教程将指导您如何为WordPress创建一个定制插件,实现小批量生产进度的可视化展示。这个插件特别适合小型制造企业、手工作坊或任何需要跟踪多任务进度的场景。
我们的生产进度可视化插件将包含以下核心功能:
- 生产任务管理(创建、编辑、删除任务)
- 进度百分比跟踪
- 可视化进度展示(进度条、图表)
- 任务状态管理(未开始、进行中、已完成)
- 数据导出功能
首先,在WordPress的wp-content/plugins目录下创建一个新文件夹,命名为production-progress-tracker。在该文件夹中创建主插件文件production-progress-tracker.php:
<?php
/**
* Plugin Name: 生产进度可视化追踪器
* Plugin URI: https://yourwebsite.com/
* Description: 一个小批量生产进度可视化追踪插件
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
* Text Domain: production-progress
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('PPT_VERSION', '1.0.0');
define('PPT_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('PPT_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
require_once PPT_PLUGIN_DIR . 'includes/class-production-progress.php';
function run_production_progress_tracker() {
$plugin = new Production_Progress_Tracker();
$plugin->run();
}
run_production_progress_tracker();
生产进度数据需要存储在数据库中。创建includes/class-database.php文件来管理数据库表:
<?php
/**
* 数据库处理类
*/
class PPT_Database {
public function __construct() {
// 构造函数
}
/**
* 创建必要的数据库表
*/
public function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'production_tasks';
// 生产任务表SQL
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
task_name varchar(255) NOT NULL,
description text,
start_date date,
due_date date,
progress tinyint(3) DEFAULT 0,
status varchar(50) DEFAULT 'pending',
assigned_to varchar(255),
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
/**
* 获取所有生产任务
*/
public function get_all_tasks() {
global $wpdb;
$table_name = $wpdb->prefix . 'production_tasks';
return $wpdb->get_results(
"SELECT * FROM $table_name ORDER BY created_at DESC"
);
}
/**
* 添加新任务
*/
public function add_task($data) {
global $wpdb;
$table_name = $wpdb->prefix . 'production_tasks';
$wpdb->insert(
$table_name,
$data
);
return $wpdb->insert_id;
}
/**
* 更新任务进度
*/
public function update_progress($task_id, $progress) {
global $wpdb;
$table_name = $wpdb->prefix . 'production_tasks';
return $wpdb->update(
$table_name,
array('progress' => $progress),
array('id' => $task_id)
);
}
}
创建admin/class-admin.php文件来构建WordPress后台管理界面:
<?php
/**
* 管理界面类
*/
class PPT_Admin {
private $database;
public function __construct($database) {
$this->database = $database;
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
}
/**
* 添加管理菜单
*/
public function add_admin_menu() {
add_menu_page(
'生产进度追踪', // 页面标题
'生产进度', // 菜单标题
'manage_options', // 权限
'production-progress', // 菜单slug
array($this, 'display_main_page'), // 回调函数
'dashicons-chart-area', // 图标
30 // 位置
);
add_submenu_page(
'production-progress',
'添加新任务',
'添加任务',
'manage_options',
'add-production-task',
array($this, 'display_add_task_page')
);
}
/**
* 加载管理界面脚本和样式
*/
public function enqueue_admin_scripts($hook) {
if (strpos($hook, 'production-progress') === false) {
return;
}
// 加载Chart.js用于可视化
wp_enqueue_script(
'chart-js',
'https://cdn.jsdelivr.net/npm/chart.js',
array(),
'3.7.0',
true
);
// 加载自定义CSS
wp_enqueue_style(
'ppt-admin-style',
PPT_PLUGIN_URL . 'assets/css/admin-style.css',
array(),
PPT_VERSION
);
// 加载自定义JS
wp_enqueue_script(
'ppt-admin-script',
PPT_PLUGIN_URL . 'assets/js/admin-script.js',
array('jquery', 'chart-js'),
PPT_VERSION,
true
);
}
/**
* 显示主页面
*/
public function display_main_page() {
$tasks = $this->database->get_all_tasks();
echo '<div class="wrap">';
echo '<h1>生产进度可视化面板</h1>';
// 进度概览
echo '<div class="ppt-overview">';
echo '<h2>生产进度概览</h2>';
echo '<canvas id="progressChart" width="400" height="200"></canvas>';
echo '</div>';
// 任务列表
echo '<div class="ppt-task-list">';
echo '<h2>生产任务列表</h2>';
if (empty($tasks)) {
echo '<p>暂无生产任务。 <a href="admin.php?page=add-production-task">添加第一个任务</a></p>';
} else {
echo '<table class="wp-list-table widefat fixed striped">';
echo '<thead><tr>
<th>任务名称</th>
<th>进度</th>
<th>状态</th>
<th>负责人</th>
<th>截止日期</th>
<th>操作</th>
</tr></thead>';
echo '<tbody>';
foreach ($tasks as $task) {
$status_class = '';
switch ($task->status) {
case 'completed':
$status_class = 'status-completed';
break;
case 'in_progress':
$status_class = 'status-in-progress';
break;
default:
$status_class = 'status-pending';
}
echo '<tr>';
echo '<td>' . esc_html($task->task_name) . '</td>';
echo '<td>
<div class="progress-container">
<div class="progress-bar" style="width: ' . esc_attr($task->progress) . '%;">
<span>' . esc_html($task->progress) . '%</span>
</div>
</div>
</td>';
echo '<td><span class="status-badge ' . $status_class . '">' . esc_html($this->get_status_text($task->status)) . '</span></td>';
echo '<td>' . esc_html($task->assigned_to) . '</td>';
echo '<td>' . esc_html($task->due_date) . '</td>';
echo '<td>
<button class="button button-small update-progress" data-task-id="' . esc_attr($task->id) . '">更新进度</button>
<button class="button button-small delete-task" data-task-id="' . esc_attr($task->id) . '">删除</button>
</td>';
echo '</tr>';
}
echo '</tbody></table>';
}
echo '</div>'; // 结束任务列表
// 添加JavaScript代码初始化图表
echo '<script>
document.addEventListener("DOMContentLoaded", function() {
var ctx = document.getElementById("progressChart").getContext("2d");
var progressChart = new Chart(ctx, {
type: "bar",
data: {
labels: ' . json_encode(array_map(function($t) { return $t->task_name; }, $tasks)) . ',
datasets: [{
label: "任务进度 (%)",
data: ' . json_encode(array_map(function($t) { return $t->progress; }, $tasks)) . ',
backgroundColor: [
"rgba(54, 162, 235, 0.5)",
"rgba(255, 99, 132, 0.5)",
"rgba(255, 206, 86, 0.5)",
"rgba(75, 192, 192, 0.5)",
"rgba(153, 102, 255, 0.5)"
],
borderColor: [
"rgba(54, 162, 235, 1)",
"rgba(255, 99, 132, 1)",
"rgba(255, 206, 86, 1)",
"rgba(75, 192, 192, 1)",
"rgba(153, 102, 255, 1)"
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true,
max: 100
}
}
}
});
});
</script>';
echo '</div>'; // 结束wrap
}
/**
* 显示添加任务页面
*/
public function display_add_task_page() {
echo '<div class="wrap">';
echo '<h1>添加新生产任务</h1>';
echo '<form method="post" action="' . admin_url('admin-post.php') . '">';
echo '<input type="hidden" name="action" value="ppt_add_task">';
wp_nonce_field('ppt_add_task_nonce', 'ppt_nonce');
echo '<table class="form-table">
<tr>
<th><label for="task_name">任务名称</label></th>
<td><input type="text" id="task_name" name="task_name" class="regular-text" required></td>
</tr>
<tr>
<th><label for="description">任务描述</label></th>
<td><textarea id="description" name="description" rows="4" class="large-text"></textarea></td>
</tr>
<tr>
<th><label for="assigned_to">负责人</label></th>
<td><input type="text" id="assigned_to" name="assigned_to" class="regular-text"></td>
</tr>
<tr>
<th><label for="start_date">开始日期</label></th>
<td><input type="date" id="start_date" name="start_date" class="regular-text"></td>
</tr>
<tr>
<th><label for="due_date">截止日期</label></th>
<td><input type="date" id="due_date" name="due_date" class="regular-text"></td>
</tr>
<tr>
<th><label for="initial_progress">初始进度 (%)</label></th>
<td><input type="number" id="initial_progress" name="initial_progress" min="0" max="100" value="0" class="small-text"></td>
</tr>
</table>';
echo '<p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="添加任务"></p>';
echo '</form>';
echo '</div>';
}
/**
* 获取状态文本
*/
private function get_status_text($status) {
$statuses = array(
'pending' => '未开始',
'in_progress' => '进行中',
'completed' => '已完成'
);
return isset($statuses[$status]) ? $statuses[$status] : $status;
}
}
创建public/class-public.php文件,允许在前端显示生产进度:
<?php
/**
* 前端显示类
*/
class PPT_Public {
private $database;
public function __construct($database) {
$this->database = $database;
add_shortcode('production_progress', array($this, 'production_progress_shortcode'));
add_action('wp_enqueue_scripts', array($this, 'enqueue_public_scripts'));
}
/**
* 加载前端脚本和样式
*/
public function enqueue_public_scripts() {
wp_enqueue_style(
'ppt-public-style',
PPT_PLUGIN_URL . 'assets/css/public-style.css',
array(),
PPT_VERSION
);
}
/**
* 生产进度短代码
*/
public function production_progress_shortcode($atts) {
$atts = shortcode_atts(array(
'limit' => 10,
'show_chart' => true
), $atts, 'production_progress');
$tasks = $this->database->get_all_tasks();
$output = '';
if (empty($tasks)) {
return '<p>暂无生产任务。</p>';
}
$output .= '<div class="ppt-public-container">';
$output .= '<h3>生产进度追踪</h3>';
if ($atts['show_chart']) {
$output .= '<div class="ppt-public-chart">
<canvas id="pptPublicChart" width="400" height="200"></canvas>
</div>';
}
$output .= '<div class="ppt-public-task-list">';
foreach ($tasks as $task) {
$output .= '<div class="ppt-task-item">';
$output .= '<h4>' . esc_html($task->task_name) . '</h4>';
$output .= '<div class="progress-container">
<div class="progress-bar" style="width: ' . esc_attr($task->progress) . '%;">
<span>' . esc_html($task->progress) . '%</span>
</div>
</div>';
$output .= '<div class="task-meta">
<span class="task-assignee">负责人: ' . esc_html($task->assigned_to) . '</span>
<span class="task-due">截止: ' . esc_html($task->due_date) . '</span>
</div>';
$output .= '</div>';
}
$output .= '</div>'; // 结束任务列表
$output .= '</div>'; // 结束容器
// 添加图表脚本
if ($atts['show_chart']) {
$output .= '<script>
document.addEventListener("DOMContentLoaded", function() {
var ctx = document.getElementById("pptPublicChart").getContext("2d");
var chartData = {
labels: ' . json_encode(array_map(function($t) { return $t->task_name; }, $tasks)) . ',
datasets: [{
label: "进度 (%)",
data: ' . json_encode(array_map(function($t) { return $t->progress; }, $tasks)) . ',
backgroundColor: "rgba(54, 162, 235, 0.5)",
borderColor: "rgba(54, 162, 235, 1)",
borderWidth: 1
}]
};
new Chart(ctx, {
type: "bar",
data: chartData,
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
max: 100
}
}
}
});
});
</script>';
}
return $output;
}
}
创建includes/class-production-progress.php文件作为插件主类:
<?php
/**
* 主插件类
*/
class Production_Progress_Tracker {
private $database;
private $admin;
private $public;
public function __construct() {
$this->load_dependencies();
$this->init_hooks();
}
/**
* 加载依赖文件
*/
private function load_dependencies() {
require_once PPT_PLUGIN_DIR . 'includes/class-database.php';
require_once PPT_PLUGIN_DIR . 'admin/class-admin.php';
require_once PPT_PLUGIN_DIR . 'public/class-public.php';
}
/**
* 初始化钩子
*/
private function init_hooks() {
register_activation_hook(__FILE__, array($this, 'activate'));
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
add_action('plugins_loaded', array($this, 'init_plugin'));
}
/**
* 插件激活时执行
*/
public function activate() {
$this->database = new PPT_Database();
$this->database->create_tables();
update_option('ppt_version', PPT_VERSION);
flush_rewrite_rules();
}
/**
* 插件停用时执行
*/
public function deactivate() {
flush_rewrite_rules();
}
/**
* 初始化插件
*/
public function init_plugin() {
$this->database = new PPT_Database();
$this->admin = new PPT_Admin($this->database);
$this->public = new PPT_Public($this->database);
$this->handle_form_submissions();
$this->add_ajax_handlers();
}
/**
* 处理表单提交
*/
private function handle_form_submissions() {
add_action('admin_post_ppt_add_task', array($this, 'handle_add_task'));
add_action('admin_post_nopriv_ppt_add_task', array($this, 'handle_add_task'));
}
/**
* 处理添加任务表单
*/
public function handle_add_task() {
// 验证nonce
if (!isset($_POST['ppt_nonce']) || !wp_verify_nonce($_POST['ppt_nonce'], 'ppt_add_task_nonce')) {
wp_die('安全验证失败');
}
// 验证权限
if (!current_user_can('manage_options')) {
wp_die('权限不足');
}
// 准备任务数据
$task_data = array(
'task_name' => sanitize_text_field($_POST['task_name']),
'description' => sanitize_textarea_field($_POST['description']),
'assigned_to' => sanitize_text_field($_POST['assigned_to']),
'start_date' => sanitize_text_field($_POST['start_date']),
'due_date' => sanitize_text_field($_POST['due_date']),
'progress' => intval($_POST['initial_progress']),
'status' => intval($_POST['initial_progress']) > 0 ? 'in_progress' : 'pending'
);
// 插入数据库
$task_id = $this->database->add_task($task_data);
// 重定向回管理页面
if ($task_id) {
wp_redirect(admin_url('admin.php?page=production-progress&message=success'));
} else {
wp_redirect(admin_url('admin.php?page=add-production-task&message=error'));
}
exit;
}
/**
* 添加AJAX处理器
*/
private function add_ajax_handlers() {
add_action('wp_ajax_ppt_update_progress', array($this, 'ajax_update_progress'));
add_action('wp_ajax_ppt_delete_task', array($this, 'ajax_delete_task'));
add_action('wp_ajax_ppt_get_task_stats', array($this, 'ajax_get_task_stats'));
}
/**
* AJAX更新进度
*/
public function ajax_update_progress() {
// 验证nonce
check_ajax_referer('ppt_ajax_nonce', 'security');
// 验证权限
if (!current_user_can('manage_options')) {
wp_die('权限不足');
}
$task_id = intval($_POST['task_id']);
$progress = intval($_POST['progress']);
// 验证进度值
if ($progress < 0 || $progress > 100) {
wp_send_json_error('进度值必须在0-100之间');
}
// 更新进度
$result = $this->database->update_progress($task_id, $progress);
if ($result) {
// 如果进度为100%,自动标记为完成
if ($progress === 100) {
global $wpdb;
$table_name = $wpdb->prefix . 'production_tasks';
$wpdb->update(
$table_name,
array('status' => 'completed'),
array('id' => $task_id)
);
}
wp_send_json_success('进度更新成功');
} else {
wp_send_json_error('更新失败');
}
}
/**
* AJAX删除任务
*/
public function ajax_delete_task() {
// 验证nonce
check_ajax_referer('ppt_ajax_nonce', 'security');
// 验证权限
if (!current_user_can('manage_options')) {
wp_die('权限不足');
}
$task_id = intval($_POST['task_id']);
global $wpdb;
$table_name = $wpdb->prefix . 'production_tasks';
$result = $wpdb->delete($table_name, array('id' => $task_id));
if ($result) {
wp_send_json_success('任务删除成功');
} else {
wp_send_json_error('删除失败');
}
}
/**
* AJAX获取任务统计
*/
public function ajax_get_task_stats() {
// 验证nonce
check_ajax_referer('ppt_ajax_nonce', 'security');
$tasks = $this->database->get_all_tasks();
$stats = array(
'total' => count($tasks),
'completed' => 0,
'in_progress' => 0,
'pending' => 0,
'avg_progress' => 0
);
$total_progress = 0;
foreach ($tasks as $task) {
switch ($task->status) {
case 'completed':
$stats['completed']++;
break;
case 'in_progress':
$stats['in_progress']++;
break;
default:
$stats['pending']++;
}
$total_progress += $task->progress;
}
if ($stats['total'] > 0) {
$stats['avg_progress'] = round($total_progress / $stats['total'], 2);
}
wp_send_json_success($stats);
}
/**
* 运行插件
*/
public function run() {
// 主插件逻辑已通过钩子初始化
}
}
创建assets/css/admin-style.css文件:
/* 生产进度追踪器 - 管理界面样式 */
.ppt-overview {
background: #fff;
padding: 20px;
margin-bottom: 20px;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.ppt-task-list {
background: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.progress-container {
width: 100%;
background-color: #f0f0f0;
border-radius: 10px;
overflow: hidden;
height: 24px;
position: relative;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #4CAF50, #8BC34A);
border-radius: 10px;
transition: width 0.3s ease;
position: relative;
}
.progress-bar span {
position: absolute;
right: 5px;
top: 50%;
transform: translateY(-50%);
color: #fff;
font-size: 12px;
font-weight: bold;
text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
}
.status-badge {
display: inline-block;
padding: 3px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
}
.status-pending {
background-color: #ff9800;
color: white;
}
.status-in-progress {
background-color: #2196F3;
color: white;
}
.status-completed {
background-color: #4CAF50;
color: white;
}
/* 模态框样式 */
.ppt-modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
}
.ppt-modal-content {
background-color: #fff;
margin: 10% auto;
padding: 20px;
width: 80%;
max-width: 500px;
border-radius: 5px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.ppt-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.ppt-modal-header h3 {
margin: 0;
}
.ppt-close {
font-size: 24px;
cursor: pointer;
color: #999;
}
.ppt-close:hover {
color: #333;
}
.ppt-modal-body {
margin-bottom: 20px;
}
.ppt-modal-footer {
text-align: right;
}
创建assets/css/public-style.css文件:
/* 生产进度追踪器 - 前端样式 */
.ppt-public-container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}
.ppt-public-container h3 {
color: #333;
border-bottom: 2px solid #4CAF50;
padding-bottom: 10px;
margin-bottom: 20px;
}
.ppt-public-chart {
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-bottom: 30px;
}
.ppt-public-task-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.ppt-task-item {
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.ppt-task-item:hover {
transform: translateY(-5px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.ppt-task-item h4 {
margin-top: 0;
color: #333;
font-size: 18px;
}
.task-meta {
display: flex;
justify-content: space-between;
margin-top: 15px;
font-size: 14px;
color: #666;
}
.task-assignee, .task-due {
display: flex;
align-items: center;
}
.task-assignee::before {
content: "👤";
margin-right: 5px;
}
.task-due::before {
content: "📅";
margin-right: 5px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.ppt-public-task-list {
grid-template-columns: 1fr;
}
.task-meta {
flex-direction: column;
gap: 5px;
}
}
创建assets/js/admin-script.js文件:
/**
* 生产进度追踪器 - 管理界面脚本
*/
jQuery(document).ready(function($) {
// 更新进度按钮点击事件
$(document).on('click', '.update-progress', function(e) {
e.preventDefault();
var taskId = $(this).data('task-id');
var currentProgress = $(this).closest('tr').find('.progress-bar').width() / $(this).closest('tr').find('.progress-container').width() * 100;
// 显示模态框
showProgressModal(taskId, Math.round(currentProgress));
});
// 删除任务按钮点击事件
$(document).on('click', '.delete-task', function(e) {
e.preventDefault();
if (!confirm('确定要删除这个任务吗?此操作不可撤销。')) {
return;
}
var taskId = $(this).data('task-id');
var button = $(this);
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'ppt_delete_task',
task_id: taskId,
security: ppt_ajax.nonce
},
beforeSend: function() {
button.text('删除中...').prop('disabled', true);
},
success: function(response) {
if (response.success) {
button.closest('tr').fadeOut(300, function() {
$(this).remove();
showNotification('任务删除成功', 'success');
});
} else {
showNotification(response.data, 'error');
button.text('删除').prop('disabled', false);
}
},
error: function() {
showNotification('请求失败,请重试', 'error');
button.text('删除').prop('disabled', false);
}
});
});
// 显示进度更新模态框
function showProgressModal(taskId, currentProgress) {
var modalHtml = `
<div id="pptProgressModal" class="ppt-modal">
<div class="ppt-modal-content">
<div class="ppt-modal-header">
<h3>更新任务进度</h3>
<span class="ppt-close">×</span>
</div>
<div class="ppt-modal-body">
<p>当前进度: <span id="currentProgressValue">${currentProgress}</span>%</p>
<input type="range" id="progressSlider" min="0" max="100" value="${currentProgress}" class="widefat">
<div style="display: flex; justify-content: space-between; margin-top: 5px;">
<span>0%</span>
<span>100%</span>
</div>
</div>
<div class="ppt-modal-footer">
<button type="button" class="button" id="pptCancelBtn">取消</button>
<button type="button" class="button button-primary" id="pptUpdateBtn">更新</button>
</div>
</div>
</div>
`;
$('body').append(modalHtml);
var modal = $('#pptProgressModal');
modal.fadeIn(200);
// 滑块值变化事件
$('#progressSlider').on('input', function() {
$('#currentProgressValue').text($(this).val());
});
// 关闭模态框
$('.ppt-close, #pptCancelBtn').on('click', function() {
modal.fadeOut(200, function() {
$(this).remove();
});
});
// 点击模态框外部关闭
$(window).on('click', function(e) {
if ($(e.target).is(modal)) {
modal.fadeOut(200, function() {
$(this).remove();
});
}
});
// 更新按钮点击事件
$('#pptUpdateBtn').on('click', function() {
var newProgress = $('#progressSlider').val();
updateTaskProgress(taskId, newProgress);
});
}
// 更新任务进度
function updateTaskProgress(taskId, progress) {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'ppt_update_progress',
task_id: taskId,
progress: progress,
security: ppt_ajax.nonce
},
beforeSend: function() {
$('#pptUpdateBtn').text('更新中...').prop('disabled', true);
},
success: function(response) {
if (response.success) {
// 更新表格中的进度显示
var progressBar = $('button[data-task-id="' + taskId + '"]').closest('tr').find('.progress-bar');
progressBar.css('width', progress + '%').find('span').text(progress + '%');
// 更新状态徽章
if (progress == 100) {
var statusBadge = progressBar.closest('tr').find('.status-badge');
statusBadge.removeClass('status-pending status-in-progress').addClass('status-completed').text('已完成');
} else if (progress > 0) {
var statusBadge = progressBar.closest('tr').find('.status-badge');
statusBadge.removeClass('status-pending status-completed').addClass('status-in-progress').text('进行中');
}
// 关闭模态框
$('#pptProgressModal').fadeOut(200, function() {
$(this).remove();
});
showNotification('进度更新成功', 'success');
// 刷新图表
if (typeof progressChart !== 'undefined') {
updateChartData();
}
} else {
showNotification(response.data, 'error');
$('#pptUpdateBtn').text('更新').prop('disabled', false);
}
},
error: function() {
showNotification('请求失败,请重试', 'error');
$('#pptUpdateBtn').text('更新').prop('disabled', false);
}
});
}
// 更新图表数据
function updateChartData() {
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'ppt_get_task_stats',
security: ppt_ajax.nonce
},
success: function(response) {
if (response.success) {
// 这里可以更新图表数据
console.log('统计数据:', response.data);
}
}
});
}
// 显示通知
function showNotification(message, type) {
var notification = $('<div class="notice notice-' + type + ' is-dismissible"><p>' + message + '</p></div>');
$('.wrap h1').after(notification);


