小鸡初始化等

This commit is contained in:
Administrator 2021-05-12 21:30:19 +08:00
parent 2ffebb8f48
commit 50556a4936
24 changed files with 254 additions and 136 deletions

View File

@ -13,6 +13,7 @@ import { ConfigurationModule } from './configuration/configuration.module';
import { AdminModule } from './admin/admin.module';
import logger from './common/utils/logger';
import { Log4jsModule } from '@nestx-log4js/core';
import { RedisModule } from 'nestjs-redis';
@Module({
@ -31,26 +32,18 @@ import { Log4jsModule } from '@nestx-log4js/core';
};
},
}),
// RedisModule.forRootAsync({
// imports: [ConfigModule],
// useFactory: (configService: ConfigService) => {
// const nodes = configService.get('redis.cluster.nodes');
// if (nodes) {
// console.log('redis集群模式');
// return {
// nodes: nodes,
// };
// } else {
// console.log('redis普通模式');
// return {
// host: configService.get('redis.host'),
// port: configService.get('redis.port'),
// password: configService.get('redis.password', undefined),
// };
// }
// }, // or use async method
// inject: [ConfigService],
// }),
RedisModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => {
console.log('redis普通模式');
return {
host: configService.get('redis.host'),
port: configService.get('redis.port'),
password: configService.get('redis.password', undefined),
};
}, // or use async method
inject: [ConfigService],
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],

View File

