文章目录[隐藏]
一步步实现:为WordPress打造内部工单系统与客户支持门户
引言:为什么选择WordPress作为工单系统平台?
在当今数字化商业环境中,高效的客户支持和内部协作系统是企业成功的关键因素。许多企业每年花费大量资金购买第三方客户支持软件,如Zendesk、Freshdesk等,但这些解决方案往往价格昂贵且缺乏定制灵活性。
WordPress作为全球最流行的内容管理系统,占据了互联网上超过40%的网站份额。其强大的插件生态和开放源代码特性,使其成为构建定制化业务工具的绝佳平台。通过WordPress二次开发,我们可以以较低成本打造一个完全符合企业特定需求的内部工单系统与客户支持门户。
本文将详细介绍如何通过WordPress代码二次开发,实现一个功能完整的工单系统,同时集成多种常用互联网小工具,提升客户支持效率和团队协作能力。
第一章:项目规划与需求分析
1.1 确定系统核心功能
在开始开发前,我们需要明确工单系统的基本功能需求:
-
用户端功能:
- 用户注册与登录
- 工单提交表单
- 工单状态跟踪
- 历史工单查看
- 文件上传功能
- 实时通知系统
-
管理端功能:
- 工单分配与转交
- 优先级管理
- 分类与标签系统
- 知识库集成
- 团队绩效统计
- 自动化规则设置
-
系统集成需求:
- 电子邮件通知
- 实时聊天小工具
- 常见问题(FAQ)模块
- 客户满意度调查
- 报表与分析工具
1.2 技术架构设计
基于WordPress的工单系统将采用以下技术架构:
- 前端界面:使用WordPress主题模板系统,结合Bootstrap框架确保响应式设计
- 数据存储:利用WordPress自定义文章类型(CPT)存储工单数据
- 用户管理:扩展WordPress原生用户系统,添加支持人员角色
- 通信机制:结合AJAX实现无刷新交互,使用WP Mail函数处理邮件通知
- 安全措施:实施WordPress非ce验证、数据消毒和权限检查
第二章:搭建基础开发环境
2.1 创建自定义插件
首先,我们需要创建一个独立的插件来容纳所有工单系统功能:
<?php
/**
* Plugin Name: 企业工单与支持系统
* Plugin URI: https://yourcompany.com/
* Description: 基于WordPress的定制化工单与客户支持系统
* Version: 1.0.0
* Author: 您的公司
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('TICKET_SYSTEM_VERSION', '1.0.0');
define('TICKET_SYSTEM_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('TICKET_SYSTEM_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
require_once TICKET_SYSTEM_PLUGIN_DIR . 'includes/class-ticket-system.php';
function run_ticket_system() {
$plugin = new Ticket_System();
$plugin->run();
}
run_ticket_system();
2.2 创建自定义文章类型存储工单
在插件中创建自定义文章类型来存储工单信息:
class Ticket_System {
public function __construct() {
// 初始化钩子
add_action('init', array($this, 'register_ticket_post_type'));
add_action('init', array($this, 'register_ticket_taxonomies'));
}
public function register_ticket_post_type() {
$labels = array(
'name' => '工单',
'singular_name' => '工单',
'menu_name' => '工单系统',
'add_new' => '新建工单',
'add_new_item' => '添加新工单',
'edit_item' => '编辑工单',
'new_item' => '新工单',
'view_item' => '查看工单',
'search_items' => '搜索工单',
'not_found' => '未找到工单',
'not_found_in_trash' => '回收站中无工单'
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array('slug' => 'ticket'),
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'menu_position' => 5,
'menu_icon' => 'dashicons-tickets-alt',
'supports' => array('title', 'editor', 'author', 'comments'),
'show_in_rest' => true, // 启用Gutenberg编辑器支持
);
register_post_type('ticket', $args);
}
public function register_ticket_taxonomies() {
// 工单状态分类
register_taxonomy(
'ticket_status',
'ticket',
array(
'labels' => array(
'name' => '工单状态',
'singular_name' => '状态',
'search_items' => '搜索状态',
'all_items' => '所有状态',
'edit_item' => '编辑状态',
'update_item' => '更新状态',
'add_new_item' => '添加新状态',
'new_item_name' => '新状态名称',
'menu_name' => '状态'
),
'hierarchical' => true,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array('slug' => 'ticket-status'),
'default_terms' => array('open', 'in-progress', 'resolved', 'closed')
)
);
// 工单优先级分类
register_taxonomy(
'ticket_priority',
'ticket',
array(
'labels' => array(
'name' => '优先级',
'singular_name' => '优先级',
'search_items' => '搜索优先级',
'all_items' => '所有优先级',
'edit_item' => '编辑优先级',
'update_item' => '更新优先级',
'add_new_item' => '添加新优先级',
'new_item_name' => '新优先级名称',
'menu_name' => '优先级'
),
'hierarchical' => true,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array('slug' => 'ticket-priority'),
'default_terms' => array('low', 'medium', 'high', 'urgent')
)
);
}
}
第三章:构建用户前端界面
3.1 创建工单提交表单
在前端创建用户提交工单的表单:
class Ticket_Frontend {
public function __construct() {
add_shortcode('ticket_submission_form', array($this, 'render_ticket_form'));
add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_scripts'));
add_action('wp_ajax_submit_ticket', array($this, 'handle_ticket_submission'));
add_action('wp_ajax_nopriv_submit_ticket', array($this, 'handle_ticket_submission'));
}
public function render_ticket_form() {
// 检查用户是否登录
if (!is_user_logged_in()) {
return '<div class="ticket-login-required">请先<a href="' . wp_login_url(get_permalink()) . '">登录</a>以提交工单</div>';
}
ob_start();
?>
<div class="ticket-submission-container">
<h2>提交新工单</h2>
<form id="ticket-submission-form" method="post" enctype="multipart/form-data">
<?php wp_nonce_field('submit_ticket_action', 'ticket_nonce'); ?>
<div class="form-group">
<label for="ticket_title">问题标题 *</label>
<input type="text" id="ticket_title" name="ticket_title" required class="form-control" placeholder="简要描述您的问题">
</div>
<div class="form-group">
<label for="ticket_description">详细描述 *</label>
<textarea id="ticket_description" name="ticket_description" rows="6" required class="form-control" placeholder="请详细描述您遇到的问题,包括步骤、期望结果和实际结果"></textarea>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="ticket_category">问题分类</label>
<select id="ticket_category" name="ticket_category" class="form-control">
<option value="technical">技术问题</option>
<option value="billing">账单问题</option>
<option value="account">账户问题</option>
<option value="feature">功能建议</option>
<option value="other">其他</option>
</select>
</div>
<div class="form-group col-md-6">
<label for="ticket_priority">优先级</label>
<select id="ticket_priority" name="ticket_priority" class="form-control">
<option value="low">低 - 常规问题</option>
<option value="medium" selected>中 - 需要尽快解决</option>
<option value="high">高 - 严重影响使用</option>
<option value="urgent">紧急 - 系统完全无法使用</option>
</select>
</div>
</div>
<div class="form-group">
<label for="ticket_attachments">附件 (可选)</label>
<input type="file" id="ticket_attachments" name="ticket_attachments[]" multiple class="form-control-file">
<small class="form-text text-muted">支持图片、文档等格式,单个文件不超过5MB</small>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-submit-ticket">提交工单</button>
<div class="spinner-border text-primary d-none" role="status" id="ticket-submit-spinner">
<span class="sr-only">提交中...</span>
</div>
</div>
<div id="ticket-submission-response" class="alert d-none"></div>
</form>
</div>
<?php
return ob_get_clean();
}
public function handle_ticket_submission() {
// 验证nonce
if (!isset($_POST['ticket_nonce']) || !wp_verify_nonce($_POST['ticket_nonce'], 'submit_ticket_action')) {
wp_die('安全验证失败');
}
// 验证用户权限
if (!is_user_logged_in()) {
wp_send_json_error(array('message' => '请先登录'));
}
$current_user = wp_get_current_user();
// 准备工单数据
$ticket_data = array(
'post_title' => sanitize_text_field($_POST['ticket_title']),
'post_content' => wp_kses_post($_POST['ticket_description']),
'post_status' => 'publish',
'post_type' => 'ticket',
'post_author' => $current_user->ID,
'meta_input' => array(
'_ticket_category' => sanitize_text_field($_POST['ticket_category']),
'_ticket_priority' => sanitize_text_field($_POST['ticket_priority']),
'_ticket_status' => 'open'
)
);
// 插入工单
$ticket_id = wp_insert_post($ticket_data);
if (is_wp_error($ticket_id)) {
wp_send_json_error(array('message' => '创建工单失败: ' . $ticket_id->get_error_message()));
}
// 处理附件上传
$this->handle_attachments($ticket_id);
// 设置分类术语
wp_set_object_terms($ticket_id, sanitize_text_field($_POST['ticket_priority']), 'ticket_priority');
wp_set_object_terms($ticket_id, 'open', 'ticket_status');
// 发送通知邮件
$this->send_ticket_notification($ticket_id, $current_user);
wp_send_json_success(array(
'message' => '工单提交成功!',
'ticket_id' => $ticket_id,
'redirect_url' => add_query_arg('ticket_id', $ticket_id, get_permalink(get_page_by_path('my-tickets')))
));
}
}
3.2 创建用户工单管理面板
为用户创建查看和管理工单的面板:
class Ticket_Dashboard {
public function __construct() {
add_shortcode('ticket_dashboard', array($this, 'render_ticket_dashboard'));
}
public function render_ticket_dashboard() {
if (!is_user_logged_in()) {
return '<p>请先登录查看您的工单。</p>';
}
$current_user = wp_get_current_user();
$user_tickets = $this->get_user_tickets($current_user->ID);
ob_start();
?>
<div class="ticket-dashboard-container">
<h2>我的工单</h2>
<div class="dashboard-actions mb-4">
<a href="<?php echo get_permalink(get_page_by_path('submit-ticket')); ?>" class="btn btn-success">
<i class="fas fa-plus-circle"></i> 提交新工单
</a>
<button class="btn btn-outline-secondary" id="refresh-tickets">
<i class="fas fa-sync-alt"></i> 刷新列表
</button>
</div>
<div class="ticket-filters mb-3">
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-primary active" data-filter="all">全部</button>
<button type="button" class="btn btn-outline-warning" data-filter="open">进行中</button>
<button type="button" class="btn btn-outline-success" data-filter="resolved">已解决</button>
<button type="button" class="btn btn-outline-secondary" data-filter="closed">已关闭</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover ticket-table">
<thead>
<tr>
<th>工单ID</th>
<th>标题</th>
<th>状态</th>
<th>优先级</th>
<th>创建时间</th>
<th>最后更新</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php if (empty($user_tickets)): ?>
<tr>
<td colspan="7" class="text-center">暂无工单记录</td>
</tr>
<?php else: ?>
<?php foreach ($user_tickets as $ticket): ?>
<?php
$status = wp_get_post_terms($ticket->ID, 'ticket_status', array('fields' => 'names'));
$priority = wp_get_post_terms($ticket->ID, 'ticket_priority', array('fields' => 'names'));
$status_class = $this->get_status_class($status[0] ?? 'open');
$priority_class = $this->get_priority_class($priority[0] ?? 'medium');
?>
<tr class="ticket-row" data-status="<?php echo strtolower($status[0] ?? ''); ?>">
<td>#<?php echo $ticket->ID; ?></td>
<td>
<a href="<?php echo get_permalink($ticket->ID); ?>" class="ticket-title">
<?php echo esc_html($ticket->post_title); ?>
</a>
</td>
<td>
<span class="badge badge-<?php echo $status_class; ?>">
<?php echo $status[0] ?? 'Open'; ?>
</span>
</td>
<td>
<span class="badge badge-<?php echo $priority_class; ?>">
<?php echo $priority[0] ?? 'Medium'; ?>
</span>
</td>
<td><?php echo get_the_date('Y-m-d H:i', $ticket->ID); ?></td>
<td><?php echo get_the_modified_date('Y-m-d H:i', $ticket->ID); ?></td>
<td>
<a href="<?php echo get_permalink($ticket->ID); ?>" class="btn btn-sm btn-outline-primary">
<i class="fas fa-eye"></i> 查看
</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<div class="ticket-statistics mt-4 p-3 bg-light rounded">
<h5>工单统计</h5>
<div class="row">
<div class="col-md-3">
<div class="stat-box text-center">
<div class="stat-number"><?php echo count($user_tickets); ?></div>
<div class="stat-label">总工单数</div>
</div>
</div>
<div class="col-md-3">
<div class="stat-box text-center">
<div class="stat-number"><?php echo $this->count_tickets_by_status($user_tickets, 'open'); ?></div>
<div class="stat-label">进行中</div>
</div>
</div>
<div class="col-md-3">
<div class="stat-box text-center">
<div class="stat-number"><?php echo $this->count_tickets_by_status($user_tickets, 'resolved'); ?></div>
<div class="stat-label">已解决</div>
</div>
</div>
<div class="col-md-3">
<div class="stat-box text-center">
<div class="stat-number"><?php echo $this->count_tickets_by_status($user_tickets, 'closed'); ?></div>
<div class="stat-label">已关闭</div>
</div>
</div>
</div>
</div>
</div>
<script>
jQuery(document).ready(function($) {
// 工单筛选功能
$('.ticket-filters button').on('click', function() {
var filter = $(this).data('filter');
// 更新按钮状态
$('.ticket-filters button').removeClass('active');
$(this).addClass('active');
// 筛选工单行
if (filter === 'all') {
$('.ticket-row').show();
} else {
$('.ticket-row').hide();
$('.ticket-row[data-status="' + filter + '"]').show();
}
});
// 刷新工单列表
$('#refresh-tickets').on('click', function() {
location.reload();
});
});
</script>
<?php
return ob_get_clean();
}
private function get_user_tickets($user_id) {
$args = array(
'post_type' => 'ticket',
'author' => $user_id,
'posts_per_page' => -1,
'orderby' => 'date',
'order' => 'DESC'
);
return get_posts($args);
}
private function count_tickets_by_status($tickets, $status) {
$count = 0;
foreach ($tickets as $ticket) {
$ticket_status = wp_get_post_terms($ticket->ID, 'ticket_status', array('fields' => 'names'));
if (!empty($ticket_status) && strtolower($ticket_status[0]) === $status) {
$count++;
}
}
return $count;
}
private function get_status_class($status) {
$status = strtolower($status);
switch ($status) {
case 'open':
return 'warning';
case 'in-progress':
return 'info';
case 'resolved':
return 'success';
case 'closed':
return 'secondary';
default:
return 'light';
}
}
private function get_priority_class($priority) {
$priority = strtolower($priority);
switch ($priority) {
case 'low':
return 'info';
case 'medium':
return 'primary';
case 'high':
return 'warning';
case 'urgent':
return 'danger';
default:
return 'light';
}
}
}
## 第四章:构建管理后台功能
### 4.1 创建工单管理界面
为支持团队创建专门的管理界面:
class Ticket_Admin {
public function __construct() {
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
add_filter('manage_ticket_posts_columns', array($this, 'add_ticket_columns'));
add_action('manage_ticket_posts_custom_column', array($this, 'manage_ticket_columns'), 10, 2);
add_action('add_meta_boxes', array($this, 'add_ticket_meta_boxes'));
add_action('save_post_ticket', array($this, 'save_ticket_meta'));
}
public function add_admin_menu() {
add_menu_page(
'工单系统',
'工单系统',
'manage_options',
'ticket-system',
array($this, 'render_admin_dashboard'),
'dashicons-tickets-alt',
30
);
add_submenu_page(
'ticket-system',
'工单统计',
'统计报表',
'manage_options',
'ticket-statistics',
array($this, 'render_statistics_page')
);
add_submenu_page(
'ticket-system',
'系统设置',
'设置',
'manage_options',
'ticket-settings',
array($this, 'render_settings_page')
);
}
public function render_admin_dashboard() {
global $wpdb;
// 获取统计数据
$total_tickets = wp_count_posts('ticket');
$open_tickets = $total_tickets->publish ?? 0;
// 获取最近工单
$recent_tickets = get_posts(array(
'post_type' => 'ticket',
'posts_per_page' => 10,
'orderby' => 'date',
'order' => 'DESC'
));
// 获取支持人员绩效
$support_performance = $this->get_support_performance();
ob_start();
?>
<div class="wrap ticket-admin-dashboard">
<h1 class="wp-heading-inline">工单系统仪表板</h1>
<div class="dashboard-widgets">
<div class="row">
<div class="col-md-3">
<div class="card text-white bg-primary mb-3">
<div class="card-body">
<h5 class="card-title">总工单数</h5>
<p class="card-text display-4"><?php echo array_sum((array)$total_tickets); ?></p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-warning mb-3">
<div class="card-body">
<h5 class="card-title">进行中</h5>
<p class="card-text display-4"><?php echo $open_tickets; ?></p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-success mb-3">
<div class="card-body">
<h5 class="card-title">已解决</h5>
<p class="card-text display-4"><?php echo $total_tickets->resolved ?? 0; ?></p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-info mb-3">
<div class="card-body">
<h5 class="card-title">平均响应时间</h5>
<p class="card-text display-4"><?php echo $this->get_average_response_time(); ?>h</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div class="card mb-3">
<div class="card-header">
<h5>最近工单</h5>
</div>
<div class="card-body">
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>标题</th>
<th>客户</th>
<th>状态</th>
<th>分配至</th>
<th>创建时间</th>
</tr>
</thead>
<tbody>
<?php foreach ($recent_tickets as $ticket): ?>
<?php
$author = get_userdata($ticket->post_author);
$assigned_to = get_post_meta($ticket->ID, '_ticket_assigned_to', true);
$assigned_user = $assigned_to ? get_userdata($assigned_to) : null;
$status = wp_get_post_terms($ticket->ID, 'ticket_status', array('fields' => 'names'));
?>
<tr>
<td>#<?php echo $ticket->ID; ?></td>
<td>
<a href="<?php echo get_edit_post_link($ticket->ID); ?>">
<?php echo esc_html($ticket->post_title); ?>
</a>
</td>
<td><?php echo $author ? $author->display_name : '未知用户'; ?></td>
<td>
<span class="badge badge-<?php echo $this->get_status_class($status[0] ?? 'open'); ?>">
<?php echo $status[0] ?? 'Open'; ?>
</span>
</td>
<td>
<?php if ($assigned_user): ?>
<?php echo $assigned_user->display_name; ?>
<?php else: ?>
<span class="text-muted">未分配</span>
<?php endif; ?>
</td>
<td><?php echo get_the_date('m-d H:i', $ticket->ID); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card mb-3">
<div class="card-header">
<h5>支持人员绩效</h5>
</div>
<div class="card-body">
<table class="table table-sm">
<thead>
<tr>
<th>姓名</th>
<th>处理数</th>
<th>解决率</th>
</tr>
</thead>
<tbody>
<?php foreach ($support_performance as $performance): ?>
<tr>
<td><?php echo $performance['name']; ?></td>
<td><?php echo $performance['ticket_count']; ?></td>
<td>
<div class="progress">
<div class="progress-bar" role="progressbar"
style="width: <?php echo $performance['resolution_rate']; ?>%">
<?php echo number_format($performance['resolution_rate'], 1); ?>%
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="card">
<div class="card-header">
<h5>快速操作</h5>
</div>
<div class="card-body">
<a href="<?php echo admin_url('post-new.php?post_type=ticket'); ?>" class="btn btn-primary btn-block mb-2">
创建新工单
</a>
<a href="<?php echo admin_url('edit.php?post_type=ticket'); ?>" class="btn btn-secondary btn-block mb-2">
查看所有工单
</a>
<a href="<?php echo admin_url('admin.php?page=ticket-statistics'); ?>" class="btn btn-info btn-block">
查看详细统计
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<?php
echo ob_get_clean();
}
private function get_support_performance() {
// 获取所有支持人员
$support_users = get_users(array(
'role__in' => array('administrator', 'editor', 'support_agent'),
'fields' => array('ID', 'display_name')
));
$performance_data = array();
foreach ($support_users as $user) {
// 获取分配给该用户的工单
$assigned_tickets = get_posts(array(
'post_type' => 'ticket',
'meta_key' => '_ticket_assigned_to',
'meta_value' => $user->ID,
'posts_per_page' => -1
));
$resolved_count = 0;
foreach ($assigned_tickets as $ticket) {
$status = wp_get_post_terms($ticket->ID, 'ticket_status', array('fields' => 'names'));
if (!empty($status) && in_array(strtolower($status[0]), array('resolved', 'closed'))) {
$resolved_count++;
}
}
$total_count = count($assigned_tickets);
$resolution_rate = $total_count > 0 ? ($resolved_count / $total_count) * 100 : 0;
$performance_data[] = array(
'name' => $user->display_name,
'ticket_count' => $total_count,
'resolved_count' => $resolved_count,
'resolution_rate' => $resolution_rate
);
}
return $performance_data;
}
}
### 4.2 添加工单分配与跟踪功能
class Ticket_Assignment {
public function __construct() {
add_action('add_meta_boxes_ticket', array($this, 'add_assignment_meta_box'));
add_action('wp_ajax_assign_ticket', array($this, 'handle_ticket_assignment'));
add_action('wp_ajax_get_available_agents', array($this, 'get_available_agents'));
}
public function add_assignment_meta_box() {
add_meta_box(
'ticket_assignment',
'工单分配',
array($this, 'render_assignment_meta_box'),
'ticket',
'side',
'high'
);
}
public function render_assignment_meta_box($post) {
$assigned_to = get_post_meta($post->ID, '_ticket_assigned_to', true);
$current_assignee = $assigned_to ? get_userdata($assigned_to) : null;
// 获取可分配的支持人员
$available_agents = get_users(array(
'role__in' => array('administrator', 'editor', 'support_agent'),
'fields' => array('ID', 'display_name', 'user_email')
));
wp_nonce_field('assign_ticket_action', 'assignment_nonce');
?>
<div class="ticket-assignment-container">
<div class="current-assignee mb-3">
<strong>当前负责人:</strong>
<?php if ($current_assignee): ?>
<div class="assignee-info mt-1 p-2 bg-light rounded">
<div class="d-flex align-items-center">
<div class="assignee-avatar mr-2">
<?php echo get_avatar($current_assignee->ID, 32); ?>
</div>
<div>
<div class="assignee-name"><?php echo $current_assignee->display_name; ?></div>
<div class="assignee-email text-muted small"><?php echo $current_assignee->user_email; ?></div>
</div>
</div>
</div>
<?php else: ?>
<div class="text-muted mt-1">未分配</div>
<?php endif; ?>
</div>
<div class="assignment-form">
<label for="assign_to"><strong>分配给:</strong></label>
<select id="assign_to" name="assign_to" class="form-control">
<option value="">选择支持人员...</option>
<?php foreach ($available_agents as $agent): ?>
<option value="<?php echo $agent->ID; ?>" <?php selected($assigned_to, $agent->ID); ?>>
<?php echo $agent->display_name; ?> (<?php echo $agent->user_email; ?>)
</option>
<?php endforeach; ?>
</select>
<div class="assignment-actions mt-3">
<button type="button" class="button button-primary" id="assign-ticket-btn">
分配工单
</button>
<?php if ($assigned_to): ?>
<button type="button" class="button button-link" id="unassign-ticket-btn">
取消分配
</button>
<?php endif; ?>
</div>
<div class="assignment-history mt-3">
<strong>分配历史:</strong>
<?php $this->display_assignment_history($post->ID); ?>
</div>
</div>
<div id="assignment-response" class="mt-2"></div>
</div>
<script>
jQuery(document).ready(function($) {
$('#assign-ticket-btn').on('click', function() {
var ticketId = <?php echo $post->ID; ?>;
var assignTo = $('#assign_to').val();
var nonce = $('#assignment_nonce').val();
if (!assignTo) {
alert('请选择要分配的支持人员');
return;
}
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'assign_ticket',
ticket_id: ticketId,
assign_to: assignTo,
nonce: nonce
},
beforeSend: function() {
$('#assign-ticket-btn').prop('disabled', true).text('分配中...');
},
success: function(response) {
if (response.success) {
$('#assignment-response').html('<div class="notice notice-success"><p>' + response.data.message + '</p></div>');
location.reload();
} else {
$('#assignment-response').html('<div class="notice notice-error"><p>' + response.data.message + '</p></div>');
}
},
complete: function() {
$('#assign-ticket-btn').prop('disabled', false).text('分配工单');
}
});
});
});
</script>
<?php
}
public function handle_ticket_assignment() {
// 验证nonce和权限
if (!check_ajax_referer('assign_ticket_action', 'nonce', false)) {
wp_send_json_error(array('
