Commit dbd8c94b authored by qinhaitao's avatar qinhaitao

test: 💍 数据接口

parent 04310f41
...@@ -107,6 +107,12 @@ export enum STAT_TYPE { ...@@ -107,6 +107,12 @@ export enum STAT_TYPE {
INITE_SUCCESS INITE_SUCCESS
} }
export enum CARD_PRIZE_STATUS {
LOCK,
UN_LOCK,
SUCCESS
}
export const appId = '${需要补充}' export const appId = '${需要补充}'
// 商铺id 拼接vip链接用 // 商铺id 拼接vip链接用
......
/** @format */ /** @format */
import { PRIZE_DATA_TYPE } from '../constants'
import { services, checkParams, preCheck, preUpdate } from '../decorator/common' import { services, checkParams, preCheck, preUpdate } from '../decorator/common'
import { resultsModel } from '../sdk' import { resultsModel } from '../sdk'
import { CommonCardService } from '../service/common' import { CommonCardService, CommonAwardsService } from '../service/common'
import { import { checkActivityTime, checkUserInfo, checkVip, checkInviteId, checkInviteUserCard } from '../utils/common/check'
checkActivityTime, import { updateUserInfo } from '../utils/common/update'
checkJoinId,
checkUserInfo,
checkVip,
checkGameTimes,
checkOpenPrizeStatus
} from '../utils/common/check'
import { updateUserInfo, reduceGameTimes } from '../utils/common/update'
export interface ISumitGameControllerInfos extends IControllerInfos { export interface ISumitGameControllerInfos extends IControllerInfos {
joinInfo: IJoinRecord joinInfo: IJoinRecord
...@@ -19,23 +13,115 @@ export interface ISumitGameControllerInfos extends IControllerInfos { ...@@ -19,23 +13,115 @@ export interface ISumitGameControllerInfos extends IControllerInfos {
export default class Card { export default class Card {
@checkParams(['activityId']) @checkParams(['activityId'])
@services([CommonCardService]) @services([CommonCardService, CommonAwardsService])
async getCollectCardInfo( async getCollectCardInfo(
context: IContext<IParams>, context: IContext<IParams>,
{ userInfo, activityInfo }: IControllerInfos, { userInfo, activityInfo }: IControllerInfos,
[cardService]: [CommonCardService] [cardService, awardsService]: [CommonCardService, CommonAwardsService]
) { ) {
const { activityId } = context.data
const { joinedTimes, gameTimes } = userInfo const { joinedTimes, gameTimes } = userInfo
const myCardInfo = cardService.getMyCardInfo(userInfo)
const joinedTimesPrizeList = await cardService.getCardPrizeList(
activityId,
PRIZE_DATA_TYPE.JOIN_TIMES,
'needTimes',
joinedTimes
)
const collectedCardTypePrizeList = await cardService.getCardPrizeList(
activityId,
PRIZE_DATA_TYPE.CARD_TYPE_AWARD,
'needCards',
myCardInfo.cardTypeCollectedCount
)
return resultsModel.success({
joinedTimes,
gameTimes,
...myCardInfo,
joinedTimesPrizeList,
collectedCardTypePrizeList
})
} }
@checkParams(['activityId']) @checkParams(['activityId'])
@services([CommonCardService]) @services([CommonCardService])
@preCheck([checkActivityTime, checkVip]) @preCheck([
async doJoin( checkActivityTime,
checkVip,
checkUserInfo(
{
gameTimes: { $gte: 1 }
},
'抽卡次数不足'
)
])
@preUpdate([
updateUserInfo({
$where: ` this.gameTimes >= 1`,
$inc: { gameTimes: -1 }
})
])
async doJoin(context: IContext<IParams>, { userInfo }: IControllerInfos, [cardService]: [CommonCardService]) {
const { activityId } = context.data
const cardResult = await cardService.collectCard(activityId, userInfo)
const recordResult = await cardService.addCollectRecord(userInfo, cardResult)
return resultsModel.success({
...cardResult,
...recordResult
})
}
// 获取中奖轮播
@checkParams(['activityId'])
@services([CommonCardService, CommonAwardsService])
async getAwardsCarouselList(
context: IContext<IParams>, context: IContext<IParams>,
{ userInfo, activityInfo }: IControllerInfos, { userInfo, activityInfo }: IControllerInfos,
[cardService]: [CommonCardService] [cardService, awardsService]: [CommonCardService, CommonAwardsService]
) { ) {
const { joinedTimes, gameTimes } = userInfo const { activityId } = context.data
const list = await cardService.getAwardsCarouselList(activityId)
return resultsModel.success({
list
})
}
// 我的卡牌详情
@checkParams(['activityId'])
@services([CommonCardService, CommonAwardsService])
async getMyCardsInfo(context: IContext<IParams>, { userInfo }: IControllerInfos, [cardService]: [CommonCardService]) {
const { activityId } = context.data
const list = await cardService.getMyCardsInfo(activityId, userInfo)
return resultsModel.success({
list
})
}
// 获取好友赠送卡片
@checkParams(['activityId', 'type', 'inviteId'])
@services([CommonCardService, CommonAwardsService])
@preCheck([checkActivityTime, checkInviteId, checkInviteUserCard])
async getGiftCard(
context: IContext<IParams>,
{ userInfo }: IControllerInfos,
[cardService]: [CommonCardService],
{ inviteUserInfo }: IPreCheckData
) {
const { activityId, type } = context.data
const giftResult = await cardService.getGiftCard(activityId, type, userInfo, inviteUserInfo)
return resultsModel.success(giftResult)
} }
} }
...@@ -16,7 +16,7 @@ export default function preCheck(checks: IFunction[]) { ...@@ -16,7 +16,7 @@ export default function preCheck(checks: IFunction[]) {
for (let i = 0; i < checks.length; i++) { for (let i = 0; i < checks.length; i++) {
const checkFn = checks[i] const checkFn = checks[i]
let result = await checkFn.apply(target, [context, { ...otherArgs }, services]) let result = await checkFn.apply(target, [context, { ...otherArgs }, services, preCheckData])
result = result || {} result = result || {}
// 校验报错 // 校验报错
if ((result as IErrorResult)?.success === false && (result as IErrorResult)?.code) { if ((result as IErrorResult)?.success === false && (result as IErrorResult)?.code) {
......
...@@ -17,6 +17,9 @@ import CustomTest1Controller from './controller/custom/test1.controller' ...@@ -17,6 +17,9 @@ import CustomTest1Controller from './controller/custom/test1.controller'
const CustomTest1ControllerInstance = new CustomTest1Controller() const CustomTest1ControllerInstance = new CustomTest1Controller()
import CustomTest2Controller from './controller/custom/test2.controller' import CustomTest2Controller from './controller/custom/test2.controller'
const CustomTest2ControllerInstance = new CustomTest2Controller() const CustomTest2ControllerInstance = new CustomTest2Controller()
import CommonCardController from './controller/card.controller'
const { getAwardsCarouselList, getCollectCardInfo, getGiftCard, getMyCardsInfo, doJoin } = new CommonCardController()
export default { export default {
getVipInfo: CommonUserControllerInstance.getVipInfo, getVipInfo: CommonUserControllerInstance.getVipInfo,
...@@ -38,5 +41,11 @@ export default { ...@@ -38,5 +41,11 @@ export default {
testAddStat: CustomTest1ControllerInstance.testAddStat, testAddStat: CustomTest1ControllerInstance.testAddStat,
testGetStats: CustomTest1ControllerInstance.testGetStats, testGetStats: CustomTest1ControllerInstance.testGetStats,
test2addStat: CustomTest2ControllerInstance.test2addStat, test2addStat: CustomTest2ControllerInstance.test2addStat,
test2getStats: CustomTest2ControllerInstance.test2getStats test2getStats: CustomTest2ControllerInstance.test2getStats,
// 卡牌类
getAwardsCarouselList,
getCollectCardInfo,
getGiftCard,
getMyCardsInfo,
doJoin
} }
...@@ -285,11 +285,17 @@ export default class AwardsService extends UserService { ...@@ -285,11 +285,17 @@ export default class AwardsService extends UserService {
} }
// 根据查询条件获取奖品配置 // 根据查询条件获取奖品配置
async getPrizeConfig(query: { activityId: string; [queryParam: string]: any }): Promise<IActivityPrize[]> { async getPrizeConfig(
return this.activityprizedao.find({ query: { activityId: string; [queryParam: string]: any },
deleteStatus: DELETE_STATUS.NORMAL, projection: IFindProjection = {}
...query ): Promise<IActivityPrize[]> {
}) return this.activityprizedao.find<IActivityPrize>(
{
deleteStatus: DELETE_STATUS.NORMAL,
...query
},
projection
)
} }
// 根据概率抽取奖品 // 根据概率抽取奖品
......
...@@ -4,20 +4,243 @@ ...@@ -4,20 +4,243 @@
* @format * @format
*/ */
import { BaseDao, TBAPIS } from '../../sdk' import { BaseDao, resultsModel, TBAPIS } from '../../sdk'
import { JOIN_DB_NAME } from '../../db' import { JOIN_DB_NAME } from '../../db'
import { ACTIVITY_STATUS } from '../../constants' import { ACTIVITY_STATUS, CARD_PRIZE_STATUS, PRIZE_DATA_TYPE, PRIZE_TYPE } from '../../constants'
import { getToday } from '../../utils' import { getToday } from '../../utils'
import UserService from './user.service' import UserService from './user.service'
import AwardService from './awards.service'
import { CODE_TYPES } from '../../errorCode'
import { uniq } from 'lodash'
export default class CardService extends UserService { export default class CardService extends UserService {
context: IContext<IParams> context: IContext<IParams>
joindao: IBaseDao joindao: IBaseDao
awardService: AwardService
constructor(context: IContext<IParams>) { constructor(context: IContext<IParams>) {
super(context) super(context)
this.joindao = new BaseDao(context, JOIN_DB_NAME) this.joindao = new BaseDao(context, JOIN_DB_NAME)
this.awardService = new AwardService(context)
} }
// 集卡 // 集卡
async collectCard(activityId: string) {} async collectCard(activityId: string, userInfo: IUserInfo) {
const card = await this.getCard(activityId)
const { cardType, _id, image, name, type } = card
if (type === PRIZE_TYPE.THANKS)
return {
type: PRIZE_TYPE.THANKS,
name: '谢谢参与'
}
const reduceResult = await this.awardService.reduceStock(_id)
if ((reduceResult as ICodeType)?.code) return CODE_TYPES.ERROR_NO_STOCK
userInfo.cardInfo[cardType] = (userInfo.cardInfo?.[cardType] || 0) + 1
const updateResult = await this.updateUser(userInfo._id, {
$inc: {
joinedTimes: 1,
[`cardInfo.${cardType}`]: 1
}
})
if (updateResult !== 1) return CODE_TYPES.SYSTEM_ERROR
const myCardInfo = this.getMyCardInfo(userInfo, cardType)
return {
cardType,
image,
name,
type,
...myCardInfo
}
}
getMyCardInfo(userInfo: IUserInfo, cardType?: number) {
const { cardInfo } = userInfo
// 该卡片收集数量
const currCardCollectedCount = cardType ? cardInfo?.[cardType] || 0 : undefined
// 已收集卡片的总数量
const cardQuantityCollectedCount = Object.values(cardInfo).reduce((total, count) => total + count, 0)
// 已收集卡片类型
const cardTypeCollectedCount = Object.keys(cardInfo).length
return {
currCardCollectedCount,
cardQuantityCollectedCount,
cardTypeCollectedCount
}
}
async addCollectRecord(userInfo: IUserInfo, cardResult: object) {
const { openId } = this.context
const { activityId } = this.context.data
const { userNick } = userInfo
const recordId = await this.joindao.insertOne({
activityId,
userNick,
openId,
...cardResult,
createTime: Date.now(),
createDay: getToday()
})
return { recordId }
}
// 获取卡片
async getCard(activityId: string) {
const cardPool = await this.awardService.getPrizeConfig({
activityId,
prizeDataType: PRIZE_DATA_TYPE.CARD
})
let card = await this.awardService.getPrizeByProbability(cardPool)
const thanksPrize = cardPool.find(v => v.type === PRIZE_TYPE.THANKS) || {
type: PRIZE_TYPE.THANKS,
prizeDataType: PRIZE_DATA_TYPE.CARD,
name: '谢谢参与'
}
!card && (card = thanksPrize)
return card
}
async getCardPrizeList(activityId: string, prizeDataType: number, needKey: string, userCount: number) {
const { openId } = this.context
const joinedTimesPrizePool = await this.awardService.getPrizeConfig(
{
activityId,
prizeDataType
},
{
projection: { type: 1, image: 1, prizeDataType: 1, name: 1 }
}
)
// 抽奖次数奖池分类 从小到大排列
const category = uniq(joinedTimesPrizePool.map(v => +v[needKey])).sort()
const prizeMapper = category.reduce((prev, curr) => {
return {
...prev,
[`${curr}`]: joinedTimesPrizePool.filter(v => v[needKey] === curr)
}
}, {})
const awardList = await this.awardService.getAwardsInfoList(
{
activityId,
openId,
prizeDataType
},
{
projection: { type: 1, image: 1, prizeDataType: 1, name: 1 }
}
)
const prizeList = category.map(key => {
return {
[needKey]: key,
status: setCardPrizeStatus(userCount, key, awardList),
prizeList: prizeMapper[key]
}
})
function setCardPrizeStatus(userCount: number, needCount: number, awardList: IAwards[]) {
if (userCount < needCount) return CARD_PRIZE_STATUS.LOCK
if (needCount >= userCount && !awardList.some(v => v[needKey] === needCount)) return CARD_PRIZE_STATUS.UN_LOCK
if (needCount >= userCount && awardList.some(v => v[needKey] === needCount)) return CARD_PRIZE_STATUS.SUCCESS
}
return prizeList
}
async getAwardsCarouselList(activityId: string, limit: number = 30) {
const list = await this.awardService.getAwardsInfoList(
{
activityId,
prizeDataType: {
$in: [PRIZE_DATA_TYPE.CARD_TYPE_AWARD, PRIZE_DATA_TYPE.JOIN_TIMES]
}
},
{
sort: {
createTime: 1
},
projection: {
name: 1,
image: 1,
type: 1,
prizeDataType: 1,
avatar: 1,
userNick: 1
},
limit
}
)
return list
}
async getMyCardsInfo(activityId: string, userInfo: IUserInfo) {
const { cardInfo } = userInfo
const cardPool = await this.awardService.getPrizeConfig({
activityId,
prizeDataType: PRIZE_DATA_TYPE.CARD
})
return Object.keys(cardInfo).map(type => {
const { name, image } = cardPool.find(v => v.cardType === +type) || {}
return {
type,
name,
image,
count: cardInfo[type] || 0
}
})
}
async getGiftCard(activityId: string, type: number, userInfo: IUserInfo, inviteUserInfo: IUserInfo) {
// 扣除邀请者的对应卡牌
const reduceResult = await this.userdao.update(
{
_id: inviteUserInfo._id,
$where: `this.cardInfo.${type} >= 1`
},
{
$inc: { [`cardInfo.${type}`]: -1 }
}
)
if (!reduceResult) return CODE_TYPES.SYSTEM_ERROR
// 增加受赠者的卡牌
const addResult = await this.updateUser(userInfo._id, {
$inc: { [`cardInfo.${type}`]: -1 }
})
if (!addResult) return CODE_TYPES.SYSTEM_ERROR
const cardInfo =
(await this.awardService.getPrizeConfig({
activityId,
prizeDataType: PRIZE_DATA_TYPE.CARD,
cardType: +type
})?.[0]) || {}
const { name, image } = cardInfo
return {
name,
image,
type
}
}
} }
/** @format */ /** @format */
interface IAwards { type IAwards = ICommonAwards & ICustomAwards
interface ICustomAwards {
needTimes?: number
}
interface ICommonAwards {
_id?: string _id?: string
id?: string id?: string
openId: string openId: string
......
/** @format */ /** @format */
type IActivityPrize = ICommonActivityPrize & ICustomActivityPrize
interface IActivityPrize { interface ICustomActivityPrize {
cardType?: number
needTimes?: number
needCards?: number
}
interface ICommonActivityPrize {
_id?: string _id?: string
id?: string id?: string
activityId?: string activityId?: string
......
...@@ -17,3 +17,5 @@ interface ICodeType { ...@@ -17,3 +17,5 @@ interface ICodeType {
} }
type IResult<T> = T extends ICodeType ? IErrorResult : IErrorResult | ISuccessResult<T> type IResult<T> = T extends ICodeType ? IErrorResult : IErrorResult | ISuccessResult<T>
type IPreCheckResult = IErrorResult | { [key: string]: any }
...@@ -3,7 +3,18 @@ ...@@ -3,7 +3,18 @@
import { resultsModel } from '../../../sdk' import { resultsModel } from '../../../sdk'
import { CODE_TYPES } from '../../../errorCode' import { CODE_TYPES } from '../../../errorCode'
export default async function checkActivityTime(context: IContext<IParams>, { activityInfo }: IControllerInfos) { /**
* 检查活动时间
*
* @export
* @param {IContext<IParams>} context
* @param {IControllerInfos} { activityInfo }
* @return {*} {(Promise<IPreCheckResult}
*/
export default async function checkActivityTime(
context: IContext<IParams>,
{ activityInfo }: IControllerInfos
): Promise<IPreCheckResult> {
// 活动不存在 // 活动不存在
if (!activityInfo) { if (!activityInfo) {
return resultsModel.error(CODE_TYPES.ERROR_NO_ACTIVITY) return resultsModel.error(CODE_TYPES.ERROR_NO_ACTIVITY)
......
...@@ -4,7 +4,7 @@ import { resultsModel } from '../../../sdk' ...@@ -4,7 +4,7 @@ import { resultsModel } from '../../../sdk'
import { CODE_TYPES } from '../../../errorCode' import { CODE_TYPES } from '../../../errorCode'
import { isBoolean } from 'lodash' import { isBoolean } from 'lodash'
export default async function checkFollow(context: IContext<IParams>) { export default async function checkFollow(context: IContext<IParams>): Promise<IPreCheckResult> {
const { isFollow } = context.data const { isFollow } = context.data
if (!isBoolean(isFollow)) return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '缺少isFollow参数') if (!isBoolean(isFollow)) return resultsModel.error(CODE_TYPES.PARAMS_ERROR, '缺少isFollow参数')
......
/** @format */
import { resultsModel } from '../../../sdk'
import { CODE_TYPES } from '../../../errorCode'
import { isBoolean } from 'lodash'
export default async function checkInviteUserCard(
context: IContext<{ type: number; activityId: string; inviteId: string }>,
{}: IControllerInfos,
[],
{ inviteUserInfo }: IPreCheckData
): Promise<IPreCheckResult> {
const { type } = context.data
if (!inviteUserInfo) {
console.error(`checkInviteUserCard必须搭配 checkInviteId使用`)
}
const { cardInfo } = inviteUserInfo
if (!cardInfo?.type) return resultsModel.error(CODE_TYPES.SYSTEM_ERROR, '邀请者该卡片不足')
}
...@@ -12,7 +12,7 @@ import checkVip from './checkVip' ...@@ -12,7 +12,7 @@ import checkVip from './checkVip'
import checkUserInfo, { checkGameTimes } from './checkUserInfo' import checkUserInfo, { checkGameTimes } from './checkUserInfo'
import checkJoinId from './checkJoinId' import checkJoinId from './checkJoinId'
import checkOpenPrizeStatus from './checkOpenPrizeStatus' import checkOpenPrizeStatus from './checkOpenPrizeStatus'
import checkInviteUserCard from './checkInviteUserCard'
const check = { const check = {
checkActivityTime, checkActivityTime,
checkExchangeCreditsTask, checkExchangeCreditsTask,
...@@ -29,7 +29,8 @@ const check = { ...@@ -29,7 +29,8 @@ const check = {
checkUserInfo, checkUserInfo,
checkJoinId, checkJoinId,
checkGameTimes, checkGameTimes,
checkOpenPrizeStatus checkOpenPrizeStatus,
checkInviteUserCard
} }
export default check export default check
...@@ -50,5 +51,6 @@ export { ...@@ -50,5 +51,6 @@ export {
checkUserInfo, checkUserInfo,
checkJoinId, checkJoinId,
checkGameTimes, checkGameTimes,
checkOpenPrizeStatus checkOpenPrizeStatus,
checkInviteUserCard
} }
...@@ -28,7 +28,7 @@ export default async function updateOrderGoods( ...@@ -28,7 +28,7 @@ export default async function updateOrderGoods(
const orderResult = await getUserOrderlist( const orderResult = await getUserOrderlist(
this.context, this.context,
//@ts-ignore //@ts-ignore
activityInfo?.startTime || Date.now(), userInfo.createTime || activityInfo?.startTime || Date.now(),
Date.now() Date.now()
) )
......
/** @format */
import { CARD_PRIZE_STATUS } from '../../constants'
export function setCardPrizeStatus(joinedTimes: number, needTimes: number, joinedTimesAwardList: IAwards[]) {
if (joinedTimes < needTimes) return CARD_PRIZE_STATUS.LOCK
if (needTimes >= joinedTimes && !joinedTimesAwardList.some(v => v.needTimes === needTimes))
return CARD_PRIZE_STATUS.UN_LOCK
if (needTimes >= joinedTimes && joinedTimesAwardList.some(v => v.needTimes === needTimes))
return CARD_PRIZE_STATUS.SUCCESS
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment