From 3bdd960cfa97213646a1ece2bb1d758465b9cfbe Mon Sep 17 00:00:00 2001 From: zhl Date: Mon, 7 Jun 2021 16:32:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=8A=BD=E5=A5=96=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/api.md | 32 +++--- src/api/controllers/game_user.controller.ts | 2 +- src/api/controllers/lottery.controller.ts | 105 ++++++++++++++++++++ src/models/shop/ShopCfg.ts | 6 ++ src/utils/number.util.ts | 24 +++++ 5 files changed, 154 insertions(+), 15 deletions(-) create mode 100644 src/api/controllers/lottery.controller.ts diff --git a/doc/api.md b/doc/api.md index 1e232a6..07d6986 100644 --- a/doc/api.md +++ b/doc/api.md @@ -526,12 +526,15 @@ 3. Response: JSON ```js -[{ - "name": '显示名', - "reward_type": '奖励物品的id', - "reward_count": 100, //奖励物品数量 - "icon": "item/item_0" // 奖励物品的图片地址, 可能是本地,远程, 如果该字段为空的话, 需要取本地的默认值 - }] +[ // 奖励列表 + { + coupon: '优惠券的id', + name: '优惠券名', + count: 1, //数量 + couponUrl: '优惠券详情图的url', + rewardType: 0, // 0: 优惠券, 1: 抽奖券 + } +] ``` ### 14. 抽奖 @@ -553,12 +556,13 @@ 3. Response: JSON ```js -{ - "name": '显示名', - "reward_type": '奖励物品的id', - "reward_count": 100, //奖励物品数量 - "icon": "item/item_0" // 奖励物品的图片地址, 可能是本地,远程, 如果该字段为空的话, 需要取本地的默认值 -} +[{ // 本次请求新获得的物品 + coupon: '优惠券的id', + name: '优惠券名', + count: 1, //数量 + couponUrl: '优惠券详情图的url', + rewardType: 0, // 0: 优惠券, 1: 抽奖券 +}] ``` @@ -583,13 +587,13 @@ ```js { num: 10, // 已邀请人数 - newget: [ // 本次请求新获得的物品 + newget: [{ // 本次请求新获得的物品 coupon: '优惠券的id', name: '优惠券名', count: 1, //数量 couponUrl: '优惠券详情图的url', rewardType: 0, // 0: 优惠券, 1: 抽奖券 - ] + }] rewards: [ // 奖励列表 { coupon: '优惠券的id', diff --git a/src/api/controllers/game_user.controller.ts b/src/api/controllers/game_user.controller.ts index 756c5e4..a89fd8b 100644 --- a/src/api/controllers/game_user.controller.ts +++ b/src/api/controllers/game_user.controller.ts @@ -94,7 +94,7 @@ class GameUserController extends BaseController { throw new ZError(12, '当前店铺未配置相关信息') } if (!cfg.share_cfgs || cfg.share_cfgs.length === 0) { - throw new ZError(12, '当前店铺未配置相关信息') + throw new ZError(13, '当前店铺未配置相关信息') } let rewardList = [] let newItems: any[] = [] diff --git a/src/api/controllers/lottery.controller.ts b/src/api/controllers/lottery.controller.ts new file mode 100644 index 0000000..e17319a --- /dev/null +++ b/src/api/controllers/lottery.controller.ts @@ -0,0 +1,105 @@ +import BaseController from '../../common/base.controller' +import { role, router } from '../../decorators/router' +import { ZError } from '../../common/ZError' +import { Shop } from '../../models/shop/Shop' +import { ShopCfg } from '../../models/shop/ShopCfg' +import { Coupon } from '../../models/shop/Coupon' +import { getCouponUrl } from '../../services/File' +import { UserItem } from '../../models/user/UserItem' +import { LOTTERY_TICKET } from '../../constants/BaseConst' +import { UserReward } from '../../models/user/UserReward' +import { random_prob } from '../../utils/number.util' + +class LotteryController extends BaseController { + @role('anon') + @router('post /api/:accountId/lottery_info') + async info(req: any) { + const { accountId, sid, sessionid } = req.params + if (!sid) { + throw new ZError(10, '缺少必要参数: sid') + } + const shop = await Shop.fetchByID(sid) + if (!shop) { + throw new ZError(11, '无法找到对应店铺') + } + const cfg = await ShopCfg.findOne({ shop: shop.id }) + if (!cfg) { + throw new ZError(12, '当前店铺未配置相关信息') + } + if (!cfg.lottery_cfgs || cfg.lottery_cfgs.length === 0) { + throw new ZError(12, '当前店铺未配置相关信息') + } + let rewardList = [] + let couponMap: Map = new Map() + for (let reward of cfg.lottery_cfgs) { + let name = '抽奖券' + let couponUrl = reward.icon + if (reward.rewardType === 0) { + if (!couponMap.has(reward.coupon)) { + let coupon = await Coupon.findById(reward.coupon) + couponMap.set(coupon.id, coupon) + } + name = couponMap.get(reward.coupon).name + couponUrl = reward.icon || getCouponUrl(shop.id, reward.coupon) + } + rewardList.push({ + coupon: reward.coupon, + name, + count: reward.count, + couponUrl, + rewardType: reward.rewardType, + }) + } + return rewardList + } + + @role('anon') + @router('post /api/:accountId/lottery') + async draw(req: any) { + const { accountId, sid, sessionid } = req.params + if (!sid) { + throw new ZError(10, '缺少必要参数: sid') + } + const shop = await Shop.fetchByID(sid) + if (!shop) { + throw new ZError(11, '无法找到对应店铺') + } + const cfg = await ShopCfg.findOne({ shop: shop.id }) + if (!cfg) { + throw new ZError(12, '当前店铺未配置相关信息') + } + if (!cfg.lottery_cfgs || cfg.lottery_cfgs.length === 0) { + throw new ZError(13, '当前店铺未配置相关信息') + } + const count = await UserItem.fetchCount({ accountId, shop: shop.id, item: LOTTERY_TICKET }) + if (count < 1) { + throw new ZError(14, '券不够了') + } + await UserItem.addOne({ + accountId, + shop: shop.id, + item: LOTTERY_TICKET, + count: -1, + reason: 'lottery', + params: {}, + }) + let arr = [] + for (let data of cfg.lottery_cfgs) { + arr.push(data.rank) + } + let idx = random_prob(arr) + const reward = cfg.lottery_cfgs[idx] + let obj = await UserReward.saveOneRecord({ + accountId, + shop: shop.id, + itemId: reward.coupon, + count: reward.count, + rewardId: reward._id + '', + activityId: 'lottery', + source: 'lottery', + }) + let rewardList = [] + rewardList.push(obj) + return rewardList + } +} diff --git a/src/models/shop/ShopCfg.ts b/src/models/shop/ShopCfg.ts index b0b3051..63b5b9f 100644 --- a/src/models/shop/ShopCfg.ts +++ b/src/models/shop/ShopCfg.ts @@ -30,6 +30,12 @@ export class ShareCfgClass extends Base { } export class LotteryCfgClass extends Base { + /** + * 获取概率 + * @type {number} + */ + @prop() + public rank: number @prop() public name: string diff --git a/src/utils/number.util.ts b/src/utils/number.util.ts index 1862094..f90f105 100644 --- a/src/utils/number.util.ts +++ b/src/utils/number.util.ts @@ -8,3 +8,27 @@ export function getRandom(max: number, min?: number): number { min = min || 0 return Math.floor(Math.random() * (max - min) + min) } + +/** + * 根据概率数组获取随机index + * @since 1.0.0 + * @param prob_array 概率数组 + */ +export function random_prob(prob_array: number[]): number { + let total = 0 + for (let _d of prob_array) { + total += _d + } + prob_array = prob_array.map(o => o / total) + // 获取随机数 + let r = Math.random() + // 对概率数组的处理 + let s = prob_array + .map((v, index) => { + return { index: index, prob: v } + }) + .sort((a, b) => a.prob - b.prob) + // 判断随机位置 + let result = s.find(v => (r -= v.prob) <= 0) + return result ? result.index : s.length - 1 +}