@ -1,4 +1,4 @@
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { Controller, Get, Post, Body, Patch, Param, Delete, UsePipes, Query, UseInterceptors } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { CustomResult, SuccessResult } from 'src/common/utils/result-utils';
import { UserService } from 'src/user/user.service';
@ -6,6 +6,12 @@ import { ChickensService } from './chickens.service';
import { CreateChickenDto } from './dto/create-chicken.dto';
import { UpdateChickenDto } from './dto/update-chicken.dto';
import { CODE } from '../common/code'
import { HttpValidationPipe } from 'src/common/utils/HttpValidationPipe';
import { ApiImplicitQuery } from '@nestjs/swagger/dist/decorators/api-implicit-query.decorator';
import { CacheService } from 'src/redis/redis';
import { getUserTokenKey } from 'src/redis/keys';
import { LoggingInterceptor } from 'src/common/utils/login.interceptor';
@ApiTags('小鸡主体数据接口')
@Controller('chickens')
@ -13,42 +19,53 @@ export class ChickensController {
constructor(
private readonly chickensService: ChickensService,
private readonly userService: UserService,
private readonly cacheService: CacheService,
) { }
//领取小鸡
@ApiOperation({ summary: '领取小鸡' })
@Post()
async create(@Body() createChickenDto: CreateChickenDto) {
//用户数据初始化
const initUser = await this.userService.init(createChickenDto)
if (!initUser) return CustomResult(CODE.CODE_INIT_USER_ERR);
@UsePipes(new HttpValidationPipe())
@ApiImplicitQuery({
name: 'userid',
required: true,
description: '当前用户ID',
type: Number,
})
@Get('draw')
async create(@Query('userid') userid: number) {
//小鸡数据初始化
createChickenDto.schedule = 0;
createChickenDto.eat_start = 0;
createChickenDto.eat_end = 0;
createChickenDto.eat_time = 0;
const init = this.chickensService.create(createChickenDto);
let createChickenDto: CreateChickenDto = {
userid: Number(userid),
token: await this.cacheService.get(getUserTokenKey(userid)),
schedule: 0,
eat_start: 0,
eat_end: 0,
eat_time: 0,
};
//用户数据初始化,有信息则返回
const initUser = await this.userService.initQuery(createChickenDto)
if (!initUser || initUser.code != 200) return CustomResult(CODE.CODE_INIT_USER_ERR);
const init = await this.chickensService.create(createChickenDto);
if (!init) return CustomResult(CODE.CODE_INIT_PLAYER_ERR);
return SuccessResult(true);
return SuccessResult(init);
}
// @Get()
// findAll() {
// return this.chickensService.findAll();
// }
//小鸡信息查询
@ApiOperation({ summary: '小鸡信息查询' })
@UsePipes(new HttpValidationPipe())
@UseInterceptors(LoggingInterceptor)
@ApiImplicitQuery({
name: 'userid',
required: true,
description: '当前用户ID',
type: Number,
})
@Get()
async query(@Query('userid') userid: number) {
//小鸡数据初始化
const res = await this.chickensService.chickensInfo(userid);
return SuccessResult(res);
}
// @Get(':id')
// findOne(@Param('id') id: string) {
// return this.chickensService.findOne(+id);
// }
// @Patch(':id')
// update(@Param('id') id: string, @Body() updateChickenDto: UpdateChickenDto) {
// return this.chickensService.update(+id, updateChickenDto);
// }
// @Delete(':id')
// remove(@Param('id') id: string) {
// return this.chickensService.remove(+id);
// }
}

View File

@ -4,14 +4,17 @@ import { ChickensController } from './chickens.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ChickenEntity } from './entities/chicken.entity';
import { UserModule } from 'src/user/user.module';
import { CacheService } from 'src/redis/redis';
import { OrderlogService } from 'src/orderlog/orderlog.service';
import { OrderlogEntity } from 'src/orderlog/entities/orderlog.entity';
@Module({
imports: [
TypeOrmModule.forFeature([ChickenEntity]),
TypeOrmModule.forFeature([ChickenEntity,OrderlogEntity]),
UserModule,
],
controllers: [ChickensController],
exports: [ChickensService],
providers: [ChickensService]
providers: [ChickensService, CacheService,OrderlogService]
})
export class ChickensModule { }

View File

@ -1,29 +1,42 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { CODE } from 'src/common/code';
import { CustomResult } from 'src/common/utils/result-utils';
import { OrderlogService } from 'src/orderlog/orderlog.service';
import { Repository } from 'typeorm';
import { CreateChickenDto } from './dto/create-chicken.dto';
import { UpdateChickenDto } from './dto/update-chicken.dto';
import { ChickenEntity } from './entities/chicken.entity';
const prefix = 'chick';
@Injectable()
export class ChickensService {
constructor(
@InjectRepository(ChickenEntity)
private readonly chickensRepository: Repository<ChickenEntity>
private readonly chickensRepository: Repository<ChickenEntity>,
private readonly orderService: OrderlogService
) { }
/**插入数据 */
async create(createChickenDto: CreateChickenDto) {
const info = await this.chickensInfo(createChickenDto.userid);
if (info) return info;
createChickenDto.create_time = new Date();
return await this.chickensRepository.save(createChickenDto);
}
findAll() {
return `This action returns all chickens`;
}
findOne(id: number) {
return `This action returns a #${id} chicken`;
/** 查询小鸡信息 */
async chickensInfo(userid: number) {
//小鸡信息
const info = await this.chickensRepository.createQueryBuilder(prefix)
.select().where(`userid=:userid`, { userid: userid }).getRawOne();
console.log(info);
if (!info) return CustomResult(CODE.CODE_PLAYER_INFO_ERR);
//小鸡穿戴套装信息
if (info.chick_ck_suitid == 0) info['suit_info'] = {};
const suit = await this.orderService.paidGoodsInfo(info.chick_suitid, info.chick_userid);
console.log(suit);
return info;
}
update(id: number, updateChickenDto: UpdateChickenDto) {

View File

@ -3,7 +3,7 @@ import { IsNotEmpty, IsNumber, IsString } from "class-validator";
export class CreateChickenDto {
@IsNotEmpty({ message: '用户ID不能为空' })
@IsNumber()
uid: number;
userid: number;
@IsString()
token: string;

View File

@ -7,11 +7,11 @@ export class ChickenEntity {
@PrimaryGeneratedColumn()
id?: number;
@Column({ comment: '套装ID', type: 'int', default: 0 })
suitid: number;
@Column({ comment: '用户ID', type: 'int', default: 0, unique: true })
userid: number;
@Column({ comment: '背景ID', type: 'int', default: 0 })
backdropid: number;
@Column({ comment: '套装订单ID', type: 'varchar', default: '' })
suitid: string;
@Column({ comment: '碗中剩余饲料', type: 'bigint', default: 0 })
surplus_fodder: number;

View File

@ -20,6 +20,8 @@ export const CODE = {
CODE_APPUSER_COIN_NOT_ENOUGHT_ERR: { code: 606, message: '用户余额不足!' },
/**扣减用户APP余额失败 */
CODE_APPUSER_SUB_COIN_ERR: { code: 606, message: '扣减用户APP余额失败!' },
/**购买中,请稍后... */
CODE_USER_PAY_LOCK_ERR: { code: 607, message: '购买中,请稍后...' },
/** 商品信息异常code */
@ -36,4 +38,8 @@ export const CODE = {
/** 订单信息异常code */
CODE_ORDER_INSERT_ERR: { code: 801, message: '订单创建失败!' },
/** 小鸡信息异常code */
/**用户数据查询失败 */
CODE_PLAYER_INFO_ERR: { code: 902, message: '小鸡数据查询失败!' },
};

View File

@ -0,0 +1,29 @@
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, HttpException, HttpStatus } from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { getUserTokenKey } from 'src/redis/keys';
import { CacheService } from 'src/redis/redis';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
constructor(
private readonly cacheRedis: CacheService
) { }
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
const ctx = context.switchToHttp();
const request = ctx.getRequest();
const userid = request.query.userid;
const token = await this.cacheRedis.get(getUserTokenKey(userid));
console.log(token)
const now = Date.now();
if (!token) {
return throwError(new HttpException('登录信息错误', HttpStatus.SEE_OTHER))
}
return next
.handle()
.pipe(
// tap(() => console.log(`After... ${Date.now() - now}ms`)),
);
}
}

View File

@ -26,7 +26,7 @@ export function DataListResult(data: any[], pageIndex: number, pageSize: number,
* @message
*/
export function CustomResult(params: { code: number, message: string }) {
return { code: params.code, message: params.message };
return { code: params.code, data: '', message: params.message };
// throw new HttpException({
// code: params.code,
// error: params.message,

View File

@ -8,3 +8,8 @@ database:
charset: utf8mb4 #数据库编码
synchronize: true #自动同步表结构
port: 8888
redis:
host: '127.0.0.1'
port: 6379
password: ''

View File

@ -6,10 +6,10 @@ import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.get(ConfigService);
const httpPort = configService.get<string>('port');
console.log(`Linsten port http://192.168.60.11:${httpPort}`);
//swagger
const options = new DocumentBuilder()
.setTitle('【 API 】小鸡游戏接口')

View File

@ -14,15 +14,6 @@ export class OrderlogController {
return this.orderlogService.create(createOrderlogDto);
}
@Get()
findAll() {
return this.orderlogService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.orderlogService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateOrderlogDto: UpdateOrderlogDto) {

View File

@ -3,11 +3,13 @@ import { OrderlogService } from './orderlog.service';
import { OrderlogController } from './orderlog.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { OrderlogEntity } from './entities/orderlog.entity';
import { ChickensService } from 'src/chickens/chickens.service';
import { ChickenEntity } from 'src/chickens/entities/chicken.entity';
@Module({
imports: [TypeOrmModule.forFeature([OrderlogEntity])],
imports: [TypeOrmModule.forFeature([OrderlogEntity,ChickenEntity])],
controllers: [OrderlogController],
exports: [OrderlogService],
providers: [OrderlogService]
providers: [OrderlogService,ChickensService]
})
export class OrderlogModule { }

View File

@ -7,6 +7,7 @@ import { CreateOrderlogDto } from './dto/create-orderlog.dto';
import { UpdateOrderlogDto } from './dto/update-orderlog.dto';
import { OrderlogEntity } from './entities/orderlog.entity';
const prefix = 'order';
@Injectable()
export class OrderlogService {
constructor(
@ -24,12 +25,11 @@ export class OrderlogService {
return CustomResult(CODE.CODE_ORDER_INSERT_ERR);
}
findAll() {
return `This action returns all orderlog`;
}
findOne(id: number) {
return `This action returns a #${id} orderlog`;
/**API查询购买的商品订单详情信息 */
async paidGoodsInfo(orderid: string, userid: number) {
const orderGoods = await this.orderLogRepository.createQueryBuilder(prefix)
.select().where(`orderid=:orderid AND userid=:userid`, { orderid: orderid, userid: userid }).getRawOne();
return orderGoods;
}
update(id: number, updateOrderlogDto: UpdateOrderlogDto) {

View File

9
src/redis/keys.ts Normal file
View File

@ -0,0 +1,9 @@
/** 获取用户token key*/
export function getUserTokenKey(userId: number): string {
return 'ckgame:user:token:' + userId;
}
/**用户购物锁key */
export function getUserShoppingKey(userId: number, goodsId: number): string {
return 'ckgame:user:shopping:' + userId + '_' + goodsId;
}

35
src/redis/redis.ts Normal file
View File

@ -0,0 +1,35 @@
import { Injectable } from '@nestjs/common';
import { RedisService } from 'nestjs-redis';
@Injectable()
export class CacheService {
public client;
constructor(private redisService: RedisService) {
this.getClient();
}
async getClient() {
this.client = this.redisService.getClient()
}
//设置值的方法
async set(key: string, value: any, seconds?: number) {
value = JSON.stringify(value);
if (!this.client) {
await this.getClient();
}
if (!seconds) {
await this.client.set(key, value);
} else {
await this.client.set(key, value, 'EX', seconds);
}
}
//获取值的方法
async get(key: string) {
if (!this.client) {
await this.getClient();
}
var data = await this.client.get(key);
if (!data) return;
return JSON.parse(data);
}
}

View File

@ -5,10 +5,6 @@ export class BuyGoodsUserDto {
@IsInt()
userid: number;
@IsNotEmpty({ message: '用户token不能为空' })
@IsString()
token: string;
@IsNotEmpty({ message: '用户购买商品ID不能为空' })
@IsInt()
goodsid: number;

View File

@ -5,5 +5,5 @@ export class CreateUserDto {
token: string;
@ApiProperty()
uid: number;
userid: number;
}

View File

@ -29,28 +29,8 @@ export class UserEntity {
})
online_status: string;
// @Column({ comment: '上级用户ID', type: 'bigint' })
// parent_id: number;
// @Column({ comment: '父级从中获取钻石数量', type: 'bigint' })
// parent_gain: number;
// @Column({
// comment: '钻石领取状态(none-无;received-已领取;unreceive-未领取;wait_receive-n天后领取)',
// type: "enum",
// enum: ParentReceiveStatus,
// default: ParentReceiveStatus.NONE
// })
// parent_gain_status: string;
// @Column({ comment: '父级盈利领取时间', type: 'varchar', default: '' })
// parent_gain_time: string;
// @Column({ comment: '父级盈利失败原因', type: 'varchar', default: '' })
// parent_gain_reason: string;
// @Column({ comment: 'APP注册时间', type: 'varchar', default: '' })
// register_time: string;
@Column({ comment: '背景订单ID', type: 'varchar', default: '' })
backdropid: string;
@CreateDateColumn({ comment: '游戏玩家信息创建时间', type: 'timestamp' })
create_time: Date;

View File

@ -6,6 +6,7 @@ import { SuccessResult } from 'src/common/utils/result-utils';
import { HttpValidationPipe } from 'src/common/utils/HttpValidationPipe';
import { ApiImplicitQuery } from '@nestjs/swagger/dist/decorators/api-implicit-query.decorator';
import { BuyGoodsUserDto } from './dto/buygoods-user.dto';
import { CreateUserDto } from './dto/create-user.dto';
@ApiTags('用户数据接口')
@Controller('user')
@ -15,9 +16,23 @@ export class UserController {
//查询用户信息
@ApiOperation({ summary: '用户信息查询' })
@Get(':userid')
async findOne(@Param('userid') userid: number) {
return SuccessResult(await this.userService.findOne(userid));
@ApiImplicitQuery({
name: 'userid',
required: true,
description: '当前用户ID',
type: Number,
})
@ApiImplicitQuery({
name: 'userid',
required: true,
description: '当前用户ID',
type: Number,
})
@Get('user_info')
async userInfoQuery(
@Query() createUserDto: CreateUserDto,
) {
return await this.userService.initQuery(createUserDto);
}
//更新用户在线状态
@ -34,11 +49,12 @@ export class UserController {
return this.userService.update(+userid, updateUserDto);
}
//TODO 购买商品
//购买商品
@ApiOperation({ summary: '购买商品' })
@UsePipes(new HttpValidationPipe())
@Post('buy')
async buy(@Body() buyGoodsUserDto: BuyGoodsUserDto) {
return await this.userService.buy(buyGoodsUserDto);
}
}

View File

@ -8,6 +8,7 @@ import { GoodsEntity } from 'src/goods/entities/good.entity';
import { OrderlogEntity } from 'src/orderlog/entities/orderlog.entity';
import { OrderlogService } from 'src/orderlog/orderlog.service';
import { ConfigModule } from '@nestjs/config';
import { CacheService } from 'src/redis/redis';
@Module({
imports: [
@ -16,6 +17,6 @@ import { ConfigModule } from '@nestjs/config';
],
controllers: [UserController],
exports: [UserService],
providers: [UserService, GoodsService, OrderlogService]
providers: [UserService, GoodsService, OrderlogService,CacheService]
})
export class UserModule { }

View File

@ -1,12 +1,14 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { CODE } from 'src/common/code';
import { GoodsStatus, UserOnlieStatus } from 'src/common/const';
import { GoodsStatus, GoodsTypes, UserOnlieStatus } from 'src/common/const';
import { ExternalApiService } from 'src/common/utils/external-api';
import { CustomResult, SuccessResult } from 'src/common/utils/result-utils';
import { CustomResult, DataResultModel, SuccessResult } from 'src/common/utils/result-utils';
import { GoodsService } from 'src/goods/goods.service';
import { CreateOrderlogDto } from 'src/orderlog/dto/create-orderlog.dto';
import { OrderlogService } from 'src/orderlog/orderlog.service';
import { getUserShoppingKey, getUserTokenKey } from 'src/redis/keys';
import { CacheService } from 'src/redis/redis';
import { Repository } from 'typeorm';
import { BuyGoodsUserDto } from './dto/buygoods-user.dto';
import { CreateUserDto } from './dto/create-user.dto';
@ -22,23 +24,26 @@ export class UserService {
@InjectRepository(UserEntity)
private readonly userRepository: Repository<UserEntity>,
private readonly goodsService: GoodsService,
private readonly orderLogService: OrderlogService
private readonly orderLogService: OrderlogService,
private readonly cacheService: CacheService,
) { }
/**查询用户信息,没有则初始化 */
async init(createUserDto: CreateUserDto) {
async initQuery(createUserDto: CreateUserDto): Promise<DataResultModel> {
//初始化token
await this.initToken(createUserDto);
//查询用户信息
const userInfo = await this.findOne(createUserDto.uid);
const userInfo = await this.findOne(createUserDto.userid);
if (userInfo) return SuccessResult(userInfo);
//有信息则返回
const appUserInfo = await ExternalApiService.getAppUserInfo(createUserDto.uid, createUserDto.token);
if (userInfo) return userInfo;
const appUserInfo = await ExternalApiService.getAppUserInfo(createUserDto.userid, createUserDto.token);
//用户信息异常处理
if (!appUserInfo || appUserInfo.code != 200) return CustomResult(CODE.CODE_USER_INFO_ERR);
if (!appUserInfo || appUserInfo.code != 200) return appUserInfo;
//没有信息则初始化
const initRes = await this.initUser(appUserInfo);
const initRes = await this.initUser(appUserInfo.data);
if (!initRes) return CustomResult(CODE.CODE_INIT_USER_ERR);
return initRes;
return SuccessResult(initRes);
}
/**用户信息初始化 */
private async initUser(appUser: AppUserModel) {
@ -56,6 +61,7 @@ export class UserService {
return await this.userRepository.save(entity);
}
/**查询用户信息 */
async findOne(userid: number) {
const info = await this.userRepository.createQueryBuilder(prefix)
@ -65,6 +71,17 @@ export class UserService {
return info;
}
/**用户token初始化 */
async initToken(createUserDto: CreateUserDto) {
const tokenKey = getUserTokenKey(createUserDto.userid);
//查询Redis token 信息
const tokenInfo = await this.cacheService.get(tokenKey);
if (tokenInfo) return SuccessResult(tokenInfo);
//存储Redis
await this.cacheService.set(tokenKey, createUserDto.token);
return SuccessResult(createUserDto.token);
}
/**更新用户数据 */
async update(userid: number, updateUserDto: UpdateUserDto) {
updateUserDto.update_time = new Date();
@ -80,7 +97,8 @@ export class UserService {
/** 用户购买商品逻辑 */
async buy(buyGoodsUserDto: BuyGoodsUserDto) {
//查询APP用户信息
const appUserInfo = await ExternalApiService.getAppUserInfo(buyGoodsUserDto.userid, buyGoodsUserDto.token);
const token = await this.cacheService.get(getUserTokenKey(buyGoodsUserDto.userid));
const appUserInfo = await ExternalApiService.getAppUserInfo(buyGoodsUserDto.userid, token);
if (appUserInfo?.code != 200) return appUserInfo;
const user = appUserInfo.data;
@ -93,11 +111,16 @@ export class UserService {
const payCoin = goods.goods_price * buyGoodsUserDto.goods_count;//应支付价格
if (user.coin < payCoin) return CustomResult(CODE.CODE_APPUSER_COIN_NOT_ENOUGHT_ERR);
//TODO 扣减加锁 锁几秒
//扣减加锁 锁几秒
const locKeys = getUserShoppingKey(buyGoodsUserDto.userid, buyGoodsUserDto.goodsid);
const queryLock = await this.cacheService.get(locKeys);
if (queryLock) return CustomResult(CODE.CODE_USER_PAY_LOCK_ERR);
await this.cacheService.set(locKeys, true, 5);
//用户金额扣减
const subUserInfo = await ExternalApiService.subAppUserCoin(buyGoodsUserDto.userid, buyGoodsUserDto.token, payCoin);
console.log('扣减后用户信息',subUserInfo);
const subUserInfo = await ExternalApiService.subAppUserCoin(buyGoodsUserDto.userid, token, payCoin);
if (subUserInfo?.code != 200) return CustomResult(CODE.CODE_APPUSER_SUB_COIN_ERR);
//发放完成记录日志
const orderInfo: CreateOrderlogDto = {
@ -107,12 +130,11 @@ export class UserService {
goods_price: goods.goods_price,
goods_attribute: goods.goods_attribute
}
// const orderRes = await this.orderLogService.create(orderInfo);
// logger.debug(`购买订单日志结果: ${JSON.stringify(orderRes)}`);
// if (orderRes.code != 200) return CustomResult(CODE.CODE_GOODS_DEAL_ERR);
const orderRes = await this.orderLogService.create(orderInfo);
logger.debug(`购买订单日志结果: ${JSON.stringify(orderRes)}`);
if (orderRes.code != 200) return CustomResult(CODE.CODE_GOODS_DEAL_ERR);
return appUserInfo;
return SuccessResult();
return SuccessResult(orderRes.data);
}