feat(订单): 订单列表拆分待发货/待收货tab并同步统计口径与缓存

- 列表筛选:待发货=实物未发货(delivery_time=0),待收货=实物已发货未收货(delivery_time<>0 且 take_time=0)
- 用户统计 grouped 拆分 pending_delivery/pending_receipt,缓存 key 升级 v3 并引入失效版本号
- 新订单 createRecord 时清除统计缓存,保证全部/待支付计数实时
- 移动端 tab 文案与旧状态映射同步:旧数字 2(待收货)改映射 pending_receipt
This commit is contained in:
吴昊天 2026-10-10 17:00:50 +08:00
parent aafd155181
commit 6865b216b9
5 changed files with 60 additions and 24 deletions

View File

@ -64,10 +64,15 @@ class CenterOrderController
'status_code' => $this->mapSemanticStatus($semanticStatus),
'product_type' => request()->param('product_type', ''),
];
// 待收货/待使用:均为 STATUS_PROCESSING,需按产品类型细分
// 待收货=实物业态(normal),待使用=非实物业态(virtual/cardkey/hotel/ticket 等)
// 待发货/待收货/待使用:均为 STATUS_PROCESSING,需按产品类型与发货状态细分
// 待发货=实物业态(normal)未发货;待收货=实物业态已发货未收货;待使用=非实物业态(virtual/cardkey/hotel/ticket 等)
if ($semanticStatus === 'pending_delivery') {
$where['product_type'] = 'normal';
$where['delivery_time'] = 0;
} elseif ($semanticStatus === 'pending_receipt') {
$where['product_type'] = 'normal';
$where['delivery_time_ne'] = 0;
$where['take_time'] = 0;
} elseif ($semanticStatus === 'pending_use') {
$where['product_type_ne'] = 'normal';
}
@ -79,8 +84,8 @@ class CenterOrderController
/**
* 语义化状态映射到实际 status_code
* 前端传入语义化状态标识,后端映射到中台 status_code,支持逗号分隔多状态(如售后=refunding,refunded)
* 待收货(pending_delivery)/待使用(pending_use) 均映射到 STATUS_PROCESSING,
* 由 list 方法追加 product_type 条件细分,此处不承担产品类型过滤
* 待发货(pending_delivery)/待收货(pending_receipt)/待使用(pending_use) 均映射到 STATUS_PROCESSING,
* 发货状态与产品类型过滤由 list 方法处理,此处不承担
* @param string $status 语义化状态标识
* @return string 返回 status_code,空表示不筛选(全部)
*/
@ -89,7 +94,7 @@ class CenterOrderController
$map = [
'pending_payment' => OrderCenter::STATUS_PENDING_PAYMENT,
'pending_receipt' => OrderCenter::STATUS_PROCESSING,
// 待收货/待使用:均为进行中状态,产品类型过滤交由 list 方法处理
// 待发货/待收货/待使用:均为进行中状态,产品类型与发货状态过滤交由 list 方法处理
'pending_delivery' => OrderCenter::STATUS_PROCESSING,
'pending_use' => OrderCenter::STATUS_PROCESSING,
// 待评价:按已完成状态筛选(与前端原 getStatusMap 逻辑一致)

View File

@ -180,6 +180,8 @@ class OrderCenterServices extends BaseService implements OrderCenterSyncInterfac
public function createRecord(array $data): bool
{
$extraInfo = $data['extra_info'] ?? [];
// 新订单进入统计(全部/待支付计数),清除统计缓存
$this->clearStatCache();
$insert = [
'order_no' => $data['order_no'], //

View File

@ -73,6 +73,16 @@ class OrderCenterUserServices extends OrderCenterServices
if (!empty($where['product_type_ne'])) {
$searchWhere[] = ['product_type', '<>', $where['product_type_ne']];
}
// 发货状态筛选(delivery_time int 默认 0,0=未发货):待发货=未发货,待收货=已发货未收货
if (isset($where['delivery_time'])) {
$searchWhere[] = ['delivery_time', '=', (int)$where['delivery_time']];
}
if (array_key_exists('delivery_time_ne', $where)) {
$searchWhere[] = ['delivery_time', '<>', (int)$where['delivery_time_ne']];
}
if (isset($where['take_time'])) {
$searchWhere[] = ['take_time', '=', (int)$where['take_time']];
}
$list = $this->dao->selectList(
$searchWhere,
@ -309,8 +319,10 @@ class OrderCenterUserServices extends OrderCenterServices
*/
public function getUserStatistics(int $uid): array
{
// 缓存 key 带 v2 版本,统计结构变更后强制失效旧缓存
$cacheKey = 'order_center:user_stat:v2:' . $uid;
// 缓存 key 带结构版本 v3 + 失效版本号:订单状态流转经 syncStatus/updateRecord 递增
// order_center:stat:ver 强制换 key 刷新(结构变更升级 v3),旧 key 靠自身 TTL 自然过期
$ver = (int) app()->cache->get('order_center:stat:ver');
$cacheKey = 'order_center:user_stat:v3:' . $uid . ':' . $ver;
return app()->cache->remember($cacheKey, function () use ($uid) {
$baseWhere = [
@ -339,7 +351,8 @@ class OrderCenterUserServices extends OrderCenterServices
];
}
// STATUS_PROCESSING 按产品类型拆分:normal=待收货(实物),其他=待使用(虚拟/卡密/酒店/门票等)
// STATUS_PROCESSING 按产品类型拆分:非实物业态=待使用(虚拟/卡密/酒店/门票等)
// 实物(normal)进行中再按发货状态细分为待发货/待收货,与订单列表 tab 及角标口径一致
$processingByType = $this->dao->getDb()
->where($baseWhere)
->where('status_code', OrderCenter::STATUS_PROCESSING)
@ -347,8 +360,6 @@ class OrderCenterUserServices extends OrderCenterServices
->group('product_type')
->select()
->toArray();
$deliveryCount = 0;
$deliveryAmount = '0.00';
$useCount = 0;
$useAmount = '0.00';
foreach ($processingByType as $row) {
@ -360,23 +371,41 @@ class OrderCenterUserServices extends OrderCenterServices
} catch (\Throwable $e) {
$isDelivery = false;
}
if ($isDelivery) {
$deliveryCount += (int) ($row['count'] ?? 0);
$deliveryAmount = bcadd($deliveryAmount, (string) ($row['amount'] ?? '0.00'), 2);
} else {
if (!$isDelivery) {
$useCount += (int) ($row['count'] ?? 0);
$useAmount = bcadd($useAmount, (string) ($row['amount'] ?? '0.00'), 2);
}
}
// 实物进行中按发货状态拆分:待发货=未发货(delivery_time=0),待收货=已发货未收货
$pendingShip = $this->dao->getDb()
->where($baseWhere)
->where('status_code', OrderCenter::STATUS_PROCESSING)
->where('product_type', 'normal')
->where('delivery_time', 0)
->field('COUNT(*) as count, SUM(pay_price) as amount')
->find();
$pendingReceipt = $this->dao->getDb()
->where($baseWhere)
->where('status_code', OrderCenter::STATUS_PROCESSING)
->where('product_type', 'normal')
->where('delivery_time', '<>', 0)
->where('take_time', 0)
->field('COUNT(*) as count, SUM(pay_price) as amount')
->find();
$grouped = [
'pending_payment' => [
'count' => $statusCounts[OrderCenter::STATUS_PENDING_PAYMENT]['count'] ?? 0,
'amount' => $statusCounts[OrderCenter::STATUS_PENDING_PAYMENT]['amount'] ?? '0.00',
],
'pending_delivery' => [
'count' => $deliveryCount,
'amount' => $deliveryAmount,
'count' => (int) ($pendingShip['count'] ?? 0),
'amount' => (string) ($pendingShip['amount'] ?? '0.00'),
],
'pending_receipt' => [
'count' => (int) ($pendingReceipt['count'] ?? 0),
'amount' => (string) ($pendingReceipt['amount'] ?? '0.00'),
],
'pending_use' => [
'count' => $useCount,

View File

@ -26,12 +26,12 @@
<view class="num">{{ orderData.grouped && orderData.grouped.pending_payment && orderData.grouped.pending_payment.count || 0 }}</view>
</view>
<view class="item" :class="orderStatus == 'pending_delivery' ? 'on' : ''" @click="statusClick('pending_delivery')">
<view>{{ $t(`待收货`) }}</view>
<view>{{ $t(`待发货`) }}</view>
<view class="num">{{ orderData.grouped && orderData.grouped.pending_delivery && orderData.grouped.pending_delivery.count || 0 }}</view>
</view>
<view class="item" :class="orderStatus == 'pending_use' ? 'on' : ''" @click="statusClick('pending_use')">
<view>{{ $t(`待使用`) }}</view>
<view class="num">{{ orderData.grouped && orderData.grouped.pending_use && orderData.grouped.pending_use.count || 0 }}</view>
<view class="item" :class="orderStatus == 'pending_receipt' ? 'on' : ''" @click="statusClick('pending_receipt')">
<view>{{ $t(`待收货`) }}</view>
<view class="num">{{ orderData.grouped && orderData.grouped.pending_receipt && orderData.grouped.pending_receipt.count || 0 }}</view>
</view>
<view class="item" :class="orderStatus == 'pending_comment' ? 'on' : ''" @click="statusClick('pending_comment')">
<view>{{ $t(`待评价`) }}</view>

View File

@ -9,18 +9,18 @@ import OrderListEngine from '@/dynamic-pages/engines/OrderListEngine.vue';
// 旧版数字 status → 新版语义化 status 映射表
// 旧:0待付款 / 1待发货 / 2待收货 / 3待评价 / 9全部
// 新:pending_payment 待支付 / pending_delivery 待收货(实物) / pending_use 待使用(非实物) / pending_comment 待评价 / after_sale 退款售后 / all 全部
// 旧数字 1/2 均为实物语义(待发货/待收货),统一映射到 pending_delivery
// 新:pending_payment 待支付 / pending_delivery 待发货(实物未发货) / pending_receipt 待收货(已发货未收货)
// / pending_use 待使用(非实物) / pending_comment 待评价 / after_sale 退款售后 / all 全部
const STATUS_MAP = {
'0': 'pending_payment',
'1': 'pending_delivery',
'2': 'pending_delivery',
'2': 'pending_receipt',
'3': 'pending_comment',
'9': 'all',
};
// 新版语义化状态白名单,命中则直接透传
const SEMANTIC_STATUS = ['all', 'pending_payment', 'pending_delivery', 'pending_use', 'pending_comment', 'after_sale'];
const SEMANTIC_STATUS = ['all', 'pending_payment', 'pending_delivery', 'pending_receipt', 'pending_use', 'pending_comment', 'after_sale'];
const statusFilter = ref('all');
const engine = ref(null);