feat(trade): WeChat confirm-receive component + admin status log columns

Open weappOrderConfirm in mini-user so users confirm in-app instead of
service notice; verify via get_order before completing. Show operator/remark
on admin order status timeline.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-29 16:48:44 +08:00
parent 05dffbfa15
commit 1a0afb6d39
14 changed files with 505 additions and 32 deletions
@@ -67,10 +67,11 @@ export class TradeController {
confirmReceive(
@CurrentUser() user: AuthUser,
@Param('id') id: string,
@Body() body?: { onSitePickup?: boolean },
@Body() body?: { onSitePickup?: boolean; source?: 'USER' | 'WECHAT_COMPONENT' },
) {
return this.tradeService.confirmReceive(user.actorId, BigInt(id), {
onSitePickup: !!body?.onSitePickup,
source: body?.source === 'WECHAT_COMPONENT' ? 'WECHAT_COMPONENT' : 'USER',
});
}
@@ -493,7 +493,11 @@ export class TradeService {
where: orderStatusLogWhere(orderId),
orderBy: { createdAt: 'desc' },
});
return serializeBigInt(mapOrderCompat({ ...order, statusLogs: mapStatusLogCompat(statusLogs) }));
const mapped = mapOrderCompat({ ...order, statusLogs: mapStatusLogCompat(statusLogs) });
return serializeBigInt({
...mapped,
wechatConfirm: this.wechatOrderShipping.buildConfirmPayload(order),
});
}
async getOrderTrack(userId: bigint, orderId: bigint) {
@@ -537,7 +541,7 @@ export class TradeService {
async confirmReceive(
userId: bigint,
orderId: bigint,
_opts?: { onSitePickup?: boolean },
opts?: { onSitePickup?: boolean; source?: 'USER' | 'WECHAT_COMPONENT' },
) {
const order = await this.prisma.order.findFirst({ where: { id: orderId, userId } });
if (!order) throw new NotFoundException('订单不存在');
@@ -546,13 +550,23 @@ export class TradeService {
throw new BadRequestException('当前状态不可确认收货');
}
await this.applyStatusTransition(
order.id,
order.status,
'COMPLETED',
order.deliveryType === 'ON_SITE_PICKUP' ? 'USER_ON_SITE' : 'USER',
order.deliveryType === 'ON_SITE_PICKUP' ? '用户现场取货确认收货' : undefined,
);
const viaWechat = opts?.source === 'WECHAT_COMPONENT';
if (viaWechat) {
await this.wechatOrderShipping.assertWechatUserConfirmed(orderId);
}
const operator = viaWechat
? 'USER_WECHAT_CONFIRM'
: order.deliveryType === 'ON_SITE_PICKUP' || opts?.onSitePickup
? 'USER_ON_SITE'
: 'USER';
const remark = viaWechat
? '用户经微信确认收货组件确认'
: order.deliveryType === 'ON_SITE_PICKUP' || opts?.onSitePickup
? '用户现场取货确认收货'
: undefined;
await this.applyStatusTransition(order.id, order.status, 'COMPLETED', operator, remark);
return this.getOrder(userId, orderId);
}