🐞 fix(shop): 修复弱网下商品可买次数为负问题
This commit is contained in:
@@ -6,11 +6,12 @@ import { UserShopModel } from "../../../db/UserShop";
|
|||||||
import { handleCost, addItems } from "../../../services/role/rewardService";
|
import { handleCost, addItems } from "../../../services/role/rewardService";
|
||||||
import { SHOP } from "../../../pubUtils/dicParam";
|
import { SHOP } from "../../../pubUtils/dicParam";
|
||||||
import { HeroModel } from "../../../db/Hero";
|
import { HeroModel } from "../../../db/Hero";
|
||||||
import { checkShopInPurchase, getShopDicById, getShopListByType, getShopPrice } from "../../../services/shopService";
|
import { checkShopInPurchase, getShopDicById, getShopListByType, getShopPrice, getShopMaxBuyTimes } from "../../../services/shopService";
|
||||||
import { RewardInter } from "../../../pubUtils/interface";
|
import { RewardInter } from "../../../pubUtils/interface";
|
||||||
import { UserShopTypeModel } from "../../../db/UserShopType";
|
import { UserShopTypeModel } from "../../../db/UserShopType";
|
||||||
import { nowSeconds } from "../../../pubUtils/timeUtil";
|
import { nowSeconds } from "../../../pubUtils/timeUtil";
|
||||||
import { isGoodsHidden } from "../../../services/dataService";
|
import { isGoodsHidden } from "../../../services/dataService";
|
||||||
|
import { RoleModel } from './../../../db/Role';
|
||||||
|
|
||||||
export default function(app: Application) {
|
export default function(app: Application) {
|
||||||
return new ShopHandler(app);
|
return new ShopHandler(app);
|
||||||
@@ -70,14 +71,28 @@ export class ShopHandler {
|
|||||||
return resResult(checkResult);
|
return resResult(checkResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 总计可买次数(从配置表读取)
|
||||||
|
const totalCanBuyTimes = getShopMaxBuyTimes(dicShopItem.price);
|
||||||
|
if (!totalCanBuyTimes || totalCanBuyTimes <= 0) {
|
||||||
|
return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最大已买次数 = 总计可买次数 - 本次要买次数
|
||||||
|
const maxAlreadyBuyTimes = totalCanBuyTimes - count;
|
||||||
|
|
||||||
// 消耗
|
// 消耗
|
||||||
let cost = getShopPrice(dicShopItem.money, count, userShop?.count||0, dicShopItem.price);
|
let cost = getShopPrice(dicShopItem.money, count, userShop?.count||0, dicShopItem.price);
|
||||||
let costResult = await handleCost(roleId, sid, cost, ITEM_CHANGE_REASON.SHOP_PURCHASE);
|
let costResult = await handleCost(roleId, sid, cost, ITEM_CHANGE_REASON.SHOP_PURCHASE);
|
||||||
if(!costResult) return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH);
|
if(!costResult) return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH);
|
||||||
|
|
||||||
// 次数
|
// 次数
|
||||||
userShop = await UserShopModel.purchase(roleId, roleName, activityId, dicShopItem, count, seasonNum);
|
userShop = await UserShopModel.protectedPurchase(roleId, roleName, activityId, dicShopItem, count, seasonNum, maxAlreadyBuyTimes);
|
||||||
if(!userShop) return resResult(STATUS.BUY_COUNT_OVER);
|
if (!userShop) {
|
||||||
|
// rollback 消耗
|
||||||
|
let role = await RoleModel.findByRoleId(roleId);
|
||||||
|
addItems(roleId, role.roleName, sid, cost, ITEM_CHANGE_REASON.SHOP_PURCHASE);
|
||||||
|
return resResult(STATUS.BUY_COUNT_OVER);
|
||||||
|
}
|
||||||
|
|
||||||
// 获得
|
// 获得
|
||||||
let reward = [{
|
let reward = [{
|
||||||
|
|||||||
@@ -106,6 +106,22 @@ export function getShopPrice(goodId: number, count: number, buyCount: number, st
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取商品的最大购买次数
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {string} str 比如: 1&0|2&50|3&100|4&150|5&200
|
||||||
|
*/
|
||||||
|
export function getShopMaxBuyTimes(str: string) {
|
||||||
|
let arr = parseShopPrice(str);
|
||||||
|
for (let { times, maxTimes } of arr) {
|
||||||
|
if (maxTimes === -1) {
|
||||||
|
return times;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
function parseShopPrice(str: string) {
|
function parseShopPrice(str: string) {
|
||||||
let result = new Array<{ times: number, price: number, maxTimes: number }>();
|
let result = new Array<{ times: number, price: number, maxTimes: number }>();
|
||||||
if (!str) return result;
|
if (!str) return result;
|
||||||
|
|||||||
@@ -95,6 +95,33 @@ export default class UserShop extends BaseModel {
|
|||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 防止并发操作的购买
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @param {string} roleId
|
||||||
|
* @param {string} roleName
|
||||||
|
* @param {number} activityId
|
||||||
|
* @param {{ id: number, goodId: number, refreshType: number, shop: number, type: number, createTime?: number }} dicShopItem
|
||||||
|
* @param {number} inc
|
||||||
|
* @param {number} seasonNum
|
||||||
|
* @param {number} maxAlreadyBuyTimes: 最大已买次数,通过这个参数防止并发购买
|
||||||
|
* @return {*}
|
||||||
|
* @memberof UserShop
|
||||||
|
*/
|
||||||
|
public static async protectedPurchase(roleId: string, roleName: string, activityId: number, dicShopItem: { id: number, goodId: number, refreshType: number, shop: number, type: number, createTime?: number }, inc: number, seasonNum: number, maxAlreadyBuyTimes: number) {
|
||||||
|
let code = genCode(8);
|
||||||
|
let timeCondition = this.getRefreshCondition(seasonNum);
|
||||||
|
let { id, goodId, refreshType, shop, type, createTime = 0 } = dicShopItem;
|
||||||
|
|
||||||
|
let rec: UserShopType = await UserShopModel.findOneAndUpdate(
|
||||||
|
{ roleId, itemId: id, $or: timeCondition, shop, type, createTime, count: {$lte: maxAlreadyBuyTimes} },
|
||||||
|
{ $setOnInsert: { roleName, code, goodId, refreshType, seasonNum }, $inc: { count: inc }, $set: { activityId } },
|
||||||
|
{ new: true, upsert: true }
|
||||||
|
).lean();
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
public static async deleteAccount(roleId: string) {
|
public static async deleteAccount(roleId: string) {
|
||||||
let result = await UserShopModel.deleteMany({roleId});
|
let result = await UserShopModel.deleteMany({roleId});
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -25,7 +25,8 @@
|
|||||||
{ "id": 6, "desc": "获取信息", "route": "connector.entryHandler.getData", "param": {}, "interval": 1000 },
|
{ "id": 6, "desc": "获取信息", "route": "connector.entryHandler.getData", "param": {}, "interval": 1000 },
|
||||||
{ "id": 7, "desc": "刷新信息", "route": "connector.entryHandler.refresh", "param": {}, "interval": 1000 },
|
{ "id": 7, "desc": "刷新信息", "route": "connector.entryHandler.refresh", "param": {}, "interval": 1000 },
|
||||||
{ "id": 8, "desc": "捐赠", "route": "guild.donateHandler.donate", "param": {}, "interval": 200 },
|
{ "id": 8, "desc": "捐赠", "route": "guild.donateHandler.donate", "param": {}, "interval": 200 },
|
||||||
{ "id": 9, "desc": "碾压镇念塔", "route": "battle.towerBattleHandler.skipTower", "param": {}, "interval": 200 }
|
{ "id": 9, "desc": "碾压镇念塔", "route": "battle.towerBattleHandler.skipTower", "param": {}, "interval": 200 },
|
||||||
|
{ "id": 10, "desc": "商店购买商品", "route": "role.shopHandler.purchase", "param": {}, "interval": 50 }
|
||||||
],
|
],
|
||||||
"TIME_STAMP_OVER": 900000,
|
"TIME_STAMP_OVER": 900000,
|
||||||
"ACCESS_CODE_EXPIRE_TIME": 900000,
|
"ACCESS_CODE_EXPIRE_TIME": 900000,
|
||||||
|
|||||||
Reference in New Issue
Block a user