核销成功提示
This commit is contained in:
@@ -18,6 +18,11 @@ export class UserRedeemController {
|
||||
return this.redeemService.getToken(token);
|
||||
}
|
||||
|
||||
@Get('tokens/:token/status')
|
||||
getTokenStatus(@CurrentUser() user: AuthUser, @Param('token') token: string) {
|
||||
return this.redeemService.getTokenStatus(token, user.actorId);
|
||||
}
|
||||
|
||||
@Post('ratings')
|
||||
rating(@CurrentUser() user: AuthUser, @Body() body: Record<string, unknown>) {
|
||||
return this.redeemService.submitRating(user.actorId, body as never);
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
validateRedeemAmount,
|
||||
allocateBenefitCoupons,
|
||||
} from '@dukang/domain';
|
||||
import { REDEEM_TOKEN_TTL_SECONDS } from '@dukang/shared-types';
|
||||
import { REDEEM_RESULT_TTL_SECONDS, REDEEM_TOKEN_TTL_SECONDS } from '@dukang/shared-types';
|
||||
import { PrismaService } from '../../common/prisma/prisma.module';
|
||||
import { RedisService } from '../../common/redis/redis.service';
|
||||
import { serializeBigInt } from '../../common/decorators/current-user.decorator';
|
||||
@@ -26,6 +26,16 @@ type TokenPayload = {
|
||||
allocations?: Array<{ couponId: string; amount: number }>;
|
||||
};
|
||||
|
||||
type RedeemResultPayload = {
|
||||
recordId: string;
|
||||
redeemNo: string;
|
||||
userId: string;
|
||||
amount: number;
|
||||
storeId: string;
|
||||
storeName: string;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class RedeemService {
|
||||
constructor(
|
||||
@@ -93,6 +103,41 @@ export class RedeemService {
|
||||
return cached;
|
||||
}
|
||||
|
||||
async getTokenStatus(token: string, userId: bigint) {
|
||||
const result = await this.redis.getJson<RedeemResultPayload>(`redeem:result:${token}`);
|
||||
if (result) {
|
||||
if (result.userId !== userId.toString()) {
|
||||
throw new NotFoundException('核销码不存在');
|
||||
}
|
||||
return {
|
||||
status: 'CONSUMED' as const,
|
||||
record: {
|
||||
id: result.recordId,
|
||||
redeemNo: result.redeemNo,
|
||||
amount: result.amount,
|
||||
storeId: result.storeId,
|
||||
storeName: result.storeName,
|
||||
createdAt: result.createdAt,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const cached = await this.redis.getJson<TokenPayload>(`redeem:token:${token}`);
|
||||
if (cached) {
|
||||
if (cached.userId !== userId.toString()) {
|
||||
throw new NotFoundException('核销码不存在');
|
||||
}
|
||||
const ttl = await this.redis.ttl(`redeem:token:${token}`);
|
||||
return {
|
||||
status: 'PENDING' as const,
|
||||
expireInSeconds: ttl > 0 ? ttl : 0,
|
||||
amount: cached.amount,
|
||||
};
|
||||
}
|
||||
|
||||
return { status: 'EXPIRED' as const };
|
||||
}
|
||||
|
||||
async previewRedeem(storeAccountId: bigint, token: string) {
|
||||
const account = await this.prisma.storeAccount.findUniqueOrThrow({
|
||||
where: { id: storeAccountId },
|
||||
@@ -223,17 +268,37 @@ export class RedeemService {
|
||||
throw e;
|
||||
}
|
||||
|
||||
await this.redis.setJson(
|
||||
`redeem:result:${body.token}`,
|
||||
{
|
||||
recordId: record.id.toString(),
|
||||
redeemNo: record.redeemNo,
|
||||
userId: cached.userId,
|
||||
amount,
|
||||
storeId: account.storeId.toString(),
|
||||
storeName: account.store.name,
|
||||
createdAt: record.createdAt.toISOString(),
|
||||
} satisfies RedeemResultPayload,
|
||||
REDEEM_RESULT_TTL_SECONDS,
|
||||
);
|
||||
await this.redis.del(`redeem:token:${body.token}`);
|
||||
|
||||
const redeemExtra = {
|
||||
redeemRecordId: record.id.toString(),
|
||||
storeId: account.storeId.toString(),
|
||||
amount,
|
||||
};
|
||||
this.analyticsService.trackOneSafe(BigInt(cached.userId), 'SHOP_H5', {
|
||||
eventName: 'benefit_redeem_success',
|
||||
refType: 'STORE',
|
||||
refId: account.storeId,
|
||||
extraJson: {
|
||||
redeemRecordId: record.id.toString(),
|
||||
storeId: account.storeId.toString(),
|
||||
amount,
|
||||
},
|
||||
extraJson: redeemExtra,
|
||||
});
|
||||
this.analyticsService.trackOneSafe(BigInt(cached.userId), 'USER_H5', {
|
||||
eventName: 'benefit_redeem_success',
|
||||
refType: 'STORE',
|
||||
refId: account.storeId,
|
||||
extraJson: redeemExtra,
|
||||
});
|
||||
|
||||
return serializeBigInt(record);
|
||||
|
||||
Reference in New Issue
Block a user