Files
wordpress-theme-aksrt/inc/helpers/user-center-renderers/profile-orders.php
T
kate522 1a9a2762f3 feat(payment): 新增「售后策略」配置与前台售后弹窗链路
- 后台「支付&付费 → 售后策略」:售后功能开关、申请时效、超时效提示(HTML)、
  预置原因、申请售后说明、所需材料、申请说明占位文案、可上传图片开关;
  PHP schema 与 SPA schema 1:1 对齐,group 字段支持拖拽排序
- PaymentRuntime 新增售后设置解析(缺键回退 schema 默认、HTML 走 kses、
  中文原因稳定 slug)与 after_sale_expired 时效判定(支付时间起算)
- 售后工单支持举证图片(order_aftersale.images 列,最多 3 张,
  复用评论图片上传校验)与上传路由;订单视图模型输出 after_sale 按钮状态
- 前台申请 / 超时效提示 / 售后详细三个独立弹窗(modal-mini + 蓝色炫彩头),
  订单详情弹窗不再内嵌售后表单并清理相关死代码
- 新增 after-sale-policy 契约测试与运行时 harness,527 项契约测试通过
2026-10-06 22:21:47 +08:00

144 lines
11 KiB
PHP

<?php
/**
* User-center knowledge-payment order panel.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
$user_id = (int) ($context['user_id'] ?? get_current_user_id());
if ($user_id <= 0) {
echo '<div class="uc-panel-empty muted-2-color">' . esc_html__('请先登录', 'aksrt') . '</div>';
return;
}
$raw_query = [
'status' => 'all',
'type' => '',
'order_number' => '',
'page' => 1,
'per_page' => 20,
];
$query = \AKSRT\Payment\OrderCenterQuery::from_array($raw_query);
$orders_view = function_exists('aksrt_get_orders_page_view')
? aksrt_get_orders_page_view($user_id, $query->page(), $query->per_page(), $query->status(), $query->product_type(), $query->order_number())
: ['items' => [], 'total' => 0, 'total_pages' => 1, 'page' => 1, 'stats' => [], 'product_types' => []];
$orders = (array) ($orders_view['items'] ?? []);
$stats = is_array($orders_view['stats'] ?? null) ? $orders_view['stats'] : [];
$type_options = is_array($orders_view['product_types'] ?? null) ? $orders_view['product_types'] : [];
$page = max(1, (int) ($orders_view['page'] ?? 1));
$total_pages = max(1, (int) ($orders_view['total_pages'] ?? 1));
$status = $query->status();
$type = $query->product_type();
$order_number = $query->order_number();
$status_options = [
'all' => __('全部', 'aksrt'),
'pending' => __('待支付', 'aksrt'),
'paid' => __('已支付', 'aksrt'),
'refunded' => __('已退款', 'aksrt'),
'closed' => __('已关闭', 'aksrt'),
];
?>
<div class="aksrt-orders-page uc-orders-panel" data-aksrt-order-center>
<header class="uc-orders-panel__head">
<div class="uc-orders-panel__title-wrap">
<p class="aksrt-orders-page__eyebrow"><?php esc_html_e('我的购买', 'aksrt'); ?></p>
<div class="uc-orders-panel__title font-bold em12">
<i class="fa fas fa-file-alt uc-orders-panel__title-icon" aria-hidden="true"></i>
<?php esc_html_e('我的订单', 'aksrt'); ?>
</div>
<p class="muted-2-color em09 mt3"><?php esc_html_e('管理已购内容、会员与账户权益。', 'aksrt'); ?></p>
</div>
<div class="aksrt-orders-page__stats" data-aksrt-order-stats>
<div class="aksrt-orders-page__stat"><span><?php esc_html_e('全部', 'aksrt'); ?></span><strong><?php echo esc_html((string) (int) ($stats['total'] ?? 0)); ?></strong></div>
<div class="aksrt-orders-page__stat"><span><?php esc_html_e('待支付', 'aksrt'); ?></span><strong class="is-pending"><?php echo esc_html((string) (int) ($stats['pending'] ?? 0)); ?></strong></div>
<div class="aksrt-orders-page__stat"><span><?php esc_html_e('已支付', 'aksrt'); ?></span><strong class="is-paid"><?php echo esc_html((string) (int) ($stats['paid'] ?? 0)); ?></strong></div>
<div class="aksrt-orders-page__stat"><span><?php esc_html_e('已退款', 'aksrt'); ?></span><strong><?php echo esc_html((string) (int) ($stats['refunded'] ?? 0)); ?></strong></div>
<div class="aksrt-orders-page__stat"><span><?php esc_html_e('售后待处理', 'aksrt'); ?></span><strong><?php echo esc_html((string) (int) ($stats['after_sale_pending'] ?? 0)); ?></strong></div>
</div>
</header>
<form class="aksrt-orders-page__search" data-aksrt-orders-search>
<label class="screen-reader-text" for="aksrt-order-number"><?php esc_html_e('按订单号查找', 'aksrt'); ?></label>
<i class="fa fas fa-search" aria-hidden="true"></i>
<input id="aksrt-order-number" value="<?php echo esc_attr($order_number); ?>" maxlength="22" placeholder="<?php esc_attr_e('输入订单号查找', 'aksrt'); ?>">
<button class="btn-primary" type="submit"><?php esc_html_e('查找', 'aksrt'); ?></button>
<button class="aksrt-orders-page__filter-toggle" type="button" data-aksrt-orders-filter-toggle aria-expanded="false" aria-controls="aksrt-orders-filter-panel"><i class="fa fas fa-sliders-h" aria-hidden="true"></i> <?php esc_html_e('筛选', 'aksrt'); ?></button>
</form>
<div id="aksrt-orders-filter-panel" class="aksrt-orders-page__filter-panel" data-aksrt-orders-filter-panel hidden>
<div class="aksrt-orders-page__filter-group">
<span class="aksrt-orders-page__filter-label"><?php esc_html_e('订单状态', 'aksrt'); ?></span>
<nav class="aksrt-orders-page__status-filters" aria-label="<?php esc_attr_e('订单状态', 'aksrt'); ?>">
<?php foreach ($status_options as $key => $label) : ?>
<button class="aksrt-orders-page__filter-chip<?php echo $status === $key ? ' is-active' : ''; ?>" type="button" data-aksrt-order-filter="status" data-aksrt-order-filter-value="<?php echo esc_attr($key); ?>" aria-pressed="<?php echo $status === $key ? 'true' : 'false'; ?>">
<?php echo esc_html($label); ?>
<?php if ($key === 'pending') : ?><span class="aksrt-orders-page__filter-count"<?php echo empty($stats['pending']) ? ' hidden' : ''; ?>><?php echo esc_html((string) (int) ($stats['pending'] ?? 0)); ?></span><?php endif; ?>
</button>
<?php endforeach; ?>
</nav>
</div>
<div class="aksrt-orders-page__filter-group">
<span class="aksrt-orders-page__filter-label"><?php esc_html_e('订单类型', 'aksrt'); ?></span>
<div class="aksrt-orders-page__type-filters">
<?php foreach ($type_options as $key => $label) : ?>
<button class="aksrt-orders-page__filter-chip<?php echo (string) $key === $type ? ' is-active' : ''; ?>" type="button" data-aksrt-order-filter="type" data-aksrt-order-filter-value="<?php echo esc_attr((string) $key); ?>" aria-pressed="<?php echo (string) $key === $type ? 'true' : 'false'; ?>"><?php echo esc_html((string) $label); ?></button>
<?php endforeach; ?>
</div>
</div>
<button class="aksrt-orders-page__clear" type="button" data-aksrt-orders-clear><?php esc_html_e('清除条件', 'aksrt'); ?></button>
</div>
<?php if ($orders !== []) : ?>
<div class="aksrt-orders-page__list" data-aksrt-order-list>
<?php foreach ($orders as $order) :
$number = (string) ($order['order_number'] ?? '');
$actions = (array) ($order['allowed_actions'] ?? []);
if (!empty($order['is_points'])) {
$amount = esc_html((string) ($order['currency_symbol'] ?? __('积分', 'aksrt')) . ' ' . (string) max(0, (int) ($order['amount'] ?? 0)));
} else {
try {
$order_amount = \AKSRT\Ledger\AssetAmount::balance(is_string($order['amount'] ?? null) ? $order['amount'] : '')->formatted();
} catch (\InvalidArgumentException $e) {
$order_amount = '0.00';
}
$amount = '¥' . esc_html($order_amount);
}
?>
<article class="aksrt-orders-page__card" data-aksrt-order-card="<?php echo esc_attr($number); ?>" data-order-status="<?php echo esc_attr((string) ($order['status_group'] ?? '')); ?>">
<div class="aksrt-orders-page__card-rail"><span><?php echo esc_html((string) ($order['product_type_label'] ?? '')); ?></span><time><?php echo esc_html((string) ($order['created_at'] ?? '')); ?></time><span class="aksrt-orders-page__card-status is-<?php echo esc_attr((string) ($order['status_group'] ?? '')); ?>"><?php echo esc_html((string) ($order['status_label'] ?? '')); ?></span></div>
<div class="aksrt-orders-page__card-main">
<?php if (!empty($order['image'])) : ?><img class="aksrt-orders-page__card-img" src="<?php echo esc_url((string) $order['image']); ?>" alt=""><?php else : ?><div class="aksrt-orders-page__card-art" aria-hidden="true"><i class="fa fas fa-book"></i></div><?php endif; ?>
<div class="aksrt-orders-page__card-copy"><h3><?php echo esc_html((string) ($order['product_name'] ?? __('订单', 'aksrt'))); ?></h3><p><?php printf(esc_html__('订单号 %s', 'aksrt'), esc_html($number)); ?></p></div>
<div class="aksrt-orders-page__card-value"><strong><?php echo $amount; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></strong><span><?php esc_html_e('实付', 'aksrt'); ?></span></div>
</div>
<footer class="aksrt-orders-page__card-actions">
<?php if (!empty($order['time_left'])) : ?><span class="aksrt-orders-page__countdown" data-aksrt-order-countdown="<?php echo esc_attr((string) $order['time_left']); ?>"></span><?php endif; ?>
<button class="btn-outline" type="button" data-aksrt-order-detail="<?php echo esc_attr($number); ?>"><?php esc_html_e('订单详情', 'aksrt'); ?></button>
<?php if (!empty($actions['can_cancel'])) : ?><button class="btn-ghost" type="button" data-aksrt-order-cancel="<?php echo esc_attr($number); ?>"><?php esc_html_e('关闭订单', 'aksrt'); ?></button><?php endif; ?>
<?php if (!empty($actions['can_pay'])) : ?><button class="btn-primary" type="button" data-aksrt-order-pay="<?php echo esc_attr($number); ?>" data-aksrt-order-method="<?php echo esc_attr((string) ($order['payment_method']['value'] ?? '')); ?>"><?php esc_html_e('继续支付', 'aksrt'); ?></button><?php endif; ?>
<?php
$after_sale = is_array($order['after_sale'] ?? null) ? $order['after_sale'] : [];
?>
<?php if (!empty($after_sale['enabled'])) : ?>
<?php if (!empty($after_sale['has_application'])) : ?>
<button class="btn-outline" type="button" data-aksrt-after-sale-detail="<?php echo esc_attr($number); ?>"><?php esc_html_e('售后详细', 'aksrt'); ?></button>
<?php else : ?>
<button class="btn-outline" type="button" data-aksrt-after-sale-apply="<?php echo esc_attr($number); ?>"><?php esc_html_e('申请售后', 'aksrt'); ?></button>
<?php endif; ?>
<?php endif; ?>
</footer>
</article>
<?php endforeach; ?>
</div>
<?php if ($total_pages > 1) : ?><nav class="aksrt-orders-page__pagination" aria-label="<?php esc_attr_e('订单分页', 'aksrt'); ?>"><?php for ($index = 1; $index <= $total_pages; $index++) : ?><button class="aksrt-orders-page__page-chip<?php echo $index === $page ? ' is-active' : ''; ?>" type="button" data-aksrt-order-page="<?php echo esc_attr((string) $index); ?>"<?php echo $index === $page ? ' aria-current="page"' : ''; ?>><?php echo esc_html((string) $index); ?></button><?php endfor; ?></nav><?php endif; ?>
<?php else : ?>
<div class="aksrt-orders-page__empty" data-aksrt-order-list><i class="fa fas fa-file-alt" aria-hidden="true"></i><h3><?php esc_html_e('还没有购买记录', 'aksrt'); ?></h3><p><?php esc_html_e('购买内容或开通权益后,订单会出现在这里。', 'aksrt'); ?></p></div>
<?php endif; ?>
</div>