feat;提交管理端和城市合伙人端
This commit is contained in:
@@ -1,15 +1,30 @@
|
||||
import { Body, Controller, Post, UseGuards } from '@nestjs/common';
|
||||
import { AnalyticsService } from './analytics.service';
|
||||
import { JwtAuthGuard, AuthUser } from '../../common/guards/jwt-auth.guard';
|
||||
import { OptionalJwtAuthGuard } from '../../common/guards/optional-jwt-auth.guard';
|
||||
import { CurrentUser } from '../../common/decorators/current-user.decorator';
|
||||
import { PromoTouchDto } from './dto/promo.dto';
|
||||
import { ActorType } from '@dukang/shared-types';
|
||||
|
||||
@Controller('analytics')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
export class AnalyticsController {
|
||||
constructor(private readonly analyticsService: AnalyticsService) {}
|
||||
|
||||
@Post('events')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
track(@CurrentUser() user: AuthUser, @Body() body: { events: Array<{ eventName: string; params?: Record<string, unknown> }> }) {
|
||||
return this.analyticsService.trackBatch(user.actorId, user.clientApp, body.events);
|
||||
}
|
||||
}
|
||||
|
||||
@Controller('promo')
|
||||
export class PromoController {
|
||||
constructor(private readonly analyticsService: AnalyticsService) {}
|
||||
|
||||
@Post('touch')
|
||||
@UseGuards(OptionalJwtAuthGuard)
|
||||
touch(@CurrentUser() user: AuthUser | undefined, @Body() dto: PromoTouchDto) {
|
||||
const userId = user?.actorType === ActorType.USER ? user.actorId : undefined;
|
||||
return this.analyticsService.touchPromo(dto.promoCode, userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { IamModule } from '../iam/iam.module';
|
||||
import { AnalyticsController } from './analytics.controller';
|
||||
import { AnalyticsController, PromoController } from './analytics.controller';
|
||||
import { AnalyticsService } from './analytics.service';
|
||||
|
||||
@Module({
|
||||
imports: [IamModule],
|
||||
controllers: [AnalyticsController],
|
||||
controllers: [AnalyticsController, PromoController],
|
||||
providers: [AnalyticsService],
|
||||
exports: [AnalyticsService],
|
||||
})
|
||||
export class AnalyticsModule {}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import type { ClientApp } from '@prisma/client';
|
||||
import { PrismaService } from '../../common/prisma/prisma.module';
|
||||
import { serializeBigInt } from '../../common/decorators/current-user.decorator';
|
||||
|
||||
@Injectable()
|
||||
export class AnalyticsService {
|
||||
@@ -22,4 +23,43 @@ export class AnalyticsService {
|
||||
});
|
||||
return { count: events.length };
|
||||
}
|
||||
|
||||
/** 扫码归因:始终累加 scan_count;已登录用户首次写入 user_promo_attribution */
|
||||
async touchPromo(promoCode: string, userId?: bigint) {
|
||||
const code = promoCode.trim().toUpperCase();
|
||||
const promo = await this.prisma.commonPromoCode.findUnique({ where: { code } });
|
||||
if (!promo || promo.status !== 'ACTIVE') {
|
||||
throw new NotFoundException('推广码无效或已停用');
|
||||
}
|
||||
|
||||
await this.prisma.commonPromoCode.update({
|
||||
where: { id: promo.id },
|
||||
data: { scanCount: { increment: 1 } },
|
||||
});
|
||||
|
||||
let attributed = false;
|
||||
if (userId) {
|
||||
const existing = await this.prisma.userPromoAttribution.findUnique({
|
||||
where: { userId },
|
||||
});
|
||||
if (!existing) {
|
||||
await this.prisma.userPromoAttribution.create({
|
||||
data: {
|
||||
userId,
|
||||
promoCodeId: promo.id,
|
||||
channelName: promo.name,
|
||||
firstTouchAt: new Date(),
|
||||
},
|
||||
});
|
||||
attributed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return serializeBigInt({
|
||||
promoCode: promo.code,
|
||||
channelName: promo.name,
|
||||
attributed,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class PromoTouchDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
promoCode: string;
|
||||
}
|
||||
Reference in New Issue
Block a user