feat(promo): promo metric event logs and HQ timeline charts (v3.4.13)

Add log_promo_event for scan/attribution/register/order with IP; admin metrics APIs and ECharts on promo detail page.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-06 00:06:52 +08:00
parent 8df0a2bea7
commit 53e0db6a98
15 changed files with 785 additions and 25 deletions
@@ -272,6 +272,15 @@ export class TradeService {
return created;
});
if (promoCodeId) {
this.promoCodeService.logPromoOrderEvent(
promoCodeId,
order.id,
userId,
location.clientIp ?? undefined,
);
}
this.analyticsService.trackOneSafe(userId, 'USER_H5', {
eventName: 'order_submit',
refType: 'ORDER',
@@ -1571,12 +1580,6 @@ export class TradeService {
const paySnapshot = await this.partnerCityService.resolveForOrder(city.id, commissionDistrict);
let promoCodeId: bigint | undefined;
if (body.promoCodeId?.trim()) {
promoCodeId = BigInt(body.promoCodeId.trim());
await this.promoCodeService.attributeUserToPromo(user.id, promoCodeId);
}
const orderNo = generateOrderNo();
const payExpireAt = new Date(Date.now() + 30 * 60 * 1000);
const location = buildOrderClientLocationSnapshot(
@@ -1585,6 +1588,14 @@ export class TradeService {
undefined,
);
let promoCodeId: bigint | undefined;
if (body.promoCodeId?.trim()) {
promoCodeId = BigInt(body.promoCodeId.trim());
await this.promoCodeService.attributeUserToPromo(user.id, promoCodeId, {
clientIp: location.clientIp ?? undefined,
});
}
const order = await this.prisma.$transaction(async (tx) => {
const created = await tx.order.create({
data: {
@@ -1651,6 +1662,15 @@ export class TradeService {
return created;
});
if (promoCodeId) {
this.promoCodeService.logPromoOrderEvent(
promoCodeId,
order.id,
user.id,
location.clientIp ?? undefined,
);
}
this.analyticsService.trackPartnerOneSafe(partnerAccountId, 'PARTNER_H5', {
partnerAccountId: primary.id,
eventName: 'partner_proxy_order_create',
@@ -1905,12 +1925,6 @@ export class TradeService {
const paySnapshot = await this.partnerCityService.resolveForOrder(city.id, commissionDistrict);
let promoCodeId: bigint | undefined;
if (body.promoCodeId?.trim()) {
promoCodeId = BigInt(body.promoCodeId.trim());
await this.promoCodeService.attributeUserToPromo(user.id, promoCodeId);
}
const orderNo = generateOrderNo();
const payExpireAt = new Date(Date.now() + 30 * 60 * 1000);
const location = buildOrderClientLocationSnapshot(
@@ -1919,6 +1933,14 @@ export class TradeService {
undefined,
);
let promoCodeId: bigint | undefined;
if (body.promoCodeId?.trim()) {
promoCodeId = BigInt(body.promoCodeId.trim());
await this.promoCodeService.attributeUserToPromo(user.id, promoCodeId, {
clientIp: location.clientIp ?? undefined,
});
}
const order = await this.prisma.$transaction(async (tx) => {
const created = await tx.order.create({
data: {
@@ -1985,6 +2007,15 @@ export class TradeService {
return created;
});
if (promoCodeId) {
this.promoCodeService.logPromoOrderEvent(
promoCodeId,
order.id,
user.id,
location.clientIp ?? undefined,
);
}
return {
id: order.id.toString(),
orderNo: order.orderNo,