文章目录
-
- 在当今数字化服务时代,企业需要一个灵活的售后服务体系来管理客户支持请求。本教程将带领您开发一个WordPress柔性售后服务管理插件,该系统将允许客户提交服务请求、跟踪处理状态,同时让管理员高效管理所有售后事务。 核心功能需求: 客户提交服务请求表单 请求状态跟踪(待处理、处理中、已解决、已关闭) 管理员后台管理界面 邮件通知系统 服务请求分类和优先级管理
- 首先,我们需要创建插件的基本文件结构。在WordPress的wp-content/plugins/目录下创建新文件夹flexible-after-sales。 创建主插件文件: <?php /** * Plugin Name: Flexible After Sales Service Manager * Plugin URI: https://yourwebsite.com/ * Description: 一个灵活的WordPress售后服务管理插件 * Version: 1.0.0 * Author: Your Name * License: GPL v2 or later * Text Domain: flexible-after-sales */ // 防止直接访问 if (!defined('ABSPATH')) { exit; } // 定义插件常量 define('FAS_VERSION', '1.0.0'); define('FAS_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('FAS_PLUGIN_URL', plugin_dir_url(__FILE__)); // 初始化插件 class FlexibleAfterSales { 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('init', array($this, 'init')); // 管理菜单 add_action('admin_menu', array($this, 'add_admin_menu')); // 加载文本域 add_action('plugins_loaded', array($this, 'load_textdomain')); } public function activate() { // 创建数据库表 $this->create_tables(); // 设置默认选项 $this->set_default_options(); // 刷新重写规则 flush_rewrite_rules(); } public function deactivate() { // 清理临时数据 delete_option('fas_flush_rewrite_rules'); // 刷新重写规则 flush_rewrite_rules(); } public function load_textdomain() { load_plugin_textdomain( 'flexible-after-sales', false, dirname(plugin_basename(__FILE__)) . '/languages' ); } public function init() { // 初始化代码将在后续步骤中添加 } public function add_admin_menu() { // 管理菜单代码将在后续步骤中添加 } private function create_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $table_name = $wpdb->prefix . 'fas_service_requests'; $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, customer_name varchar(100) NOT NULL, customer_email varchar(100) NOT NULL, product_name varchar(200) NOT NULL, issue_type varchar(50) NOT NULL, description text NOT NULL, priority tinyint(1) DEFAULT 2, status varchar(20) DEFAULT 'pending', assigned_to bigint(20) DEFAULT 0, 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); } private function set_default_options() { if (!get_option('fas_settings')) { $default_settings = array( 'email_notifications' => 1, 'default_priority' => 2, 'auto_assign' => 0, 'support_email' => get_option('admin_email') ); update_option('fas_settings', $default_settings); } } } // 启动插件 FlexibleAfterSales::get_instance(); ?>
- 创建服务请求管理类: <?php // 文件路径: includes/class-service-request.php if (!defined('ABSPATH')) { exit; } class FAS_Service_Request { private $db; private $table_name; public function __construct() { global $wpdb; $this->db = $wpdb; $this->table_name = $wpdb->prefix . 'fas_service_requests'; } /** * 创建新的服务请求 * @param array $data 请求数据 * @return int|false 插入ID或false */ public function create($data) { $defaults = array( 'customer_name' => '', 'customer_email' => '', 'product_name' => '', 'issue_type' => 'general', 'description' => '', 'priority' => 2, 'status' => 'pending', 'assigned_to' => 0 ); $data = wp_parse_args($data, $defaults); // 验证必要字段 if (empty($data['customer_name']) || empty($data['customer_email']) || empty($data['description'])) { return false; } // 插入数据 $result = $this->db->insert( $this->table_name, array( 'customer_name' => sanitize_text_field($data['customer_name']), 'customer_email' => sanitize_email($data['customer_email']), 'product_name' => sanitize_text_field($data['product_name']), 'issue_type' => sanitize_text_field($data['issue_type']), 'description' => wp_kses_post($data['description']), 'priority' => absint($data['priority']), 'status' => sanitize_text_field($data['status']), 'assigned_to' => absint($data['assigned_to']) ), array('%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d') ); if ($result) { $request_id = $this->db->insert_id; // 发送通知邮件 $this->send_notification_email($request_id, 'new_request'); return $request_id; } return false; } /** * 获取服务请求 * @param int $id 请求ID * @return object|null 请求对象或null */ public function get($id) { $query = $this->db->prepare( "SELECT * FROM {$this->table_name} WHERE id = %d", $id ); return $this->db->get_row($query); } /** * 更新服务请求 * @param int $id 请求ID * @param array $data 更新数据 * @return bool 是否成功 */ public function update($id, $data) { $allowed_fields = array( 'customer_name', 'customer_email', 'product_name', 'issue_type', 'description', 'priority', 'status', 'assigned_to' ); $update_data = array(); $format = array(); foreach ($data as $key => $value) { if (in_array($key, $allowed_fields)) { $update_data[$key] = $value; // 设置格式 if (in_array($key, array('priority', 'assigned_to'))) { $format[] = '%d'; } else { $format[] = '%s'; } } } if (empty($update_data)) { return false; } $result = $this->db->update( $this->table_name, $update_data, array('id' => $id), $format, array('%d') ); return $result !== false; } /** * 获取所有服务请求 * @param array $args 查询参数 * @return array 请求数组 */ public function get_all($args = array()) { $defaults = array( 'status' => '', 'priority' => 0, 'per_page' => 20, 'page' => 1, 'orderby' => 'created_at', 'order' => 'DESC' ); $args = wp_parse_args($args, $defaults); $where = array('1=1'); $values = array(); // 状态筛选 if (!empty($args['status'])) { $where[] = 'status = %s'; $values[] = $args['status']; } // 优先级筛选 if ($args['priority'] > 0) { $where[] = 'priority = %d'; $values[] = $args['priority']; } $where_clause = implode(' AND ', $where); // 分页计算 $offset = ($args['page'] - 1) * $args['per_page']; // 构建查询 $query = "SELECT * FROM {$this->table_name} WHERE {$where_clause}"; if (!empty($values)) { $query = $this->db->prepare($query, $values); } $query .= " ORDER BY {$args['orderby']} {$args['order']}"; $query .= " LIMIT {$args['per_page']} OFFSET {$offset}"; return $this->db->get_results($query); } /** * 发送通知邮件 * @param int $request_id 请求ID * @param string $type 邮件类型 */ private function send_notification_email($request_id, $type) { $settings = get_option('fas_settings'); if (!$settings['email_notifications']) { return; } $request = $this->get($request_id); if (!$request) { return; } $to = $settings['support_email']; $subject = ''; $message = ''; switch ($type) { case 'new_request': $subject = sprintf(__('新的服务请求 #%d', 'flexible-after-sales'), $request_id); $message = $this->get_email_template('new_request', $request); break; case 'status_update': $subject = sprintf(__('服务请求 #%d 状态更新', 'flexible-after-sales'), $request_id); $message = $this->get_email_template('status_update', $request); break; } if (!empty($subject) && !empty($message)) { wp_mail($to, $subject, $message, array('Content-Type: text/html; charset=UTF-8')); } } /** * 获取邮件模板 * @param string $template 模板名称 * @param object $request 请求对象 * @return string 邮件内容 */ private function get_email_template($template, $request) { ob_start(); include FAS_PLUGIN_DIR . 'templates/emails/' . $template . '.php'; return ob_get_clean(); } } ?>
- 创建服务请求提交表单: <?php // 文件路径: includes/class-frontend-form.php if (!defined('ABSPATH')) { exit; } class FAS_Frontend_Form { public function __construct() { add_shortcode('fas_service_form', array($this, 'render_form')); add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts')); add_action('wp_ajax_fas_submit_request', array($this, 'handle_submission')); add_action('wp_ajax_nopriv_fas_submit_request', array($this, 'handle_submission')); } public function enqueue_scripts() { wp_enqueue_style( 'fas-frontend', FAS_PLUGIN_URL . 'assets/css/frontend.css', array(), FAS_VERSION ); wp_enqueue_script( 'fas-frontend', FAS_PLUGIN_URL . 'assets/js/frontend.js', array('jquery'), FAS_VERSION, true ); wp_localize_script('fas-frontend', 'fas_ajax', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('fas_submit_request') )); } public function render_form() { ob_start(); ?> <div class="fas-service-form-container"> <form id="fas-service-form" class="fas-form"> <div class="fas-form-group"> <label for="customer_name"><?php _e('姓名', 'flexible-after-sales'); ?> *</label> <input type="text" id="customer_name" name="customer_name" required> </div> <div class="fas-form-group"> <label for="customer_email"><?php _e('邮箱', 'flexible-after-sales'); ?> *</label> <input type="email" id="customer_email" name="customer_email" required> </div> <div class="fas-form-group"> <label for="product_name"><?php _e('产品名称', 'flexible-after-sales'); ?></label> <input type="text" id="product_name" name="product_name"> </div> <div class="fas-form-group"> <label for="issue_type"><?php _e('问题类型', 'flexible-after-sales'); ?></label> <select id="issue_type" name="issue_type"> <option value="technical"><?php _e('技术问题', 'flexible-after-sales'); ?></option> <option value="billing"><?php _e('账单问题', 'flexible-after-sales'); ?></option> <option value="refund"><?php _e('退款问题', 'flexible-after-sales'); ?></option> <option value="general"><?php _e('一般咨询', 'flexible-after-sales'); ?></option> </select> </div> <div class="fas-form-group"> <label for="priority"><?php _e('优先级', 'flexible-after-sales'); ?></label> <select id="priority" name="priority"> <option value="1"><?php _e('低', 'flexible-after-sales'); ?></option> <option value="2" selected><?php _e('中', 'flexible-after-sales'); ?></option> <option value="3"><?php _e('高', 'flexible-after-sales'); ?></option> <option value="4"><?php _e('紧急', 'flexible-after-sales'); ?></option> </select> </div> <div class="fas-form-group"> <label for="description"><?php _e('问题描述', 'flexible-after-sales'); ?> *</label> <textarea id="description" name="description" rows="5" required></textarea> </div> <div class="fas-form-group"> <button type="submit" class="fas-submit-btn"> <?php _e('提交请求', 'flexible-after-sales'); ?> </button> <div class="fas-loading" style="display:none;"> <?php _e('提交中...', 'flexible-after-sales'); ?> </div> </div> <div class="fas-message"></div> </form> </div> <?php return ob_get_clean(); } public function handle_submission() { // 验证nonce if (!wp_verify_nonce($_POST['nonce'], 'fas_submit_request')) { wp_die(__('安全验证失败', 'flexible-after-sales')); } // 验证数据 $data = array( 'customer_name' => sanitize_text_field($_POST['customer_name']), 'customer_email' => sanitize_email($_POST['customer_email']), 'product_name' => sanitize_text_field($_POST['product_name']), 'issue_type' => sanitize_text_field($_POST['issue_type']), 'priority' => absint($_POST['priority']), 'description' => wp_kses_post($_POST['description']) ); // 创建服务请求 $service_request = new FAS_Service_Request(); $request_id = $service_request->create($data); if ($request_id) { wp_send_json_success(array( 'message' => sprintf(__('请求提交成功!您的请求编号是:%d', 'flexible-after-sales'), $request_id), 'request_id' => $request_id )); } else { wp_send_json_error(array( 'message' => __('提交失败,请稍后重试', 'flexible-after-sales') )); } } } ?>
- 创建管理后台页面: <?php // 文件路径: includes/class-admin-dashboard.php if (!defined('ABSPATH')) { exit; } class FAS_Admin_Dashboard { public function __construct() { add_action('admin_menu', array($this, 'add_admin_pages')); add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
- <?php // 文件路径: includes/class-admin-dashboard.php(续) public function add_admin_pages() { // 主菜单 add_menu_page( __('售后服务管理', 'flexible-after-sales'), __('售后服务', 'flexible-after-sales'), 'manage_options', 'fas-dashboard', array($this, 'render_dashboard'), 'dashicons-businessman', 30 ); // 子菜单 add_submenu_page( 'fas-dashboard', __('所有服务请求', 'flexible-after-sales'), __('所有请求', 'flexible-after-sales'), 'manage_options', 'fas-requests', array($this, 'render_requests_page') ); add_submenu_page( 'fas-dashboard', __('插件设置', 'flexible-after-sales'), __('设置', 'flexible-after-sales'), 'manage_options', 'fas-settings', array($this, 'render_settings_page') ); add_submenu_page( 'fas-dashboard', __('统计报告', 'flexible-after-sales'), __('报告', 'flexible-after-sales'), 'manage_options', 'fas-reports', array($this, 'render_reports_page') ); } public function enqueue_admin_scripts($hook) { if (strpos($hook, 'fas-') === false) { return; } wp_enqueue_style( 'fas-admin', FAS_PLUGIN_URL . 'assets/css/admin.css', array(), FAS_VERSION ); wp_enqueue_script( 'fas-admin', FAS_PLUGIN_URL . 'assets/js/admin.js', array('jquery', 'jquery-ui-datepicker'), FAS_VERSION, true ); wp_enqueue_style('jquery-ui-css', 'https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css'); } public function render_dashboard() { $service_request = new FAS_Service_Request(); // 获取统计数据 $stats = $this->get_dashboard_stats(); ?> <div class="wrap fas-admin-dashboard"> <h1><?php _e('售后服务管理面板', 'flexible-after-sales'); ?></h1> <div class="fas-stats-container"> <div class="fas-stat-card"> <h3><?php _e('待处理', 'flexible-after-sales'); ?></h3> <div class="fas-stat-number"><?php echo $stats['pending']; ?></div> </div> <div class="fas-stat-card"> <h3><?php _e('处理中', 'flexible-after-sales'); ?></h3> <div class="fas-stat-number"><?php echo $stats['in_progress']; ?></div> </div> <div class="fas-stat-card"> <h3><?php _e('已解决', 'flexible-after-sales'); ?></h3> <div class="fas-stat-number"><?php echo $stats['resolved']; ?></div> </div> <div class="fas-stat-card"> <h3><?php _e('总计', 'flexible-after-sales'); ?></h3> <div class="fas-stat-number"><?php echo $stats['total']; ?></div> </div> </div> <div class="fas-recent-requests"> <h2><?php _e('最近的请求', 'flexible-after-sales'); ?></h2> <?php $this->render_requests_table(array('per_page' => 10)); ?> </div> </div> <?php } public function render_requests_page() { ?> <div class="wrap fas-requests-page"> <h1><?php _e('服务请求管理', 'flexible-after-sales'); ?></h1> <div class="fas-filters"> <form method="get" action=""> <input type="hidden" name="page" value="fas-requests"> <select name="status"> <option value=""><?php _e('所有状态', 'flexible-after-sales'); ?></option> <option value="pending" <?php selected(isset($_GET['status']) && $_GET['status'] == 'pending'); ?>> <?php _e('待处理', 'flexible-after-sales'); ?> </option> <option value="in_progress" <?php selected(isset($_GET['status']) && $_GET['status'] == 'in_progress'); ?>> <?php _e('处理中', 'flexible-after-sales'); ?> </option> <option value="resolved" <?php selected(isset($_GET['status']) && $_GET['status'] == 'resolved'); ?>> <?php _e('已解决', 'flexible-after-sales'); ?> </option> <option value="closed" <?php selected(isset($_GET['status']) && $_GET['status'] == 'closed'); ?>> <?php _e('已关闭', 'flexible-after-sales'); ?> </option> </select> <select name="priority"> <option value="0"><?php _e('所有优先级', 'flexible-after-sales'); ?></option> <option value="1" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 1); ?>> <?php _e('低', 'flexible-after-sales'); ?> </option> <option value="2" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 2); ?>> <?php _e('中', 'flexible-after-sales'); ?> </option> <option value="3" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 3); ?>> <?php _e('高', 'flexible-after-sales'); ?> </option> <option value="4" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 4); ?>> <?php _e('紧急', 'flexible-after-sales'); ?> </option> </select> <input type="submit" class="button" value="<?php _e('筛选', 'flexible-after-sales'); ?>"> <a href="?page=fas-requests" class="button"><?php _e('重置', 'flexible-after-sales'); ?></a> </form> </div> <?php $this->render_requests_table(); ?> </div> <?php } private function render_requests_table($args = array()) { $service_request = new FAS_Service_Request(); $defaults = array( 'status' => isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '', 'priority' => isset($_GET['priority']) ? absint($_GET['priority']) : 0, 'per_page' => 20, 'page' => isset($_GET['paged']) ? max(1, absint($_GET['paged'])) : 1 ); $args = wp_parse_args($args, $defaults); $requests = $service_request->get_all($args); ?> <table class="wp-list-table widefat fixed striped fas-requests-table"> <thead> <tr> <th><?php _e('ID', 'flexible-after-sales'); ?></th> <th><?php _e('客户', 'flexible-after-sales'); ?></th> <th><?php _e('产品', 'flexible-after-sales'); ?></th> <th><?php _e('问题类型', 'flexible-after-sales'); ?></th> <th><?php _e('优先级', 'flexible-after-sales'); ?></th> <th><?php _e('状态', 'flexible-after-sales'); ?></th> <th><?php _e('创建时间', 'flexible-after-sales'); ?></th> <th><?php _e('操作', 'flexible-after-sales'); ?></th> </tr> </thead> <tbody> <?php if (empty($requests)): ?> <tr> <td colspan="8"><?php _e('没有找到服务请求', 'flexible-after-sales'); ?></td> </tr> <?php else: ?> <?php foreach ($requests as $request): ?> <tr> <td>#<?php echo $request->id; ?></td> <td> <strong><?php echo esc_html($request->customer_name); ?></strong><br> <small><?php echo esc_html($request->customer_email); ?></small> </td> <td><?php echo esc_html($request->product_name); ?></td> <td><?php echo $this->get_issue_type_label($request->issue_type); ?></td> <td><?php echo $this->get_priority_badge($request->priority); ?></td> <td><?php echo $this->get_status_badge($request->status); ?></td> <td><?php echo date_i18n(get_option('date_format'), strtotime($request->created_at)); ?></td> <td> <a href="?page=fas-requests&action=view&id=<?php echo $request->id; ?>" class="button button-small"> <?php _e('查看', 'flexible-after-sales'); ?> </a> <a href="?page=fas-requests&action=edit&id=<?php echo $request->id; ?>" class="button button-small"> <?php _e('编辑', 'flexible-after-sales'); ?> </a> </td> </tr> <?php endforeach; ?> <?php endif; ?> </tbody> </table> <?php // 这里可以添加分页代码 } private function get_dashboard_stats() { global $wpdb; $table_name = $wpdb->prefix . 'fas_service_requests'; $stats = array( 'pending' => 0, 'in_progress' => 0, 'resolved' => 0, 'total' => 0 ); // 获取各状态数量 $results = $wpdb->get_results(" SELECT status, COUNT(*) as count FROM {$table_name} GROUP BY status "); foreach ($results as $row) { if (isset($stats[$row->status])) { $stats[$row->status] = $row->count; } $stats['total'] += $row->count; } return $stats; } private function get_priority_badge($priority) { $labels = array( 1 => array('label' => __('低', 'flexible-after-sales'), 'class' => 'priority-low'), 2 => array('label' => __('中', 'flexible-after-sales'), 'class' => 'priority-medium'), 3 => array('label' => __('高', 'flexible-after-sales'), 'class' => 'priority-high'), 4 => array('label' => __('紧急', 'flexible-after-sales'), 'class' => 'priority-urgent') ); if (isset($labels[$priority])) { return sprintf('<span class="fas-badge %s">%s</span>', $labels[$priority]['class'], $labels[$priority]['label'] ); } return ''; } private function get_status_badge($status) { $labels = array( 'pending' => array('label' => __('待处理', 'flexible-after-sales'), 'class' => 'status-pending'), 'in_progress' => array('label' => __('处理中', 'flexible-after-sales'), 'class' => 'status-in-progress'), 'resolved' => array('label' => __('已解决', 'flexible-after-sales'), 'class' => 'status-resolved'), 'closed' => array('label' => __('已关闭', 'flexible-after-sales'), 'class' => 'status-closed') ); if (isset($labels[$status])) { return sprintf('<span class="fas-badge %s">%s</span>', $labels[$status]['class'], $labels[$status]['label'] ); } return ''; } private function get_issue_type_label($type) { $labels = array( 'technical' => __('技术问题', 'flexible-after-sales'), 'billing' => __('账单问题', 'flexible-after-sales'), 'refund' => __('退款问题', 'flexible-after-sales'), 'general' => __('一般咨询', 'flexible-after-sales') ); return isset($labels[$type]) ? $labels[$type] : $type; } } ?>
- <?php // 文件路径: includes/class-settings.php if (!defined('ABSPATH')) { exit; } class FAS_Settings { public function __construct() { add_action('admin_init', array($this, 'register_settings')); } public function register_settings() { register_setting('fas_settings_group', 'fas_settings', array($this, 'sanitize_settings')); // 常规设置 add_settings_section( 'fas_general_section', __('常规设置', 'flexible-after-sales'), array($this, 'render_general_section'), 'fas_settings' ); add_settings_field( 'email_notifications', __('邮件通知', 'flexible-after-sales'), array($this, 'render_email_notifications_field'), 'fas_settings', 'fas_general_section' ); add_settings_field( 'support_email', __('支持邮箱', 'flexible-after-sales'), array($this, 'render_support_email_field'), 'fas_settings', 'fas_general_section' ); add_settings_field( 'default_priority', __('默认优先级', 'flexible-after-sales'), array($this, 'render_default_priority_field'), 'fas_settings', 'fas_general_section' ); // 高级设置 add_settings_section( 'fas_advanced_section', __('高级设置', 'flexible-after-sales'), array($this, 'render_advanced_section'), 'fas_settings' ); add_settings_field( 'auto_assign', __('自动分配', 'flexible-after-sales'), array($this, 'render_auto_assign_field'), 'fas_settings', 'fas_advanced_section' ); add_settings_field( 'allowed_users', __('允许的管理员', 'flexible-after-sales'), array($this, 'render_allowed_users_field'), 'fas_settings', 'fas_advanced_section' ); } public function sanitize_settings($input) { $sanitized = array(); // 邮件通知 $sanitized['email_notifications'] = isset($input['email_notifications']) ? 1 : 0; // 支持邮箱 $sanitized['support_email'] = sanitize_email($input['support_email']); if (!is_email($sanitized['support_email'])) { $sanitized['support_email'] = get_option('admin_email'); } // 默认优先级 $sanitized['default_priority'] = absint($input['default_priority']); if ($sanitized['default_priority'] < 1 || $sanitized['default_priority'] > 4) { $sanitized['default_priority'] = 2; } // 自动分配 $sanitized['auto_assign'] = isset($input['auto_assign']) ? 1 : 0; // 允许的用户 $sanitized['allowed_users'] = array(); if (isset($input['allowed_users']) && is_array($input['allowed_users'])) { foreach ($input['allowed_users'] as $user_id) { $user_id = absint($user_id); if ($user_id > 0) { $sanitized['allowed_users'][] = $user_id; } } } return $sanitized; } public function render_general_section() { echo '<p>' . __('配置插件的基本设置', 'flexible-after-sales') . '</p>'; } public function render_advanced_section() { echo '<p>' . __('高级功能配置', 'flexible-after-sales') . '</p>'; } public function render_email_notifications_field() { $settings = get_option('fas_settings'); $checked = isset($settings['email_notifications']) && $settings['email_notifications'] ? 'checked' : ''; echo '<label>'; echo '<input type="checkbox" name="fas_settings[email_notifications]" value="1" ' . $checked . '>'; echo __('启用新请求邮件通知', 'flexible-after-sales'); echo '</label>'; echo '<p class="description">' . __('当有新服务请求时发送邮件通知', 'flexible-after-sales') . '</p>'; } public function render_support_email_field() { $settings = get_option('fas_settings'); $value = isset($settings['support_email']) ? $settings['support_email'] : get_option('admin_email'); echo '<input type="email" name="fas_settings[support_email]" value="' . esc_attr($value) . '" class="regular-text">'; echo '<p class="description">' . __('接收通知的邮箱地址', 'flexible-after-sales') . '</p>'; } public function render_default_priority_field() { $settings = get_option('fas_settings'); $value = isset($settings['default_priority']) ? $settings['default_priority'] : 2; echo '<select name="fas_settings[default_priority]">';
在当今数字化服务时代,企业需要一个灵活的售后服务体系来管理客户支持请求。本教程将带领您开发一个WordPress柔性售后服务管理插件,该系统将允许客户提交服务请求、跟踪处理状态,同时让管理员高效管理所有售后事务。
核心功能需求:
- 客户提交服务请求表单
- 请求状态跟踪(待处理、处理中、已解决、已关闭)
- 管理员后台管理界面
- 邮件通知系统
- 服务请求分类和优先级管理
首先,我们需要创建插件的基本文件结构。在WordPress的wp-content/plugins/目录下创建新文件夹flexible-after-sales。
创建主插件文件:
<?php
/**
* Plugin Name: Flexible After Sales Service Manager
* Plugin URI: https://yourwebsite.com/
* Description: 一个灵活的WordPress售后服务管理插件
* Version: 1.0.0
* Author: Your Name
* License: GPL v2 or later
* Text Domain: flexible-after-sales
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('FAS_VERSION', '1.0.0');
define('FAS_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('FAS_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
class FlexibleAfterSales {
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('init', array($this, 'init'));
// 管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 加载文本域
add_action('plugins_loaded', array($this, 'load_textdomain'));
}
public function activate() {
// 创建数据库表
$this->create_tables();
// 设置默认选项
$this->set_default_options();
// 刷新重写规则
flush_rewrite_rules();
}
public function deactivate() {
// 清理临时数据
delete_option('fas_flush_rewrite_rules');
// 刷新重写规则
flush_rewrite_rules();
}
public function load_textdomain() {
load_plugin_textdomain(
'flexible-after-sales',
false,
dirname(plugin_basename(__FILE__)) . '/languages'
);
}
public function init() {
// 初始化代码将在后续步骤中添加
}
public function add_admin_menu() {
// 管理菜单代码将在后续步骤中添加
}
private function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'fas_service_requests';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
customer_name varchar(100) NOT NULL,
customer_email varchar(100) NOT NULL,
product_name varchar(200) NOT NULL,
issue_type varchar(50) NOT NULL,
description text NOT NULL,
priority tinyint(1) DEFAULT 2,
status varchar(20) DEFAULT 'pending',
assigned_to bigint(20) DEFAULT 0,
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);
}
private function set_default_options() {
if (!get_option('fas_settings')) {
$default_settings = array(
'email_notifications' => 1,
'default_priority' => 2,
'auto_assign' => 0,
'support_email' => get_option('admin_email')
);
update_option('fas_settings', $default_settings);
}
}
}
// 启动插件
FlexibleAfterSales::get_instance();
?>
创建服务请求管理类:
<?php
// 文件路径: includes/class-service-request.php
if (!defined('ABSPATH')) {
exit;
}
class FAS_Service_Request {
private $db;
private $table_name;
public function __construct() {
global $wpdb;
$this->db = $wpdb;
$this->table_name = $wpdb->prefix . 'fas_service_requests';
}
/**
* 创建新的服务请求
* @param array $data 请求数据
* @return int|false 插入ID或false
*/
public function create($data) {
$defaults = array(
'customer_name' => '',
'customer_email' => '',
'product_name' => '',
'issue_type' => 'general',
'description' => '',
'priority' => 2,
'status' => 'pending',
'assigned_to' => 0
);
$data = wp_parse_args($data, $defaults);
// 验证必要字段
if (empty($data['customer_name']) || empty($data['customer_email']) || empty($data['description'])) {
return false;
}
// 插入数据
$result = $this->db->insert(
$this->table_name,
array(
'customer_name' => sanitize_text_field($data['customer_name']),
'customer_email' => sanitize_email($data['customer_email']),
'product_name' => sanitize_text_field($data['product_name']),
'issue_type' => sanitize_text_field($data['issue_type']),
'description' => wp_kses_post($data['description']),
'priority' => absint($data['priority']),
'status' => sanitize_text_field($data['status']),
'assigned_to' => absint($data['assigned_to'])
),
array('%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d')
);
if ($result) {
$request_id = $this->db->insert_id;
// 发送通知邮件
$this->send_notification_email($request_id, 'new_request');
return $request_id;
}
return false;
}
/**
* 获取服务请求
* @param int $id 请求ID
* @return object|null 请求对象或null
*/
public function get($id) {
$query = $this->db->prepare(
"SELECT * FROM {$this->table_name} WHERE id = %d",
$id
);
return $this->db->get_row($query);
}
/**
* 更新服务请求
* @param int $id 请求ID
* @param array $data 更新数据
* @return bool 是否成功
*/
public function update($id, $data) {
$allowed_fields = array(
'customer_name',
'customer_email',
'product_name',
'issue_type',
'description',
'priority',
'status',
'assigned_to'
);
$update_data = array();
$format = array();
foreach ($data as $key => $value) {
if (in_array($key, $allowed_fields)) {
$update_data[$key] = $value;
// 设置格式
if (in_array($key, array('priority', 'assigned_to'))) {
$format[] = '%d';
} else {
$format[] = '%s';
}
}
}
if (empty($update_data)) {
return false;
}
$result = $this->db->update(
$this->table_name,
$update_data,
array('id' => $id),
$format,
array('%d')
);
return $result !== false;
}
/**
* 获取所有服务请求
* @param array $args 查询参数
* @return array 请求数组
*/
public function get_all($args = array()) {
$defaults = array(
'status' => '',
'priority' => 0,
'per_page' => 20,
'page' => 1,
'orderby' => 'created_at',
'order' => 'DESC'
);
$args = wp_parse_args($args, $defaults);
$where = array('1=1');
$values = array();
// 状态筛选
if (!empty($args['status'])) {
$where[] = 'status = %s';
$values[] = $args['status'];
}
// 优先级筛选
if ($args['priority'] > 0) {
$where[] = 'priority = %d';
$values[] = $args['priority'];
}
$where_clause = implode(' AND ', $where);
// 分页计算
$offset = ($args['page'] - 1) * $args['per_page'];
// 构建查询
$query = "SELECT * FROM {$this->table_name} WHERE {$where_clause}";
if (!empty($values)) {
$query = $this->db->prepare($query, $values);
}
$query .= " ORDER BY {$args['orderby']} {$args['order']}";
$query .= " LIMIT {$args['per_page']} OFFSET {$offset}";
return $this->db->get_results($query);
}
/**
* 发送通知邮件
* @param int $request_id 请求ID
* @param string $type 邮件类型
*/
private function send_notification_email($request_id, $type) {
$settings = get_option('fas_settings');
if (!$settings['email_notifications']) {
return;
}
$request = $this->get($request_id);
if (!$request) {
return;
}
$to = $settings['support_email'];
$subject = '';
$message = '';
switch ($type) {
case 'new_request':
$subject = sprintf(__('新的服务请求 #%d', 'flexible-after-sales'), $request_id);
$message = $this->get_email_template('new_request', $request);
break;
case 'status_update':
$subject = sprintf(__('服务请求 #%d 状态更新', 'flexible-after-sales'), $request_id);
$message = $this->get_email_template('status_update', $request);
break;
}
if (!empty($subject) && !empty($message)) {
wp_mail($to, $subject, $message, array('Content-Type: text/html; charset=UTF-8'));
}
}
/**
* 获取邮件模板
* @param string $template 模板名称
* @param object $request 请求对象
* @return string 邮件内容
*/
private function get_email_template($template, $request) {
ob_start();
include FAS_PLUGIN_DIR . 'templates/emails/' . $template . '.php';
return ob_get_clean();
}
}
?>
创建服务请求提交表单:
<?php
// 文件路径: includes/class-frontend-form.php
if (!defined('ABSPATH')) {
exit;
}
class FAS_Frontend_Form {
public function __construct() {
add_shortcode('fas_service_form', array($this, 'render_form'));
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
add_action('wp_ajax_fas_submit_request', array($this, 'handle_submission'));
add_action('wp_ajax_nopriv_fas_submit_request', array($this, 'handle_submission'));
}
public function enqueue_scripts() {
wp_enqueue_style(
'fas-frontend',
FAS_PLUGIN_URL . 'assets/css/frontend.css',
array(),
FAS_VERSION
);
wp_enqueue_script(
'fas-frontend',
FAS_PLUGIN_URL . 'assets/js/frontend.js',
array('jquery'),
FAS_VERSION,
true
);
wp_localize_script('fas-frontend', 'fas_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('fas_submit_request')
));
}
public function render_form() {
ob_start();
?>
<div class="fas-service-form-container">
<form id="fas-service-form" class="fas-form">
<div class="fas-form-group">
<label for="customer_name"><?php _e('姓名', 'flexible-after-sales'); ?> *</label>
<input type="text" id="customer_name" name="customer_name" required>
</div>
<div class="fas-form-group">
<label for="customer_email"><?php _e('邮箱', 'flexible-after-sales'); ?> *</label>
<input type="email" id="customer_email" name="customer_email" required>
</div>
<div class="fas-form-group">
<label for="product_name"><?php _e('产品名称', 'flexible-after-sales'); ?></label>
<input type="text" id="product_name" name="product_name">
</div>
<div class="fas-form-group">
<label for="issue_type"><?php _e('问题类型', 'flexible-after-sales'); ?></label>
<select id="issue_type" name="issue_type">
<option value="technical"><?php _e('技术问题', 'flexible-after-sales'); ?></option>
<option value="billing"><?php _e('账单问题', 'flexible-after-sales'); ?></option>
<option value="refund"><?php _e('退款问题', 'flexible-after-sales'); ?></option>
<option value="general"><?php _e('一般咨询', 'flexible-after-sales'); ?></option>
</select>
</div>
<div class="fas-form-group">
<label for="priority"><?php _e('优先级', 'flexible-after-sales'); ?></label>
<select id="priority" name="priority">
<option value="1"><?php _e('低', 'flexible-after-sales'); ?></option>
<option value="2" selected><?php _e('中', 'flexible-after-sales'); ?></option>
<option value="3"><?php _e('高', 'flexible-after-sales'); ?></option>
<option value="4"><?php _e('紧急', 'flexible-after-sales'); ?></option>
</select>
</div>
<div class="fas-form-group">
<label for="description"><?php _e('问题描述', 'flexible-after-sales'); ?> *</label>
<textarea id="description" name="description" rows="5" required></textarea>
</div>
<div class="fas-form-group">
<button type="submit" class="fas-submit-btn">
<?php _e('提交请求', 'flexible-after-sales'); ?>
</button>
<div class="fas-loading" style="display:none;">
<?php _e('提交中...', 'flexible-after-sales'); ?>
</div>
</div>
<div class="fas-message"></div>
</form>
</div>
<?php
return ob_get_clean();
}
public function handle_submission() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'fas_submit_request')) {
wp_die(__('安全验证失败', 'flexible-after-sales'));
}
// 验证数据
$data = array(
'customer_name' => sanitize_text_field($_POST['customer_name']),
'customer_email' => sanitize_email($_POST['customer_email']),
'product_name' => sanitize_text_field($_POST['product_name']),
'issue_type' => sanitize_text_field($_POST['issue_type']),
'priority' => absint($_POST['priority']),
'description' => wp_kses_post($_POST['description'])
);
// 创建服务请求
$service_request = new FAS_Service_Request();
$request_id = $service_request->create($data);
if ($request_id) {
wp_send_json_success(array(
'message' => sprintf(__('请求提交成功!您的请求编号是:%d', 'flexible-after-sales'), $request_id),
'request_id' => $request_id
));
} else {
wp_send_json_error(array(
'message' => __('提交失败,请稍后重试', 'flexible-after-sales')
));
}
}
}
?>
创建管理后台页面:
<?php
// 文件路径: includes/class-admin-dashboard.php
if (!defined('ABSPATH')) {
exit;
}
class FAS_Admin_Dashboard {
public function __construct() {
add_action('admin_menu', array($this, 'add_admin_pages'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
<?php
// 文件路径: includes/class-admin-dashboard.php(续)
public function add_admin_pages() {
// 主菜单
add_menu_page(
__('售后服务管理', 'flexible-after-sales'),
__('售后服务', 'flexible-after-sales'),
'manage_options',
'fas-dashboard',
array($this, 'render_dashboard'),
'dashicons-businessman',
30
);
// 子菜单
add_submenu_page(
'fas-dashboard',
__('所有服务请求', 'flexible-after-sales'),
__('所有请求', 'flexible-after-sales'),
'manage_options',
'fas-requests',
array($this, 'render_requests_page')
);
add_submenu_page(
'fas-dashboard',
__('插件设置', 'flexible-after-sales'),
__('设置', 'flexible-after-sales'),
'manage_options',
'fas-settings',
array($this, 'render_settings_page')
);
add_submenu_page(
'fas-dashboard',
__('统计报告', 'flexible-after-sales'),
__('报告', 'flexible-after-sales'),
'manage_options',
'fas-reports',
array($this, 'render_reports_page')
);
}
public function enqueue_admin_scripts($hook) {
if (strpos($hook, 'fas-') === false) {
return;
}
wp_enqueue_style(
'fas-admin',
FAS_PLUGIN_URL . 'assets/css/admin.css',
array(),
FAS_VERSION
);
wp_enqueue_script(
'fas-admin',
FAS_PLUGIN_URL . 'assets/js/admin.js',
array('jquery', 'jquery-ui-datepicker'),
FAS_VERSION,
true
);
wp_enqueue_style('jquery-ui-css', 'https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css');
}
public function render_dashboard() {
$service_request = new FAS_Service_Request();
// 获取统计数据
$stats = $this->get_dashboard_stats();
?>
<div class="wrap fas-admin-dashboard">
<h1><?php _e('售后服务管理面板', 'flexible-after-sales'); ?></h1>
<div class="fas-stats-container">
<div class="fas-stat-card">
<h3><?php _e('待处理', 'flexible-after-sales'); ?></h3>
<div class="fas-stat-number"><?php echo $stats['pending']; ?></div>
</div>
<div class="fas-stat-card">
<h3><?php _e('处理中', 'flexible-after-sales'); ?></h3>
<div class="fas-stat-number"><?php echo $stats['in_progress']; ?></div>
</div>
<div class="fas-stat-card">
<h3><?php _e('已解决', 'flexible-after-sales'); ?></h3>
<div class="fas-stat-number"><?php echo $stats['resolved']; ?></div>
</div>
<div class="fas-stat-card">
<h3><?php _e('总计', 'flexible-after-sales'); ?></h3>
<div class="fas-stat-number"><?php echo $stats['total']; ?></div>
</div>
</div>
<div class="fas-recent-requests">
<h2><?php _e('最近的请求', 'flexible-after-sales'); ?></h2>
<?php $this->render_requests_table(array('per_page' => 10)); ?>
</div>
</div>
<?php
}
public function render_requests_page() {
?>
<div class="wrap fas-requests-page">
<h1><?php _e('服务请求管理', 'flexible-after-sales'); ?></h1>
<div class="fas-filters">
<form method="get" action="">
<input type="hidden" name="page" value="fas-requests">
<select name="status">
<option value=""><?php _e('所有状态', 'flexible-after-sales'); ?></option>
<option value="pending" <?php selected(isset($_GET['status']) && $_GET['status'] == 'pending'); ?>>
<?php _e('待处理', 'flexible-after-sales'); ?>
</option>
<option value="in_progress" <?php selected(isset($_GET['status']) && $_GET['status'] == 'in_progress'); ?>>
<?php _e('处理中', 'flexible-after-sales'); ?>
</option>
<option value="resolved" <?php selected(isset($_GET['status']) && $_GET['status'] == 'resolved'); ?>>
<?php _e('已解决', 'flexible-after-sales'); ?>
</option>
<option value="closed" <?php selected(isset($_GET['status']) && $_GET['status'] == 'closed'); ?>>
<?php _e('已关闭', 'flexible-after-sales'); ?>
</option>
</select>
<select name="priority">
<option value="0"><?php _e('所有优先级', 'flexible-after-sales'); ?></option>
<option value="1" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 1); ?>>
<?php _e('低', 'flexible-after-sales'); ?>
</option>
<option value="2" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 2); ?>>
<?php _e('中', 'flexible-after-sales'); ?>
</option>
<option value="3" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 3); ?>>
<?php _e('高', 'flexible-after-sales'); ?>
</option>
<option value="4" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 4); ?>>
<?php _e('紧急', 'flexible-after-sales'); ?>
</option>
</select>
<input type="submit" class="button" value="<?php _e('筛选', 'flexible-after-sales'); ?>">
<a href="?page=fas-requests" class="button"><?php _e('重置', 'flexible-after-sales'); ?></a>
</form>
</div>
<?php $this->render_requests_table(); ?>
</div>
<?php
}
private function render_requests_table($args = array()) {
$service_request = new FAS_Service_Request();
$defaults = array(
'status' => isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '',
'priority' => isset($_GET['priority']) ? absint($_GET['priority']) : 0,
'per_page' => 20,
'page' => isset($_GET['paged']) ? max(1, absint($_GET['paged'])) : 1
);
$args = wp_parse_args($args, $defaults);
$requests = $service_request->get_all($args);
?>
<table class="wp-list-table widefat fixed striped fas-requests-table">
<thead>
<tr>
<th><?php _e('ID', 'flexible-after-sales'); ?></th>
<th><?php _e('客户', 'flexible-after-sales'); ?></th>
<th><?php _e('产品', 'flexible-after-sales'); ?></th>
<th><?php _e('问题类型', 'flexible-after-sales'); ?></th>
<th><?php _e('优先级', 'flexible-after-sales'); ?></th>
<th><?php _e('状态', 'flexible-after-sales'); ?></th>
<th><?php _e('创建时间', 'flexible-after-sales'); ?></th>
<th><?php _e('操作', 'flexible-after-sales'); ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($requests)): ?>
<tr>
<td colspan="8"><?php _e('没有找到服务请求', 'flexible-after-sales'); ?></td>
</tr>
<?php else: ?>
<?php foreach ($requests as $request): ?>
<tr>
<td>#<?php echo $request->id; ?></td>
<td>
<strong><?php echo esc_html($request->customer_name); ?></strong><br>
<small><?php echo esc_html($request->customer_email); ?></small>
</td>
<td><?php echo esc_html($request->product_name); ?></td>
<td><?php echo $this->get_issue_type_label($request->issue_type); ?></td>
<td><?php echo $this->get_priority_badge($request->priority); ?></td>
<td><?php echo $this->get_status_badge($request->status); ?></td>
<td><?php echo date_i18n(get_option('date_format'), strtotime($request->created_at)); ?></td>
<td>
<a href="?page=fas-requests&action=view&id=<?php echo $request->id; ?>"
class="button button-small">
<?php _e('查看', 'flexible-after-sales'); ?>
</a>
<a href="?page=fas-requests&action=edit&id=<?php echo $request->id; ?>"
class="button button-small">
<?php _e('编辑', 'flexible-after-sales'); ?>
</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<?php
// 这里可以添加分页代码
}
private function get_dashboard_stats() {
global $wpdb;
$table_name = $wpdb->prefix . 'fas_service_requests';
$stats = array(
'pending' => 0,
'in_progress' => 0,
'resolved' => 0,
'total' => 0
);
// 获取各状态数量
$results = $wpdb->get_results("
SELECT status, COUNT(*) as count
FROM {$table_name}
GROUP BY status
");
foreach ($results as $row) {
if (isset($stats[$row->status])) {
$stats[$row->status] = $row->count;
}
$stats['total'] += $row->count;
}
return $stats;
}
private function get_priority_badge($priority) {
$labels = array(
1 => array('label' => __('低', 'flexible-after-sales'), 'class' => 'priority-low'),
2 => array('label' => __('中', 'flexible-after-sales'), 'class' => 'priority-medium'),
3 => array('label' => __('高', 'flexible-after-sales'), 'class' => 'priority-high'),
4 => array('label' => __('紧急', 'flexible-after-sales'), 'class' => 'priority-urgent')
);
if (isset($labels[$priority])) {
return sprintf('<span class="fas-badge %s">%s</span>',
$labels[$priority]['class'],
$labels[$priority]['label']
);
}
return '';
}
private function get_status_badge($status) {
$labels = array(
'pending' => array('label' => __('待处理', 'flexible-after-sales'), 'class' => 'status-pending'),
'in_progress' => array('label' => __('处理中', 'flexible-after-sales'), 'class' => 'status-in-progress'),
'resolved' => array('label' => __('已解决', 'flexible-after-sales'), 'class' => 'status-resolved'),
'closed' => array('label' => __('已关闭', 'flexible-after-sales'), 'class' => 'status-closed')
);
if (isset($labels[$status])) {
return sprintf('<span class="fas-badge %s">%s</span>',
$labels[$status]['class'],
$labels[$status]['label']
);
}
return '';
}
private function get_issue_type_label($type) {
$labels = array(
'technical' => __('技术问题', 'flexible-after-sales'),
'billing' => __('账单问题', 'flexible-after-sales'),
'refund' => __('退款问题', 'flexible-after-sales'),
'general' => __('一般咨询', 'flexible-after-sales')
);
return isset($labels[$type]) ? $labels[$type] : $type;
}
}
?>
<?php
// 文件路径: includes/class-admin-dashboard.php(续)
public function add_admin_pages() {
// 主菜单
add_menu_page(
__('售后服务管理', 'flexible-after-sales'),
__('售后服务', 'flexible-after-sales'),
'manage_options',
'fas-dashboard',
array($this, 'render_dashboard'),
'dashicons-businessman',
30
);
// 子菜单
add_submenu_page(
'fas-dashboard',
__('所有服务请求', 'flexible-after-sales'),
__('所有请求', 'flexible-after-sales'),
'manage_options',
'fas-requests',
array($this, 'render_requests_page')
);
add_submenu_page(
'fas-dashboard',
__('插件设置', 'flexible-after-sales'),
__('设置', 'flexible-after-sales'),
'manage_options',
'fas-settings',
array($this, 'render_settings_page')
);
add_submenu_page(
'fas-dashboard',
__('统计报告', 'flexible-after-sales'),
__('报告', 'flexible-after-sales'),
'manage_options',
'fas-reports',
array($this, 'render_reports_page')
);
}
public function enqueue_admin_scripts($hook) {
if (strpos($hook, 'fas-') === false) {
return;
}
wp_enqueue_style(
'fas-admin',
FAS_PLUGIN_URL . 'assets/css/admin.css',
array(),
FAS_VERSION
);
wp_enqueue_script(
'fas-admin',
FAS_PLUGIN_URL . 'assets/js/admin.js',
array('jquery', 'jquery-ui-datepicker'),
FAS_VERSION,
true
);
wp_enqueue_style('jquery-ui-css', 'https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css');
}
public function render_dashboard() {
$service_request = new FAS_Service_Request();
// 获取统计数据
$stats = $this->get_dashboard_stats();
?>
<div class="wrap fas-admin-dashboard">
<h1><?php _e('售后服务管理面板', 'flexible-after-sales'); ?></h1>
<div class="fas-stats-container">
<div class="fas-stat-card">
<h3><?php _e('待处理', 'flexible-after-sales'); ?></h3>
<div class="fas-stat-number"><?php echo $stats['pending']; ?></div>
</div>
<div class="fas-stat-card">
<h3><?php _e('处理中', 'flexible-after-sales'); ?></h3>
<div class="fas-stat-number"><?php echo $stats['in_progress']; ?></div>
</div>
<div class="fas-stat-card">
<h3><?php _e('已解决', 'flexible-after-sales'); ?></h3>
<div class="fas-stat-number"><?php echo $stats['resolved']; ?></div>
</div>
<div class="fas-stat-card">
<h3><?php _e('总计', 'flexible-after-sales'); ?></h3>
<div class="fas-stat-number"><?php echo $stats['total']; ?></div>
</div>
</div>
<div class="fas-recent-requests">
<h2><?php _e('最近的请求', 'flexible-after-sales'); ?></h2>
<?php $this->render_requests_table(array('per_page' => 10)); ?>
</div>
</div>
<?php
}
public function render_requests_page() {
?>
<div class="wrap fas-requests-page">
<h1><?php _e('服务请求管理', 'flexible-after-sales'); ?></h1>
<div class="fas-filters">
<form method="get" action="">
<input type="hidden" name="page" value="fas-requests">
<select name="status">
<option value=""><?php _e('所有状态', 'flexible-after-sales'); ?></option>
<option value="pending" <?php selected(isset($_GET['status']) && $_GET['status'] == 'pending'); ?>>
<?php _e('待处理', 'flexible-after-sales'); ?>
</option>
<option value="in_progress" <?php selected(isset($_GET['status']) && $_GET['status'] == 'in_progress'); ?>>
<?php _e('处理中', 'flexible-after-sales'); ?>
</option>
<option value="resolved" <?php selected(isset($_GET['status']) && $_GET['status'] == 'resolved'); ?>>
<?php _e('已解决', 'flexible-after-sales'); ?>
</option>
<option value="closed" <?php selected(isset($_GET['status']) && $_GET['status'] == 'closed'); ?>>
<?php _e('已关闭', 'flexible-after-sales'); ?>
</option>
</select>
<select name="priority">
<option value="0"><?php _e('所有优先级', 'flexible-after-sales'); ?></option>
<option value="1" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 1); ?>>
<?php _e('低', 'flexible-after-sales'); ?>
</option>
<option value="2" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 2); ?>>
<?php _e('中', 'flexible-after-sales'); ?>
</option>
<option value="3" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 3); ?>>
<?php _e('高', 'flexible-after-sales'); ?>
</option>
<option value="4" <?php selected(isset($_GET['priority']) && $_GET['priority'] == 4); ?>>
<?php _e('紧急', 'flexible-after-sales'); ?>
</option>
</select>
<input type="submit" class="button" value="<?php _e('筛选', 'flexible-after-sales'); ?>">
<a href="?page=fas-requests" class="button"><?php _e('重置', 'flexible-after-sales'); ?></a>
</form>
</div>
<?php $this->render_requests_table(); ?>
</div>
<?php
}
private function render_requests_table($args = array()) {
$service_request = new FAS_Service_Request();
$defaults = array(
'status' => isset($_GET['status']) ? sanitize_text_field($_GET['status']) : '',
'priority' => isset($_GET['priority']) ? absint($_GET['priority']) : 0,
'per_page' => 20,
'page' => isset($_GET['paged']) ? max(1, absint($_GET['paged'])) : 1
);
$args = wp_parse_args($args, $defaults);
$requests = $service_request->get_all($args);
?>
<table class="wp-list-table widefat fixed striped fas-requests-table">
<thead>
<tr>
<th><?php _e('ID', 'flexible-after-sales'); ?></th>
<th><?php _e('客户', 'flexible-after-sales'); ?></th>
<th><?php _e('产品', 'flexible-after-sales'); ?></th>
<th><?php _e('问题类型', 'flexible-after-sales'); ?></th>
<th><?php _e('优先级', 'flexible-after-sales'); ?></th>
<th><?php _e('状态', 'flexible-after-sales'); ?></th>
<th><?php _e('创建时间', 'flexible-after-sales'); ?></th>
<th><?php _e('操作', 'flexible-after-sales'); ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($requests)): ?>
<tr>
<td colspan="8"><?php _e('没有找到服务请求', 'flexible-after-sales'); ?></td>
</tr>
<?php else: ?>
<?php foreach ($requests as $request): ?>
<tr>
<td>#<?php echo $request->id; ?></td>
<td>
<strong><?php echo esc_html($request->customer_name); ?></strong><br>
<small><?php echo esc_html($request->customer_email); ?></small>
</td>
<td><?php echo esc_html($request->product_name); ?></td>
<td><?php echo $this->get_issue_type_label($request->issue_type); ?></td>
<td><?php echo $this->get_priority_badge($request->priority); ?></td>
<td><?php echo $this->get_status_badge($request->status); ?></td>
<td><?php echo date_i18n(get_option('date_format'), strtotime($request->created_at)); ?></td>
<td>
<a href="?page=fas-requests&action=view&id=<?php echo $request->id; ?>"
class="button button-small">
<?php _e('查看', 'flexible-after-sales'); ?>
</a>
<a href="?page=fas-requests&action=edit&id=<?php echo $request->id; ?>"
class="button button-small">
<?php _e('编辑', 'flexible-after-sales'); ?>
</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<?php
// 这里可以添加分页代码
}
private function get_dashboard_stats() {
global $wpdb;
$table_name = $wpdb->prefix . 'fas_service_requests';
$stats = array(
'pending' => 0,
'in_progress' => 0,
'resolved' => 0,
'total' => 0
);
// 获取各状态数量
$results = $wpdb->get_results("
SELECT status, COUNT(*) as count
FROM {$table_name}
GROUP BY status
");
foreach ($results as $row) {
if (isset($stats[$row->status])) {
$stats[$row->status] = $row->count;
}
$stats['total'] += $row->count;
}
return $stats;
}
private function get_priority_badge($priority) {
$labels = array(
1 => array('label' => __('低', 'flexible-after-sales'), 'class' => 'priority-low'),
2 => array('label' => __('中', 'flexible-after-sales'), 'class' => 'priority-medium'),
3 => array('label' => __('高', 'flexible-after-sales'), 'class' => 'priority-high'),
4 => array('label' => __('紧急', 'flexible-after-sales'), 'class' => 'priority-urgent')
);
if (isset($labels[$priority])) {
return sprintf('<span class="fas-badge %s">%s</span>',
$labels[$priority]['class'],
$labels[$priority]['label']
);
}
return '';
}
private function get_status_badge($status) {
$labels = array(
'pending' => array('label' => __('待处理', 'flexible-after-sales'), 'class' => 'status-pending'),
'in_progress' => array('label' => __('处理中', 'flexible-after-sales'), 'class' => 'status-in-progress'),
'resolved' => array('label' => __('已解决', 'flexible-after-sales'), 'class' => 'status-resolved'),
'closed' => array('label' => __('已关闭', 'flexible-after-sales'), 'class' => 'status-closed')
);
if (isset($labels[$status])) {
return sprintf('<span class="fas-badge %s">%s</span>',
$labels[$status]['class'],
$labels[$status]['label']
);
}
return '';
}
private function get_issue_type_label($type) {
$labels = array(
'technical' => __('技术问题', 'flexible-after-sales'),
'billing' => __('账单问题', 'flexible-after-sales'),
'refund' => __('退款问题', 'flexible-after-sales'),
'general' => __('一般咨询', 'flexible-after-sales')
);
return isset($labels[$type]) ? $labels[$type] : $type;
}
}
?>
<?php
// 文件路径: includes/class-settings.php
if (!defined('ABSPATH')) {
exit;
}
class FAS_Settings {
public function __construct() {
add_action('admin_init', array($this, 'register_settings'));
}
public function register_settings() {
register_setting('fas_settings_group', 'fas_settings', array($this, 'sanitize_settings'));
// 常规设置
add_settings_section(
'fas_general_section',
__('常规设置', 'flexible-after-sales'),
array($this, 'render_general_section'),
'fas_settings'
);
add_settings_field(
'email_notifications',
__('邮件通知', 'flexible-after-sales'),
array($this, 'render_email_notifications_field'),
'fas_settings',
'fas_general_section'
);
add_settings_field(
'support_email',
__('支持邮箱', 'flexible-after-sales'),
array($this, 'render_support_email_field'),
'fas_settings',
'fas_general_section'
);
add_settings_field(
'default_priority',
__('默认优先级', 'flexible-after-sales'),
array($this, 'render_default_priority_field'),
'fas_settings',
'fas_general_section'
);
// 高级设置
add_settings_section(
'fas_advanced_section',
__('高级设置', 'flexible-after-sales'),
array($this, 'render_advanced_section'),
'fas_settings'
);
add_settings_field(
'auto_assign',
__('自动分配', 'flexible-after-sales'),
array($this, 'render_auto_assign_field'),
'fas_settings',
'fas_advanced_section'
);
add_settings_field(
'allowed_users',
__('允许的管理员', 'flexible-after-sales'),
array($this, 'render_allowed_users_field'),
'fas_settings',
'fas_advanced_section'
);
}
public function sanitize_settings($input) {
$sanitized = array();
// 邮件通知
$sanitized['email_notifications'] = isset($input['email_notifications']) ? 1 : 0;
// 支持邮箱
$sanitized['support_email'] = sanitize_email($input['support_email']);
if (!is_email($sanitized['support_email'])) {
$sanitized['support_email'] = get_option('admin_email');
}
// 默认优先级
$sanitized['default_priority'] = absint($input['default_priority']);
if ($sanitized['default_priority'] < 1 || $sanitized['default_priority'] > 4) {
$sanitized['default_priority'] = 2;
}
// 自动分配
$sanitized['auto_assign'] = isset($input['auto_assign']) ? 1 : 0;
// 允许的用户
$sanitized['allowed_users'] = array();
if (isset($input['allowed_users']) && is_array($input['allowed_users'])) {
foreach ($input['allowed_users'] as $user_id) {
$user_id = absint($user_id);
if ($user_id > 0) {
$sanitized['allowed_users'][] = $user_id;
}
}
}
return $sanitized;
}
public function render_general_section() {
echo '<p>' . __('配置插件的基本设置', 'flexible-after-sales') . '</p>';
}
public function render_advanced_section() {
echo '<p>' . __('高级功能配置', 'flexible-after-sales') . '</p>';
}
public function render_email_notifications_field() {
$settings = get_option('fas_settings');
$checked = isset($settings['email_notifications']) && $settings['email_notifications'] ? 'checked' : '';
echo '<label>';
echo '<input type="checkbox" name="fas_settings[email_notifications]" value="1" ' . $checked . '>';
echo __('启用新请求邮件通知', 'flexible-after-sales');
echo '</label>';
echo '<p class="description">' . __('当有新服务请求时发送邮件通知', 'flexible-after-sales') . '</p>';
}
public function render_support_email_field() {
$settings = get_option('fas_settings');
$value = isset($settings['support_email']) ? $settings['support_email'] : get_option('admin_email');
echo '<input type="email" name="fas_settings[support_email]" value="' . esc_attr($value) . '" class="regular-text">';
echo '<p class="description">' . __('接收通知的邮箱地址', 'flexible-after-sales') . '</p>';
}
public function render_default_priority_field() {
$settings = get_option('fas_settings');
$value = isset($settings['default_priority']) ? $settings['default_priority'] : 2;
echo '<select name="fas_settings[default_priority]">';
<?php
// 文件路径: includes/class-settings.php
if (!defined('ABSPATH')) {
exit;
}
class FAS_Settings {
public function __construct() {
add_action('admin_init', array($this, 'register_settings'));
}
public function register_settings() {
register_setting('fas_settings_group', 'fas_settings', array($this, 'sanitize_settings'));
// 常规设置
add_settings_section(
'fas_general_section',
__('常规设置', 'flexible-after-sales'),
array($this, 'render_general_section'),
'fas_settings'
);
add_settings_field(
'email_notifications',
__('邮件通知', 'flexible-after-sales'),
array($this, 'render_email_notifications_field'),
'fas_settings',
'fas_general_section'
);
add_settings_field(
'support_email',
__('支持邮箱', 'flexible-after-sales'),
array($this, 'render_support_email_field'),
'fas_settings',
'fas_general_section'
);
add_settings_field(
'default_priority',
__('默认优先级', 'flexible-after-sales'),
array($this, 'render_default_priority_field'),
'fas_settings',
'fas_general_section'
);
// 高级设置
add_settings_section(
'fas_advanced_section',
__('高级设置', 'flexible-after-sales'),
array($this, 'render_advanced_section'),
'fas_settings'
);
add_settings_field(
'auto_assign',
__('自动分配', 'flexible-after-sales'),
array($this, 'render_auto_assign_field'),
'fas_settings',
'fas_advanced_section'
);
add_settings_field(
'allowed_users',
__('允许的管理员', 'flexible-after-sales'),
array($this, 'render_allowed_users_field'),
'fas_settings',
'fas_advanced_section'
);
}
public function sanitize_settings($input) {
$sanitized = array();
// 邮件通知
$sanitized['email_notifications'] = isset($input['email_notifications']) ? 1 : 0;
// 支持邮箱
$sanitized['support_email'] = sanitize_email($input['support_email']);
if (!is_email($sanitized['support_email'])) {
$sanitized['support_email'] = get_option('admin_email');
}
// 默认优先级
$sanitized['default_priority'] = absint($input['default_priority']);
if ($sanitized['default_priority'] < 1 || $sanitized['default_priority'] > 4) {
$sanitized['default_priority'] = 2;
}
// 自动分配
$sanitized['auto_assign'] = isset($input['auto_assign']) ? 1 : 0;
// 允许的用户
$sanitized['allowed_users'] = array();
if (isset($input['allowed_users']) && is_array($input['allowed_users'])) {
foreach ($input['allowed_users'] as $user_id) {
$user_id = absint($user_id);
if ($user_id > 0) {
$sanitized['allowed_users'][] = $user_id;
}
}
}
return $sanitized;
}
public function render_general_section() {
echo '<p>' . __('配置插件的基本设置', 'flexible-after-sales') . '</p>';
}
public function render_advanced_section() {
echo '<p>' . __('高级功能配置', 'flexible-after-sales') . '</p>';
}
public function render_email_notifications_field() {
$settings = get_option('fas_settings');
$checked = isset($settings['email_notifications']) && $settings['email_notifications'] ? 'checked' : '';
echo '<label>';
echo '<input type="checkbox" name="fas_settings[email_notifications]" value="1" ' . $checked . '>';
echo __('启用新请求邮件通知', 'flexible-after-sales');
echo '</label>';
echo '<p class="description">' . __('当有新服务请求时发送邮件通知', 'flexible-after-sales') . '</p>';
}
public function render_support_email_field() {
$settings = get_option('fas_settings');
$value = isset($settings['support_email']) ? $settings['support_email'] : get_option('admin_email');
echo '<input type="email" name="fas_settings[support_email]" value="' . esc_attr($value) . '" class="regular-text">';
echo '<p class="description">' . __('接收通知的邮箱地址', 'flexible-after-sales') . '</p>';
}
public function render_default_priority_field() {
$settings = get_option('fas_settings');
$value = isset($settings['default_priority']) ? $settings['default_priority'] : 2;
echo '<select name="fas_settings[default_priority]">';


