feat(orders): replace order stat cards with a 售后中 filter

/user/orders 顶部的「已退款」「售后待处理」统计卡移除(统计行改为
全部 / 待支付 / 已支付 / 已关闭 四格,栅格同步由 3 列调为 4 列),
筛选的订单状态新增「售后中」,命中带有「待审核 / 处理中」工单的订单。

售后中与订单自身状态正交(售后中的订单可能仍是 paid,也可能已
refunded),因此不过滤 status 列,而是由 OrderCenterQuery 通过
repository_args 的 after_sale_open 下传,在 get_user_order_query_parts
中作为独立谓词叠加工单子查询,与类型、订单号条件自然组合。

工单流转口径复用 AfterSaleService 的 STATUS_PENDING / STATUS_PROCESSING,
与 find_active() 的退款闸门同一套判定;已完结(completed)与已撤销
(cancelled)不算售后中。

同时清理随之失效的死代码:UserOrders::get_user_order_stats()、
AfterSaleService::count_user_open()、aksrt_get_order_status_labels(),
以及两处 summary 查询与空视图中的 refunded / after_sale_pending 统计键。
不写双路与数据迁移,旧键直接替换。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Opus 5 committed 2026-10-25 18:58:06 +08:00
1 parent 81b60eb427
commit 761c84d70f
8 files changed
+29 -39

No files matched your search

+15 -5
View File
@@ -264,7 +264,7 @@ trait OrderRepositoryCore {
if ($user_id <= 0) {
return [
'total' => 0,
'stats' => ['total' => 0, 'pending' => 0, 'paid' => 0, 'refunded' => 0, 'closed' => 0, 'after_sale_pending' => 0],
'stats' => ['total' => 0, 'pending' => 0, 'paid' => 0, 'closed' => 0],
];
}
@@ -279,13 +279,12 @@ trait OrderRepositoryCore {
SUM(CASE WHEN status = %s THEN 1 ELSE 0 END) AS pending,
SUM(CASE WHEN status = %s THEN 1 ELSE 0 END) AS paid,
SUM(CASE WHEN status = 'refunding' THEN 1 ELSE 0 END) AS paid_legacy,
SUM(CASE WHEN status = %s THEN 1 ELSE 0 END) AS refunded,
SUM(CASE WHEN status = %s THEN 1 ELSE 0 END) AS closed
FROM {$this->table()}
WHERE user_id = %d AND status IN ({$known_placeholders})";
$params = array_merge(
$parts['params'],
[Order::STATUS_PENDING, Order::STATUS_PAID, Order::STATUS_REFUNDED, Order::STATUS_CLOSED],
[Order::STATUS_PENDING, Order::STATUS_PAID, Order::STATUS_CLOSED],
[$user_id],
$known_statuses
);
@@ -297,9 +296,7 @@ trait OrderRepositoryCore {
'total' => (int) ($row['known_total'] ?? 0),
'pending' => (int) ($row['pending'] ?? 0),
'paid' => (int) ($row['paid'] ?? 0) + (int) ($row['paid_legacy'] ?? 0),
'refunded' => (int) ($row['refunded'] ?? 0),
'closed' => (int) ($row['closed'] ?? 0),
'after_sale_pending' => class_exists(AfterSaleService::class) ? AfterSaleService::get_instance()->count_user_open($user_id) : 0,
],
];
}
@@ -765,6 +762,19 @@ trait OrderRepositoryCore {
}
}
// 售后中:只认「待审核 / 处理中」两张在流转状态,与订单自身状态正交,
// 因此作为独立谓词叠加上去(工单已完结或已撤销不算售后中)。
if (!empty($args['after_sale_open']) && class_exists(AfterSaleService::class)) {
$open = [
AfterSaleService::STATUS_PENDING,
AfterSaleService::STATUS_PROCESSING,
];
$where[] = 'order_number IN (SELECT order_number FROM '
. \AKSRT\Core\DBMigrator::table('order_aftersale')
. ' WHERE status IN (' . implode(', ', array_fill(0, count($open), '%s')) . '))';
array_push($params, ...$open);
}
$product_type = sanitize_key((string) ($args['product_type'] ?? ''));
if ($product_type !== '') {
if ($product_type === \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE) {