diff --git a/game-server/app/servers/activity/handler/selfServiceShopHandler.ts b/game-server/app/servers/activity/handler/selfServiceShopHandler.ts new file mode 100644 index 000000000..3cbddf4aa --- /dev/null +++ b/game-server/app/servers/activity/handler/selfServiceShopHandler.ts @@ -0,0 +1,95 @@ +import { Application, BackendSession } from 'pinus'; +import { deltaDays, resResult } from '../../../pubUtils/util'; +import { STATUS, ACTIVITY_RESOURCES_TYPE, ACTIVITY_TYPE, CURRENCY_BY_TYPE, CURRENCY_TYPE } from '../../../consts'; +import { SelfServiceShopData, SelfServiceShopItem, SelfServiceShopItemInfo } from '../../../domain/activityField/selfServiceShopField'; +import { addItems, handleCost } from '../../../services/rewardService'; +import { ActivitySelfServiceShopModel, ActivitySelfServiceShopModelType } from '../../../db/ActivitySelfServiceShop'; +import { ActivitySelfServiceGoodsModel, ActivitySelfServiceGoodsModelType } from '../../../db/ActivitySelfServiceGoods'; +import moment = require('moment'); +import Activity, { ActivityModel, ActivityModelType } from '../../../db/Activity'; +import { addSelfServiceShopGiftReward, getActivityData, getPlayerActivityData } from '../../../services/selfServiceShopActivityService'; + +export default function (app: Application) { + return new thirtyDaysHandler(app); +} + +export class thirtyDaysHandler { + constructor(private app: Application) { + } + + /************************自助商店****************************/ + + /** + * @description 获取自助商店数据 + * @param {{ }} msg + * @param {BackendSession} session + * @memberof thirtyDaysHandler + */ + async getSelfServiceShopActivity(msg: {}, session: BackendSession) { + const { } = msg; + const roleId = session.get('roleId'); + const serverId = session.get('serverId'); + + let playerData = await getActivityData(serverId, roleId) + if (!playerData) return resResult(STATUS.ACTIVITY_MISSING); + let playerGoods = await ActivitySelfServiceGoodsModel.findData(playerData.activityId, roleId, playerData.roundIndex, true); + return resResult(STATUS.SUCCESS, { playerData, playerGoods }); + } + + /** + * @description 购买礼包 + * @param {{ activityId: number, roundIndex: number, index: number, cellIndex: number}} msg + * @param {BackendSession} session + * @memberof thirtyDaysHandler + */ + async buyGift(msg: { activityId: number, roundIndex: number, index: number }, session: BackendSession) { + const { activityId, roundIndex, index } = msg; + const roleId = session.get('roleId'); + const serverId = session.get('serverId'); + const sid = session.get('sid'); + const roleName = session.get('roleName'); + const funcs: number[] = session.get('funcs'); + + let activityData: ActivityModelType = await ActivityModel.findActivity(activityId, true); + let playerData = new SelfServiceShopData(activityData); + let item = playerData.getItem(index); + + if (item.countMax > 0) {//限制购买次数 + let playerRecords: ActivitySelfServiceShopModelType[] = await ActivitySelfServiceShopModel.findDataByIndex(activityId, roleId, playerData.roundIndex, index); + if (playerRecords.length >= item.countMax) { + return resResult(STATUS.ACTIVITY_MAX_COUNT); + } + } + + let price = item.price; + let priceType = item.priceType; + + //检查资源 + if (priceType === ACTIVITY_RESOURCES_TYPE.GOODS) {//茶晶 + let result = await handleCost(roleId, sid, [{ id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.COIN), count: price }]); + if (!result) return resResult(STATUS.ROLE_MATERIAL_NOT_ENOUGH); + + } else if (priceType === ACTIVITY_RESOURCES_TYPE.RMB) {//RMB购买 + return resResult(STATUS.ACTIVITY_DATA_ERROR); + } + let result = await addSelfServiceShopGiftReward(roleId, roleName, sid, serverId, funcs, activityId, roundIndex, index, price, priceType); + return resResult(STATUS.SUCCESS, Object.assign(result, {})); + } + + /** + * @description 操作礼包 + * @param {{ activityId: number, roundIndex: number, index: number, cellIndex: number, gift: number, rewardIndex: number}} msg + * @param {BackendSession} session + * @memberof thirtyDaysHandler + */ + async saveGood(msg: { activityId: number, roundIndex: number, index: number, cellIndex: number, gift: number, rewardIndex: number }, session: BackendSession) { + const { activityId, roundIndex, index, cellIndex, gift, rewardIndex } = msg; + const roleId = session.get('roleId'); + const serverId = session.get('serverId'); + const sid = session.get('sid'); + const roleName = session.get('roleName'); + const funcs: number[] = session.get('funcs'); + await ActivitySelfServiceGoodsModel.addGoods(activityId, roleId, roundIndex, index, cellIndex, gift, rewardIndex); + return resResult(STATUS.SUCCESS, {}); + } +} diff --git a/game-server/app/services/giftPackageService.ts b/game-server/app/services/giftPackageService.ts index 786f9fb14..f690f39bb 100644 --- a/game-server/app/services/giftPackageService.ts +++ b/game-server/app/services/giftPackageService.ts @@ -98,9 +98,14 @@ function rewardItemData(reward: Array) { return { goods, heroes } } -function getSelectedReward(giftData: DicGiftPackage, selected: Array) { - let selectedReward = []; - +export function getSelectedReward(giftData: DicGiftPackage, selected: Array): Array { + let selectedReward: Array = []; + for (let i = 0; i < selected.length; i++) { + let index = selected[i]; + if (giftData.reward.length > index) { + selectedReward.push(giftData.reward[index]); + } + } return selectedReward; } diff --git a/game-server/app/services/selfServiceShopActivityService.ts b/game-server/app/services/selfServiceShopActivityService.ts new file mode 100644 index 000000000..fd9c151f1 --- /dev/null +++ b/game-server/app/services/selfServiceShopActivityService.ts @@ -0,0 +1,81 @@ +import { ACTIVITY_RESOURCES_TYPE, ACTIVITY_TYPE } from '../consts'; +import { ActivityModel, ActivityModelType } from '../db/Activity'; +import { ActivitySelfServiceGoodsModel, ActivitySelfServiceGoodsModelType } from '../db/ActivitySelfServiceGoods'; +import { ActivitySelfServiceShopModel, ActivitySelfServiceShopModelType } from '../db/ActivitySelfServiceShop'; +import { RewardParam } from '../domain/activityField/rewardField'; +import { SelfServiceShopData, SelfServiceShopItem } from '../domain/activityField/selfServiceShopField'; +import { gameData } from '../pubUtils/data'; +import { addReward, getSelectedReward } from './giftPackageService'; + +/** + * 获取活动数据 + * + * @param {number} serverId 区Id + * @param {number} activityId 活动Id + * @param {string} roleId 角色Id + * + */ +export async function getActivityData(serverId: number, roleId: string) { + let activityArray: ActivityModelType[] = await ActivityModel.findOpenActivityByType(ACTIVITY_TYPE.SELF_SERVICE_SHOP, new Date()) + activityArray = activityArray.sort((a, b) => { + return b.acvitityId - a.acvitityId + }); + if (activityArray.length > 0) { + let activityData = activityArray[0]; + let playerData = await getPlayerActivityData(activityData.acvitityId, serverId, roleId); + return playerData; + } + return null; +} + +/** + * 玩家活动数据 + * + * @param {number} serverId 区Id + * @param {number} activityId 活动Id + * @param {string} roleId 角色Id + * + */ +export async function getPlayerActivityData(activityId: number, serverId: number, roleId: string) { + let activityData: ActivityModelType = await ActivityModel.findActivity(activityId, true); + let playerData = new SelfServiceShopData(activityData); + + let playerRecords: ActivitySelfServiceShopModelType[] = await ActivitySelfServiceShopModel.findDataByPriceType(activityId, roleId, playerData.roundIndex, ACTIVITY_RESOURCES_TYPE.RMB); + + playerData.setPlayerRecords(playerRecords); + + return playerData; +} + +/** + * 结算礼包 + * + * @param {number} serverId 区Id + * @param {number} activityId 活动Id + * @param {string} roleId 角色Id + * @param {number} roundIndex 周期数 + * @param {number} index 货架 + * @param {number} price 价格 + * @param {number} priceType 价格类型 + * + */ +export async function addSelfServiceShopGiftReward(roleId: string, roleName: string, sid: string, serverId: number, funcs: number[], activityId: number, roundIndex: number, index: number, price: number, priceType: number) { + let playerGoods: ActivitySelfServiceGoodsModelType[] = await ActivitySelfServiceGoodsModel.findDataByIndex(activityId, roleId, roundIndex, index); + + let rewardArray: Array = []; + for (let obj of playerGoods) { + let giftID = obj.gift; + let selectedIndex = obj.rewardIndex; + let giftPackageData = gameData.giftPackage.get(giftID); + let selectedReward: Array = getSelectedReward(giftPackageData, [selectedIndex]) + rewardArray = rewardArray.concat(selectedReward) + } + let goodsStr = ''; + for (let obj of rewardArray) { + goodsStr += `${obj.type}&${obj.id}&${obj.count}|`; + } + let result = await addReward(roleId, roleName, sid, serverId, funcs, rewardArray); + //购买记录 + await ActivitySelfServiceShopModel.addBuyRecord(activityId, roleId, roundIndex, index, price, priceType, goodsStr); + return result +} \ No newline at end of file diff --git a/shared/consts/constModules/activityConst.ts b/shared/consts/constModules/activityConst.ts index 1bcb1ee9f..93773f8eb 100644 --- a/shared/consts/constModules/activityConst.ts +++ b/shared/consts/constModules/activityConst.ts @@ -17,6 +17,7 @@ export enum ACTIVITY_TYPE { GROWTH_FUND_MAIN_ELITE = 10, // 精英成长基金 GROWTH_FUND_MAIN_ELITE_VIP = 11, // 精英成长基金(高阶) THIRTY_DAYS = 12, // 30日目标活动 + SELF_SERVICE_SHOP = 13, // 自选商店 } /** @@ -36,4 +37,12 @@ export enum GIFT_PACKAGE_TYPE { ALL = 1, // 全部 SELECTED_X = 2, // 多选* RANDOM_X = 3, // 多随* +} + +/** + * 活动自助商店坑位类型 + */ +export enum SELF_SERVICE_SHOP_CELL_TYPE { + SPECIAL = 1, // 特殊 + NORMAL = 2, // 普通 } \ No newline at end of file diff --git a/shared/db/ActivitySelfServiceGoods.ts b/shared/db/ActivitySelfServiceGoods.ts new file mode 100644 index 000000000..33e3ffc46 --- /dev/null +++ b/shared/db/ActivitySelfServiceGoods.ts @@ -0,0 +1,55 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + +/** + * 自助商店货架上的商品 +*/ +@index({ roleId: 1 }) + +export default class ActivitySelfServiceGoods extends BaseModel { + @prop({ required: true }) + acvitityId: number; // 活动Id + @prop({ required: true }) + roundIndex: number; // 活动第几周期 从1开始,根据活动开始时间计算 + @prop({ required: true }) + roleId: string; // 用户Id + @prop({ required: true }) + index: number; // 第几个货架从1开始 + @prop({ required: true }) + cellIndex: number; // 第几个坑位从1开始 + @prop({ required: true }) + gift: number; // 礼包id + @prop({ required: true }) + rewardIndex: number; // 礼包中第几项奖励 + + + //添加选中的物品 + public static async addGoods(acvitityId: number, roleId: string, roundIndex: number, index: number, cellIndex: number, gift: number, rewardIndex: number) { + let result: ActivitySelfServiceGoodsModelType = await ActivitySelfServiceGoodsModel.findOneAndUpdate({ roleId, acvitityId, roundIndex, index, cellIndex }, + { $set: { gift, rewardIndex } }, { upsert: true, new: true }).lean(true); + return result; + } + + public static async findData(acvitityId: number, roleId: string, roundIndex: number, lean = true) { + let result: ActivitySelfServiceGoodsModelType[] = await ActivitySelfServiceGoodsModel.find({ roleId, acvitityId, roundIndex }, { + index: 1, cellIndex: 1, gift: 1, rewardIndex: 1, _id: -1 + }).lean(lean); + return result; + } + + //查询第几个货架数据 + public static async findDataByIndex(acvitityId: number, roleId: string, roundIndex: number, index: number, lean = true) { + let result: ActivitySelfServiceGoodsModelType[] = await ActivitySelfServiceGoodsModel.find({ roleId, acvitityId, roundIndex, index }).lean(lean); + return result; + } + + //删除活动领取记录 + public static async deleteActivity(acvitityId: number, roleId: string, roundIndex: number, index: number,) { + await ActivitySelfServiceGoodsModel.deleteMany({ roleId, acvitityId, index, roundIndex }); + } +} + +export const ActivitySelfServiceGoodsModel = getModelForClass(ActivitySelfServiceGoods); + +export interface ActivitySelfServiceGoodsModelType extends Pick, keyof ActivitySelfServiceGoods> { } +export type ActivitySelfServiceGoodsModelTypeParam = Partial; // 将所有字段变成可选项 \ No newline at end of file diff --git a/shared/db/ActivitySelfServiceShop.ts b/shared/db/ActivitySelfServiceShop.ts new file mode 100644 index 000000000..8764bd01c --- /dev/null +++ b/shared/db/ActivitySelfServiceShop.ts @@ -0,0 +1,60 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + + +/** + * 自助商店 +*/ +@index({ roleId: 1 }) + +export default class ActivitySelfServiceShop extends BaseModel { + @prop({ required: true }) + acvitityId: number; // 活动Id + @prop({ required: true }) + roundIndex: number; // 活动第几周期 从1开始,根据活动开始时间计算 + @prop({ required: true }) + roleId: string; // 用户Id + @prop({ required: true }) + index: number; // 第几个货架从1开始 + @prop({ required: true }) + price: number; //购买价格 + @prop({ required: true }) + priceType: number; //1.虚拟货币,2.RMB + @prop({ required: true }) + goods: string; // 商品信息 + + //添加购买记录 + public static async addBuyRecord(acvitityId: number, roleId: string, roundIndex: number, index: number, price: number, priceType: number, goods: string) { + await ActivitySelfServiceShopModel.insertMany([ + { roleId, acvitityId, roundIndex, index, price, priceType, goods } + ]) + } + + //根据活动id查询活动数据 + public static async findData(acvitityId: number, roleId: string, roundIndex: number, lean = true) { + let result: ActivitySelfServiceShopModelType[] = await ActivitySelfServiceShopModel.find({ roleId, acvitityId, roundIndex }).lean(lean); + return result; + } + + //查询第几个货架数据 + public static async findDataByIndex(acvitityId: number, roleId: string, roundIndex: number, index: number, lean = true) { + let result: ActivitySelfServiceShopModelType[] = await ActivitySelfServiceShopModel.find({ roleId, acvitityId, roundIndex, index }).lean(lean); + return result; + } + + //查询购买价格类型的数据 + public static async findDataByPriceType(acvitityId: number, roleId: string, roundIndex: number, priceType: number, lean = true) { + let result: ActivitySelfServiceShopModelType[] = await ActivitySelfServiceShopModel.find({ roleId, acvitityId, priceType, roundIndex }).lean(lean); + return result; + } + + //删除活动领取记录 + public static async deleteActivity(acvitityId: number, roleId: string, roundIndex: number, index: number,) { + await ActivitySelfServiceShopModel.deleteMany({ roleId, acvitityId, index, roundIndex }); + } +} + +export const ActivitySelfServiceShopModel = getModelForClass(ActivitySelfServiceShop); + +export interface ActivitySelfServiceShopModelType extends Pick, keyof ActivitySelfServiceShop> { } +export type ActivitySelfServiceShopModelTypeParam = Partial; // 将所有字段变成可选项 \ No newline at end of file diff --git a/shared/domain/activityField/selfServiceShopField.ts b/shared/domain/activityField/selfServiceShopField.ts new file mode 100644 index 000000000..5d608257a --- /dev/null +++ b/shared/domain/activityField/selfServiceShopField.ts @@ -0,0 +1,79 @@ +import { SELF_SERVICE_SHOP_CELL_TYPE, ACTIVITY_RESOURCES_TYPE, ACTIVITY_TYPE } from '../../consts'; +import { ActivityModelType } from '../../db/Activity'; +import { ActivitySelfServiceShopModelType } from '../../db/ActivitySelfServiceShop'; +import { deltaDays } from '../../pubUtils/util'; +import { ActivityBase } from './activityField'; + +// 自助商店数据坑位数据 +export class SelfServiceShopItemInfo { + cellIndex: number; // 第几个坑位,从1开始 + cellType: number; //坑位类型 SELF_SERVICE_SHOP_CELL_TYPE 1.特殊 2.普通 + gift: number; //礼包内容 + + constructor(data: any) { + this.cellIndex = data.cellIndex; + this.cellType = data.cellType; + this.gift = data.gift; + } +} + +// 自助商店数据 +export class SelfServiceShopItem { + index: number; // 第几个货架,从1开始 + name: string; //名称 + countMax: number = 0; // 最大可购买次数 0表示无限 + price: number; //价格 + priceType: number; //价格类型 ACTIVITY_RESOURCES_TYPE 2.物品表 3.RMB + data: Array = []; + + buyCount: number = 0; //已经购买次数 + + constructor(cellData: any) { + this.index = cellData.index; + this.name = cellData.name; + this.countMax = cellData.countMax; + this.price = cellData.price; + this.priceType = cellData.priceType; + this.data = []; + for (let obj of cellData.data) { + this.data.push(new SelfServiceShopItemInfo(obj)) + } + } +} + +// 自选商店 +export class SelfServiceShopData extends ActivityBase { + list: Array = [];//货架 + days: number = 20;//刷新周期天数 + roundIndex: number = 0; //第几周期 从1开始 + + public getItem(index: number) { + let listIndex = this.list.findIndex(obj => { return obj.index == index }); + return (listIndex != -1) ? this.list[listIndex] : null; + } + + //解析玩家购买记录 + public setPlayerRecords(data: ActivitySelfServiceShopModelType[]) { + for (let item of this.list) { + let buyData = data.filter(obj => { return obj.index === item.index }) + item.buyCount = buyData.length + } + } + + public initData(data: string) { + console.log('ddddddd', data) + let dataObj = JSON.parse(data); + this.days = dataObj.days; + + let arr = dataObj.data; + for (let obj of arr) { + this.list.push(new SelfServiceShopItem(obj)) + } + this.roundIndex = Math.ceil(this.todayIndex / this.days); + } + + constructor(activityData: ActivityModelType) { + super(activityData) + this.initData(activityData.data) + } +} \ No newline at end of file