文章目录[隐藏]
实操指南:构建售后与退货处理接口的3个周全方法
引言:售后接口在电商系统中的重要性
在当今竞争激烈的电商环境中,完善的售后与退货处理系统不仅是提升客户满意度的关键,更是企业运营效率的重要保障。根据Statista的数据显示,超过60%的在线购物者在购买前会查看退货政策,而高效的退货处理可以将客户保留率提高30%以上。
对于使用WordPress构建电商网站的开发者和企业来说,构建一个稳定、高效的售后与退货处理接口尤为重要。WordPress作为全球最流行的内容管理系统,配合WooCommerce等电商插件,为开发者提供了强大的基础框架。然而,标准解决方案往往无法满足企业的个性化需求,这就需要我们深入代码层面,构建定制化的售后接口。
本文将基于WordPress开源系统,为行业新人和程序员提供三种周全的售后与退货处理接口构建方法,从基础到高级,逐步深入。
方法一:基于WooCommerce原生功能的扩展开发
1.1 WooCommerce售后系统基础架构分析
WooCommerce作为WordPress最流行的电商插件,已经内置了基本的订单管理和退款功能。要构建售后接口,首先需要理解其核心数据结构:
// WooCommerce订单退款相关的主要数据表
// wp_woocommerce_order_items - 订单项目
// wp_woocommerce_order_itemmeta - 订单项目元数据
// wp_posts (post_type = 'shop_order') - 订单主数据
// wp_postmeta - 订单元数据
// wp_comments (comment_type = 'order_note') - 订单备注/历史
// 退款创建的基本流程
function create_woocommerce_refund($order_id, $amount, $reason) {
$order = wc_get_order($order_id);
// 创建退款对象
$refund = wc_create_refund(array(
'amount' => $amount,
'reason' => $reason,
'order_id' => $order_id,
'refund_payment' => true, // 是否退款到支付方式
'restock_items' => true // 是否恢复库存
));
return $refund;
}
1.2 创建基础的售后请求处理接口
基于WooCommerce原生功能,我们可以构建一个基础的售后请求处理接口:
/**
* 售后请求处理类
*/
class Basic_After_Sales_Handler {
private $request_types = array('refund', 'return', 'exchange', 'repair');
/**
* 初始化售后系统
*/
public function init() {
// 注册售后请求自定义帖子类型
add_action('init', array($this, 'register_after_sales_post_type'));
// 添加REST API端点
add_action('rest_api_init', array($this, 'register_rest_endpoints'));
// 添加管理界面
add_action('admin_menu', array($this, 'add_admin_menu'));
}
/**
* 注册售后请求自定义帖子类型
*/
public function register_after_sales_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' => false,
'publicly_queryable' => false,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array('slug' => 'after-sales'),
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => false,
'menu_position' => 56,
'menu_icon' => 'dashicons-undo',
'supports' => array('title', 'editor', 'author', 'custom-fields'),
'show_in_rest' => true // 启用REST API支持
);
register_post_type('after_sales_request', $args);
// 注册售后状态分类
register_taxonomy(
'after_sales_status',
'after_sales_request',
array(
'label' => '售后状态',
'rewrite' => array('slug' => 'after-sales-status'),
'hierarchical' => true,
'show_in_rest' => true
)
);
}
/**
* 注册REST API端点
*/
public function register_rest_endpoints() {
// 创建售后请求端点
register_rest_route('after-sales/v1', '/request', array(
'methods' => 'POST',
'callback' => array($this, 'handle_after_sales_request'),
'permission_callback' => array($this, 'check_request_permission'),
'args' => array(
'order_id' => array(
'required' => true,
'validate_callback' => function($param) {
return is_numeric($param) && $param > 0;
}
),
'request_type' => array(
'required' => true,
'validate_callback' => function($param) {
$allowed_types = array('refund', 'return', 'exchange', 'repair');
return in_array($param, $allowed_types);
}
),
'reason' => array(
'required' => true,
'sanitize_callback' => 'sanitize_text_field'
),
'items' => array(
'required' => false,
'validate_callback' => function($param) {
return is_array($param);
}
)
)
));
// 获取售后请求状态端点
register_rest_route('after-sales/v1', '/status/(?P<id>d+)', array(
'methods' => 'GET',
'callback' => array($this, 'get_request_status'),
'permission_callback' => function() {
return current_user_can('read');
}
));
}
/**
* 处理售后请求
*/
public function handle_after_sales_request($request) {
$parameters = $request->get_params();
// 验证订单是否存在且属于当前用户
$order = wc_get_order($parameters['order_id']);
if (!$order) {
return new WP_Error('invalid_order', '订单不存在', array('status' => 404));
}
// 检查用户权限
$user_id = get_current_user_id();
if ($order->get_customer_id() !== $user_id && !current_user_can('manage_woocommerce')) {
return new WP_Error('permission_denied', '无权访问此订单', array('status' => 403));
}
// 创建售后请求记录
$request_id = wp_insert_post(array(
'post_title' => sprintf('售后请求 - 订单 #%s', $parameters['order_id']),
'post_content' => $parameters['reason'],
'post_status' => 'publish',
'post_type' => 'after_sales_request',
'post_author' => $user_id,
'meta_input' => array(
'_order_id' => $parameters['order_id'],
'_request_type' => $parameters['request_type'],
'_status' => 'pending',
'_request_date' => current_time('mysql')
)
));
// 添加请求物品信息
if (!empty($parameters['items']) && is_array($parameters['items'])) {
update_post_meta($request_id, '_request_items', $parameters['items']);
}
// 发送通知邮件
$this->send_notification_email($order, $request_id, $parameters);
// 记录操作日志
$order->add_order_note(sprintf('客户提交了%s请求,原因:%s',
$this->get_request_type_name($parameters['request_type']),
$parameters['reason']
));
return array(
'success' => true,
'request_id' => $request_id,
'message' => '售后请求已提交,我们将在24小时内处理'
);
}
/**
* 发送通知邮件
*/
private function send_notification_email($order, $request_id, $parameters) {
$to = get_option('admin_email');
$subject = sprintf('新的售后请求 #%s - 订单 #%s', $request_id, $order->get_id());
$message = sprintf(
"收到新的售后请求:nn请求ID:%sn订单号:%sn请求类型:%sn原因:%sn客户:%snn请登录后台查看详情。",
$request_id,
$order->get_id(),
$this->get_request_type_name($parameters['request_type']),
$parameters['reason'],
$order->get_billing_first_name() . ' ' . $order->get_billing_last_name()
);
wp_mail($to, $subject, $message);
}
}
1.3 实现前端用户界面
为了让用户能够方便地提交售后请求,我们需要创建一个前端界面:
/**
* 前端售后请求表单
*/
function after_sales_request_form($order_id = null) {
// 如果未提供订单ID,尝试从URL参数获取
if (!$order_id && isset($_GET['order_id'])) {
$order_id = intval($_GET['order_id']);
}
// 验证订单
if (!$order_id) {
return '<div class="alert alert-danger">请提供有效的订单号</div>';
}
$order = wc_get_order($order_id);
if (!$order) {
return '<div class="alert alert-danger">订单不存在</div>';
}
// 检查当前用户是否有权访问此订单
$user_id = get_current_user_id();
if ($order->get_customer_id() !== $user_id && !current_user_can('manage_woocommerce')) {
return '<div class="alert alert-danger">您无权访问此订单</div>';
}
// 检查订单是否在可售后时间内(例如30天内)
$order_date = $order->get_date_created();
$current_date = new DateTime();
$order_age = $current_date->diff($order_date)->days;
if ($order_age > 30) {
return '<div class="alert alert-warning">此订单已超过30天售后期限</div>';
}
ob_start();
?>
<div class="after-sales-request-form">
<h3>提交售后请求 - 订单 #<?php echo $order->get_id(); ?></h3>
<form id="after-sales-request-form" method="post">
<input type="hidden" name="order_id" value="<?php echo $order->get_id(); ?>">
<div class="form-group">
<label for="request_type">请求类型 *</label>
<select name="request_type" id="request_type" required class="form-control">
<option value="">请选择请求类型</option>
<option value="refund">仅退款</option>
<option value="return">退货退款</option>
<option value="exchange">换货</option>
<option value="repair">维修</option>
</select>
</div>
<div class="form-group">
<label for="reason">问题描述 *</label>
<textarea name="reason" id="reason" rows="5" required class="form-control"
placeholder="请详细描述您遇到的问题..."></textarea>
</div>
<div class="form-group">
<label>选择需要售后的商品</label>
<div class="order-items-list">
<?php foreach ($order->get_items() as $item_id => $item): ?>
<div class="order-item-checkbox">
<label>
<input type="checkbox" name="items[]" value="<?php echo $item_id; ?>">
<?php echo $item->get_name(); ?> × <?php echo $item->get_quantity(); ?>
</label>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">提交请求</button>
</div>
<div id="form-message" class="alert" style="display:none;"></div>
</form>
</div>
<script>
jQuery(document).ready(function($) {
$('#after-sales-request-form').on('submit', function(e) {
e.preventDefault();
var formData = $(this).serialize();
// 显示加载状态
$('#form-message').removeClass('alert-success alert-danger')
.addClass('alert-info')
.html('正在提交,请稍候...')
.show();
$.ajax({
url: '<?php echo rest_url('after-sales/v1/request'); ?>',
method: 'POST',
data: formData,
beforeSend: function(xhr) {
xhr.setRequestHeader('X-WP-Nonce', '<?php echo wp_create_nonce('wp_rest'); ?>');
},
success: function(response) {
if (response.success) {
$('#form-message').removeClass('alert-info alert-danger')
.addClass('alert-success')
.html('请求提交成功!' + response.message)
.show();
$('#after-sales-request-form')[0].reset();
} else {
$('#form-message').removeClass('alert-info alert-success')
.addClass('alert-danger')
.html('提交失败:' + response.message)
.show();
}
},
error: function(xhr, status, error) {
var message = '请求失败,请稍后重试';
if (xhr.responseJSON && xhr.responseJSON.message) {
message = xhr.responseJSON.message;
}
$('#form-message').removeClass('alert-info alert-success')
.addClass('alert-danger')
.html(message)
.show();
}
});
});
});
</script>
<?php
return ob_get_clean();
}
// 注册短代码
add_shortcode('after_sales_form', 'after_sales_request_form');
方法二:构建模块化、可扩展的售后系统
2.1 设计模块化架构
对于需要更复杂功能的企业,我们需要构建一个模块化的售后系统:
/**
* 模块化售后系统主类
*/
class Modular_After_Sales_System {
private $modules = array();
private $settings = array();
/**
* 初始化系统
*/
public function init() {
// 加载配置
$this->load_settings();
// 注册核心模块
$this->register_core_modules();
// 允许第三方模块注册
do_action('after_sales_system_init', $this);
// 初始化所有模块
$this->initialize_modules();
}
/**
* 加载设置
*/
private function load_settings() {
$defaults = array(
'return_period' => 30,
'refund_methods' => array('original', 'credit'),
'auto_approve_threshold' => 100, // 自动审批金额阈值
'enable_partial_refunds' => true,
'restock_on_return' => true
);
$this->settings = wp_parse_args(
get_option('after_sales_settings', array()),
$defaults
);
}
/**
* 注册核心模块
*/
private function register_core_modules() {
// 请求管理模块
$this->register_module('request_manager', new Request_Manager_Module());
// 退款处理模块
$this->register_module('refund_processor', new Refund_Processor_Module());
// 物流跟踪模块
$this->register_module('logistics_tracker', new Logistics_Tracker_Module());
// 通知系统模块
$this->register_module('notification_system', new Notification_System_Module());
// 数据分析模块
$this->register_module('analytics', new Analytics_Module());
}
/**
* 注册模块
*/
public function register_module($module_id, $module_instance) {
if (isset($this->modules[$module_id])) {
error_log(sprintf('售后系统模块 %s 已注册', $module_id));
return false;
}
$this->modules[$module_id] = $module_instance;
return true;
}
/**
* 获取模块
*/
public function get_module($module_id) {
return isset($this->modules[$module_id]) ? $this->modules[$module_id] : null;
}
}
/**
* 请求管理模块
*/
class Request_Manager_Module {
private $status_flow = array(
'pending' => array('processing', 'cancelled'),
'processing' => array('approved', 'rejected', 'cancelled'),
'approved' => array('refunded', 'exchanged', 'completed'),
'rejected' => array(),
'cancelled' => array(),
'refunded' => array('completed'),
'exchanged' => array('completed'),
'completed' => array()
);
/**
* 处理状态转换
*/
public function change_request_status($request_id, $new_status, $notes = '') {
$current_status = get_post_meta($request_id, '_status', true);
// 检查状态转换是否有效
if (!isset($this->status_flow[$current_status]) ||
!in_array($new_status, $this->status_flow[$current_status])) {
return new WP_Error('invalid_status_transition',
sprintf('无法从状态 %s 转换到 %s', $current_status, $new_status));
}
// 更新状态
update_post_meta($request_id, '_status', $new_status);
// 记录状态变更历史
$this->add_status_history($request_id, $current_status, $new_status, $notes);
// 触发状态变更钩子
do_action('after_sales_request_status_changed', $request_id, $current_status, $new_status, $notes);
return true;
}
/**
* 添加状态历史记录
*/
private function add_status_history($request_id, $from_status, $to_status, $notes) {
$history = get_post_meta($request_id, '_status_history', true);
if (!is_array($history)) {
$history = array();
}
$history[] = array(
'from' => $from_status,
'to' => $to_status,
'timestamp' => current_time('mysql'),
'user_id' => get_current_user_id(),
'notes' => $notes
);
update_post_meta($request_id, '_status_history', $history);
}
}
/**
* 退款处理模块
*/
class Refund_Processor_Module {
/**
* 处理退款请求
*/
public function process_refund($request_id) {
$request = get_post($request_id);
if (!$request || $request->post_type !== 'after_sales_request') {
return new WP_Error('invalid_request', '无效的售后请求');
}
$order_id = get_post_meta($request_id, '_order_id', true);
$order = wc_get_order($order_id);
if (!$order) {
return new WP_Error('invalid_order', '订单不存在');
}
// 获取退款金额
$refund_amount = $this->calculate_refund_amount($request_id, $order);
// 创建退款
$refund = wc_create_refund(array(
'amount' => $refund_amount,
'reason' => get_post_meta($request_id, '_reason', true),
'order_id' => $order_id,
'refund_payment' => true,
'restock_items' => $this->should_restock_items($request_id)
));
if (is_wp_error($refund)) {
return $refund;
}
// 更新请求状态
update_post_meta($request_id, '_refund_id', $refund->get_id());
update_post_meta($request_id, '_refund_amount', $refund_amount);
update_post_meta($request_id, '_refund_date', current_time('mysql'));
return $refund->get_id();
}
/**
* 计算退款金额
*/
private function calculate_refund_amount($request_id, $order) {
$request_type = get_post_meta($request_id, '_request_type', true);
$request_items = get_post_meta($request_id, '_request_items', true);
// 如果是全额退款
if (empty($request_items)) {
return $order->get_total();
}
// 计算部分退款金额
$refund_amount = 0;
foreach ($request_items as $item_id) {
$item = $order->get_item($item_id);
if ($item) {
$refund_amount += $item->get_total();
}
}
// 考虑运费和税费
$refund_amount = $this->adjust_for_fees_and_taxes($refund_amount, $order, $request_items);
return $refund_amount;
}
}
/**
* 物流跟踪模块
*/
class Logistics_Tracker_Module {
/**
* 添加快递跟踪信息
*/
public function add_tracking_info($request_id, $carrier, $tracking_number, $shipping_date = null) {
$tracking_info = array(
'carrier' => $carrier,
'tracking_number' => $tracking_number,
'shipping_date' => $shipping_date ?: current_time('mysql'),
'status' => 'shipped',
'last_updated' => current_time('mysql')
);
update_post_meta($request_id, '_tracking_info', $tracking_info);
// 调用快递API获取实时跟踪信息
$this->update_tracking_status($request_id, $carrier, $tracking_number);
return true;
}
/**
* 更新跟踪状态
*/
private function update_tracking_status($request_id, $carrier, $tracking_number) {
// 这里可以集成第三方快递API,如快递鸟、快递100等
$api_response = $this->call_carrier_api($carrier, $tracking_number);
if ($api_response && isset($api_response['status'])) {
update_post_meta($request_id, '_tracking_status', $api_response['status']);
update_post_meta($request_id, '_tracking_details', $api_response['details']);
}
}
}
2.2 实现RESTful API接口
/**
* RESTful API接口类
*/
class After_Sales_REST_API {
/**
* 注册所有API端点
*/
public function register_endpoints() {
// 批量获取售后请求
register_rest_route('after-sales/v2', '/requests', array(
array(
'methods' => 'GET',
'callback' => array($this, 'get_requests'),
'permission_callback' => array($this, 'check_admin_permission'),
'args' => $this->get_collection_params()
),
array(
'methods' => 'POST',
'callback' => array($this, 'create_request'),
'permission_callback' => array($this, 'check_create_permission')
)
));
// 单个售后请求操作
register_rest_route('after-sales/v2', '/requests/(?P<id>d+)', array(
array(
'methods' => 'GET',
'callback' => array($this, 'get_request'),
'permission_callback' => array($this, 'check_request_permission')
),
array(
'methods' => 'PUT',
'callback' => array($this, 'update_request'),
'permission_callback' => array($this, 'check_admin_permission')
),
array(
'methods' => 'DELETE',
'callback' => array($this, 'delete_request'),
'permission_callback' => array($this, 'check_admin_permission')
)
));
// 状态操作
register_rest_route('after-sales/v2', '/requests/(?P<id>d+)/status', array(
'methods' => 'PUT',
'callback' => array($this, 'update_status'),
'permission_callback' => array($this, 'check_admin_permission')
));
// 退款操作
register_rest_route('after-sales/v2', '/requests/(?P<id>d+)/refund', array(
'methods' => 'POST',
'callback' => array($this, 'process_refund'),
'permission_callback' => array($this, 'check_admin_permission')
));
// 统计信息
register_rest_route('after-sales/v2', '/stats', array(
'methods' => 'GET',
'callback' => array($this, 'get_statistics'),
'permission_callback' => array($this, 'check_admin_permission')
));
}
/**
* 获取售后请求列表
*/
public function get_requests($request) {
$params = $request->get_params();
$args = array(
'post_type' => 'after_sales_request',
'post_status' => 'publish',
'posts_per_page' => isset($params['per_page']) ? intval($params['per_page']) : 10,
'paged' => isset($params['page']) ? intval($params['page']) : 1
);
// 添加过滤条件
if (!empty($params['status'])) {
$args['meta_query'][] = array(
'key' => '_status',
'value' => $params['status']
);
}
if (!empty($params['order_id'])) {
$args['meta_query'][] = array(
'key' => '_order_id',
'value' => intval($params['order_id'])
);
}
if (!empty($params['customer_id'])) {
$args['author'] = intval($params['customer_id']);
}
if (!empty($params['date_from'])) {
$args['date_query'][] = array(
'after' => $params['date_from'],
'inclusive' => true
);
}
if (!empty($params['date_to'])) {
$args['date_query'][] = array(
'before' => $params['date_to'],
'inclusive' => true
);
}
$query = new WP_Query($args);
$requests = array();
foreach ($query->posts as $post) {
$requests[] = $this->prepare_request_data($post);
}
$response = new WP_REST_Response($requests);
// 添加分页头信息
$total = $query->found_posts;
$total_pages = ceil($total / $args['posts_per_page']);
$response->header('X-WP-Total', $total);
$response->header('X-WP-TotalPages', $total_pages);
return $response;
}
/**
* 准备请求数据
*/
private function prepare_request_data($post) {
$meta = get_post_meta($post->ID);
$data = array(
'id' => $post->ID,
'title' => $post->post_title,
'description' => $post->post_content,
'date' => $post->post_date,
'customer_id' => $post->post_author,
'order_id' => isset($meta['_order_id'][0]) ? $meta['_order_id'][0] : null,
'request_type' => isset($meta['_request_type'][0]) ? $meta['_request_type'][0] : null,
'status' => isset($meta['_status'][0]) ? $meta['_status'][0] : 'pending',
'items' => isset($meta['_request_items'][0]) ? maybe_unserialize($meta['_request_items'][0]) : array(),
'refund_amount' => isset($meta['_refund_amount'][0]) ? $meta['_refund_amount'][0] : null,
'tracking_info' => isset($meta['_tracking_info'][0]) ? maybe_unserialize($meta['_tracking_info'][0]) : null,
'status_history' => isset($meta['_status_history'][0]) ? maybe_unserialize($meta['_status_history'][0]) : array()
);
// 获取客户信息
$customer = get_userdata($post->post_author);
if ($customer) {
$data['customer'] = array(
'name' => $customer->display_name,
'email' => $customer->user_email
);
}
// 获取订单信息
if ($data['order_id']) {
$order = wc_get_order($data['order_id']);
if ($order) {
$data['order'] = array(
'total' => $order->get_total(),
'currency' => $order->get_currency(),
'date' => $order->get_date_created()->date('Y-m-d H:i:s')
);
}
}
return $data;
}
/**
* 处理退款
*/
public function process_refund($request) {
$request_id = $request['id'];
$parameters = $request->get_params();
$refund_processor = $GLOBALS['after_sales_system']->get_module('refund_processor');
if (!$refund_processor) {
return new WP_Error('module_not_found', '退款处理模块未找到', array('status' => 500));
}
$result = $refund_processor->process_refund($request_id);
if (is_wp_error($result)) {
return $result;
}
return array(
'success' => true,
'refund_id' => $result,
'message' => '退款处理成功'
);
}
/**
* 获取统计信息
*/
public function get_statistics($request) {
$params = $request->get_params();
$period = isset($params['period']) ? $params['period'] : 'month'; // day, week, month, year
$stats = array(
'total_requests' => $this->get_total_requests($period),
'by_status' => $this->get_requests_by_status($period),
'by_type' => $this->get_requests_by_type($period),
'refund_amount' => $this->get_refund_amount($period),
'processing_time' => $this->get_average_processing_time($period)
);
return $stats;
}
/**
* 获取请求总数
*/
private function get_total_requests($period) {
$date_query = $this->get_date_query_for_period($period);
$args = array(
'post_type' => 'after_sales_request',
'post_status' => 'publish',
'date_query' => $date_query,
'fields' => 'ids',
'posts_per_page' => -1
);
$query = new WP_Query($args);
return $query->found_posts;
}
}
2.3 实现后台管理界面
/**
* 后台管理界面
*/
class After_Sales_Admin_Interface {
/**
* 初始化管理界面
*/
public function init() {
add_action('admin_menu', array($this, 'add_admin_pages'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
add_action('add_meta_boxes', array($this, 'add_meta_boxes'));
add_action('save_post_after_sales_request', array($this, 'save_request_meta'));
// 添加列表页列
add_filter('manage_after_sales_request_posts_columns', array($this, 'add_custom_columns'));
add_action('manage_after_sales_request_posts_custom_column', array($this, 'render_custom_columns'), 10, 2);
add_filter('manage_edit-after_sales_request_sortable_columns', array($this, 'make_columns_sortable'));
}
/**
* 添加管理页面
*/
public function add_admin_pages() {
// 主菜单
add_menu_page(
'售后管理',
'售后管理',
'manage_woocommerce',
'after-sales',
array($this, 'render_dashboard'),
'dashicons-undo',
56
);
// 子菜单
add_submenu_page(
'after-sales',
'售后仪表盘',
'仪表盘',
'manage_woocommerce',
'after-sales',
array($this, 'render_dashboard')
);
add_submenu_page(
'after-sales',
'售后请求',
'所有请求',
'manage_woocommerce',
'edit.php?post_type=after_sales_request'
);
add_submenu_page(
'after-sales',
'售后设置',
'设置',
'manage_woocommerce',
'after-sales-settings',
array($this, 'render_settings_page')
);
add_submenu_page(
'after-sales',
'售后报表',
'报表',
'manage_woocommerce',
'after-sales-reports',
array($this, 'render_reports_page')
);
}
/**
* 渲染仪表盘
*/
public function render_dashboard() {
?>
<div class="wrap after-sales-dashboard">
<h1 class="wp-heading-inline">售后管理仪表盘</h1>
<div class="dashboard-widgets">
<div class="widget-row">
<div class="widget-card">
<h3>待处理请求</h3>
<div class="widget-value" id="pending-requests">0</div>
<a href="<?php echo admin_url('edit.php?post_type=after_sales_request&status=pending'); ?>" class="widget-link">查看详情</a>
</div>
<div class="widget-card">
<h3>今日请求</h3>
<div class="widget-value" id="today-requests">0</div>
</div>
<div class="widget-card">
<h3>本月退款金额</h3>
<div class="widget-value" id="monthly-refund">¥0</div>
</div>
<div class="widget-card">
<h3>平均处理时间</h3>
<div class="widget-value" id="avg-processing-time">0小时</div>
</div>
</div>
<div class="widget-row">
<div class="widget-large-card">
<h3>请求趋势</h3>
<div class="chart-container">
<canvas id="requests-trend-chart"></canvas>
</div>
</div>
<div class="widget-large-card">
<h3>状态分布</h3>
