diff --git a/game-server/app/servers/activity/handler/weeklyFundHandler.ts b/game-server/app/servers/activity/handler/weeklyFundHandler.ts new file mode 100644 index 000000000..b2421a6e7 --- /dev/null +++ b/game-server/app/servers/activity/handler/weeklyFundHandler.ts @@ -0,0 +1,68 @@ +import { Application, BackendSession, HandlerService, } from 'pinus'; +import { resResult } from '../../../pubUtils/util'; +import { ITEM_CHANGE_REASON, STATUS } from '../../../consts'; +import { getWeeklyFundDataShow, getWeeklyFundData } from '../../../services/activity/weeklyFundService'; +import { ActivityWeeklyFundModel } from '../../../db/ActivityWeeklyFund'; +import { addReward, stringToRewardParam } from '../../../services/activity/giftPackageService'; + + +export default function (app: Application) { + new HandlerService(app, {}); + return new WeeklyFundHandler(app); +} + +export class WeeklyFundHandler { + constructor(private app: Application) { + } + + /************************周基金****************************/ + + /** + * @description 获取数据 + * @param {BackendSession} session + * @memberof WeeklyFundHandler + */ + async getData(msg: { activityId: number }, session: BackendSession) { + const { activityId } = msg; + const roleId = session.get('roleId'); + const serverId = session.get('serverId'); + + let playerData = await getWeeklyFundDataShow(activityId, serverId, roleId); + if (!playerData) return resResult(STATUS.ACTIVITY_MISSING); + + return resResult(STATUS.SUCCESS, playerData); + } + + /** + * @description 签到 + * @param {BackendSession} session + * @memberof WeeklyFundHandler + */ + async sign(msg: { activityId: number, dayIndex: number }, session: BackendSession) { + + const { activityId, dayIndex } = msg; + const roleId = session.get('roleId'); + const roleName = session.get('roleName'); + const sid = session.get('sid'); + const serverId = session.get('serverId'); + + let playerData = await getWeeklyFundData(activityId, serverId, roleId); + if (!playerData) return resResult(STATUS.ACTIVITY_MISSING); + + if(!playerData.hasBought) return resResult(STATUS.ACTIVITY_WEEKLY_FUND_NOT_BOUGHT); + let signReward = playerData.findSignReward(dayIndex); + if(!signReward) return resResult(STATUS.ACTIVITY_WEEKLY_FUND_NOT_FOUND); + if(signReward.hasReceived) return resResult(STATUS.ACTIVITY_WEEKLY_FUND_HAS_SIGN); + if(signReward.dayIndex > playerData.todayIndex) return resResult(STATUS.ACTIVITY_WEEKLY_FUND_LOCK); + + let record = await ActivityWeeklyFundModel.sign(serverId, activityId, roleId, dayIndex, playerData.todayIndex); + if(!record) return resResult(STATUS.ACTIVITY_WEEKLY_FUND_HAS_SIGN); + + let rewardParamArr = stringToRewardParam(signReward.reward); + let { goods, addHeros } = await addReward(roleId, roleName, sid, serverId, rewardParamArr, ITEM_CHANGE_REASON.ACT_WEEKLY_FUND_SIGN); + + return resResult(STATUS.SUCCESS, { + activityId, dayIndex, goods, addHeros + }); + } +} diff --git a/game-server/app/services/activity/activityService.ts b/game-server/app/services/activity/activityService.ts index 1bc5fbd45..6e7f7cb73 100644 --- a/game-server/app/services/activity/activityService.ts +++ b/game-server/app/services/activity/activityService.ts @@ -43,6 +43,7 @@ import { getGroupShopDataShow } from './groupShopService'; import { getBindPhoneDataShow } from './bindPhoneService'; import { getPlayerForgeDataShow } from './forgeService'; import { getPlayerMiniGameDataShow } from './miniGameService'; +import { getWeeklyFundDataShow } from './weeklyFundService'; /** * 获取活动数据 @@ -244,6 +245,11 @@ export async function getActivity(serverId: number, roleId: string, uid: number, activityData = await getPlayerMiniGameDataShow(activityId, serverId, roleId); break } + case ACTIVITY_TYPE.WEEKLY_FUND: + { + activityData = await getWeeklyFundDataShow(activityId, serverId, roleId); + break + } default: { console.log('未知活动类型.........', activityType) break; diff --git a/game-server/app/services/activity/monthlyFundService.ts b/game-server/app/services/activity/monthlyFundService.ts new file mode 100644 index 000000000..e69de29bb diff --git a/game-server/app/services/activity/weeklyFundService.ts b/game-server/app/services/activity/weeklyFundService.ts new file mode 100644 index 000000000..3abfc5a9e --- /dev/null +++ b/game-server/app/services/activity/weeklyFundService.ts @@ -0,0 +1,87 @@ +import { ACTIVITY_TYPE, ITEM_CHANGE_REASON, STATUS } from "../../consts"; +import { ActivityModelType } from "../../db/Activity"; +import { ActivityWeeklyFundModel } from "../../db/ActivityWeeklyFund"; +import { WeeklyFundData } from "../../domain/activityField/weeklyFundField"; +import { getRoleCreateTime, getServerCreateTime } from "../redisService"; +import { getActivityById } from "./activityService"; +import { stringToRewardParam, addReward } from "./giftPackageService"; + +/** + * 周基金玩家活动数据 + * + * @param {number} serverId 区Id + * @param {number} activityId 活动Id + * @param {string} roleId 角色Id + * + */ +export async function getWeeklyFundData(activityId: number, serverId: number, roleId: string) { + let activityData = await getActivityById(activityId); + let createTime = await getRoleCreateTime(roleId); + let serverTime = await getServerCreateTime(serverId); + let playerData = new WeeklyFundData(activityData, createTime, serverTime); + let playerRecord = await ActivityWeeklyFundModel.findData(serverId, activityId, roleId); + playerData.setPlayerRecord(playerRecord); + return playerData; +} + +/** + * 周基金 玩家活动数据 + * + * @param {number} serverId 区Id + * @param {number} activityId 活动Id + * @param {string} roleId 角色Id + * + */ +export async function getWeeklyFundDataShow(activityId: number, serverId: number, roleId: string) { + let playerData = await getWeeklyFundData(activityId, serverId, roleId); + if(playerData && playerData.canShow && playerData.canShow()) { + return playerData.getShowResult(); + } + return null +} + +/** + * 周基金 是否可以购买 + * @param roleId 玩家id + * @param serverId 服 + * @param activityData 活动数据 + * @returns + */ +export async function checkWeeklyFund(roleId: string, serverId: number, activityData: ActivityModelType) { + if(!activityData || activityData.type !== ACTIVITY_TYPE.WEEKLY_FUND) return false; + + let playerRecord = await ActivityWeeklyFundModel.findData(serverId, activityData.activityId, roleId); + return !playerRecord; +} + +/** + * 周基金购买 + * @param roleId 玩家id + * @param roleName 玩家名 + * @param sid + * @param serverId 服 + * @param activityId 活动 + * @param productID 商品id + * @returns + */ +export async function makeWeeklyFund(roleId: string, roleName: string, sid: string, serverId: number, activityId: number, productID: string) { + let activityData: ActivityModelType = await getActivityById(activityId); + if (!activityData) { + return STATUS.ACTIVITY_MISSING; + } + if (activityData.type !== ACTIVITY_TYPE.WEEKLY_FUND) { + return STATUS.ACTIVITY_TYPE_ERROR; + } + let createTime = await getRoleCreateTime(roleId); + let serverTime = await getServerCreateTime(serverId); + let playerData = new WeeklyFundData(activityData, createTime, serverTime); + await ActivityWeeklyFundModel.buy(serverId, activityId, roleId, productID); + + let rewardParamArr = stringToRewardParam(playerData.onceReward); + let result = await addReward(roleId, roleName, sid, serverId, rewardParamArr, ITEM_CHANGE_REASON.ACT_WEEKLY_FUND_BUY); + + return { + code: 0, + data: Object.assign(result, { activityId: activityId }) + } +} \ No newline at end of file diff --git a/game-server/app/services/checkParam.ts b/game-server/app/services/checkParam.ts index 3a268e06f..407027fcf 100644 --- a/game-server/app/services/checkParam.ts +++ b/game-server/app/services/checkParam.ts @@ -121,6 +121,7 @@ export function checkRouteParam(route: string, msg: any) { case 'activity.groupShopHandler.leaveGroupShopPage': case 'activity.forgeHandler.getForgeActivity': case 'activity.miniGameHandler.getMiniGameActivity': + case 'activity.weeklyFundHandler.getData': { if(!checkNaturalNumbers(msg.activityId)) return false; break; @@ -472,6 +473,11 @@ export function checkRouteParam(route: string, msg: any) { if(!checkNaturalNumbers(msg.activityId)) return false; break; } + case 'activity.weeklyFundHandler.sign': + { + if(!checkNaturalNumbers(msg.activityId, msg.dayIndex)) return false; + break; + } case "battle.barrageHandler.getBarrageList": { if(!checkNaturalStrings(msg.rid)) return false; diff --git a/game-server/app/services/orderService.ts b/game-server/app/services/orderService.ts index 06289b649..e3bebcdaa 100644 --- a/game-server/app/services/orderService.ts +++ b/game-server/app/services/orderService.ts @@ -8,8 +8,6 @@ import { makeSignInVIP } from './activity/signInService'; import { makeDailyRMBGiftsReward } from './activity/dailyRMBGiftsService'; import { checkPopUpShopCanBuy, makePopUpShopReward } from './activity/popUpShopService'; import { ActivityModel, ActivityModelType } from '../db/Activity'; -import { ActivityFirstGiftModel } from '../db/ActivityFirstGift'; -import { ServerlistModel } from '../db/Serverlist'; import { makeGrowthFund } from './activity/growthFundService'; import { checkLimitPackageCanBuy, makeLimitPackageReward } from './activity/limitPackageService'; import { makeShop } from './activity/treasureHuntService'; @@ -31,14 +29,13 @@ import { recordFirstGift } from './activity/firstGiftService'; import { makeTaskPass } from './activity/taskPassService'; import { addGuildPay } from './activity/guildPayService'; import { sendMessageToUserWithSuc } from './pushService'; -import { gameData } from '../pubUtils/data'; import { checkParamPrice, needRebate } from '../pubUtils/sdkUtil'; import { checkShopCanBuyInOrder, makeShopOrder } from './shopService'; import { UserModel } from '../db/User'; import { HistoryOrderModel } from '../db/HistoryOrder'; import { sendMailByContent } from './mailService'; -import { getGoldObject } from './role/rewardService'; import { RECHARGE } from '../pubUtils/dicParam'; +import { checkWeeklyFund, makeWeeklyFund } from './activity/weeklyFundService'; export async function checkOrderCanBuy(roleId: string, serverId: number, activityData: ActivityModelType, productID: string, paramStr: string) { let activityId = activityData.activityId; @@ -58,6 +55,10 @@ export async function checkOrderCanBuy(roleId: string, serverId: number, activit { return await checkLimitPackageCanBuy(roleId, serverId, activityData, productID) } + case ACTIVITY_TYPE.WEEKLY_FUND: + { + return await checkWeeklyFund(roleId, serverId, activityData); + } } return true } @@ -174,6 +175,11 @@ export async function makeOrder(orderInfo: UserOrderModelType, sid: string) { break; } + case ACTIVITY_TYPE.WEEKLY_FUND: // 周基金 + { + rewardResult = await makeWeeklyFund(roleId, roleInfo.roleName, sid, orderInfo.serverId, orderInfo.activityId, orderInfo.productID) + break; + } default: rewardResult = STATUS.ERROR_TYPE; break; diff --git a/shared/consts/constModules/activityConst.ts b/shared/consts/constModules/activityConst.ts index 0051c2aba..eaa9a69e7 100644 --- a/shared/consts/constModules/activityConst.ts +++ b/shared/consts/constModules/activityConst.ts @@ -63,6 +63,7 @@ export enum ACTIVITY_TYPE { FORGE = 48, // 火神祭祀 GROUP_SHOP = 49, // 团购 BIND_PHONE = 50, // 绑定手机号 + WEEKLY_FUND = 51, // 周基金 } /** diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index d3d13a519..5d36b5e0d 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -1148,6 +1148,8 @@ export enum ITEM_CHANGE_REASON { ACT_FORGE_HELP = 178, // 火神祭祀失败补助 ACT_MINI_GAME_REWARD = 179, // 小游戏单局奖励 ACT_MINI_GAME_BUY_CNT = 180, // 小游戏花元宝买 + ACT_WEEKLY_FUND_BUY = 181, // 周基金一次性购买 + ACT_WEEKLY_FUND_SIGN = 182, // 周基金签到 } export enum TA_EVENT { diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index 29ca38d3e..0bbc6176b 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -655,6 +655,10 @@ export const STATUS = { ACTIVITY_MINI_GAME_BOX_NOT_FOUND: { code: 50053, simStr: '未找到该宝箱' }, ACTIVITY_MINI_GAME_BOX_HAS_RECEIVED: { code: 50054, simStr: '该宝箱已领取' }, ACTIVITY_MINI_GAME_SCORE_NOT_ENOUGH: { code: 50055, simStr: '积分不足' }, + ACTIVITY_WEEKLY_FUND_NOT_BOUGHT: { code: 50056, simStr: '周基金未购买' }, + ACTIVITY_WEEKLY_FUND_NOT_FOUND: { code: 50057, simStr: '未找到该配置' }, + ACTIVITY_WEEKLY_FUND_LOCK: { code: 50058, simStr: '本次签到暂未解锁' }, + ACTIVITY_WEEKLY_FUND_HAS_SIGN: { code: 50059, simStr: '本次签到奖励已领取' }, // GM后台相关状态 60000 - 69999 GM_ERR_PASSWORD: { code: 60001, simStr: '账号或密码错误' }, diff --git a/shared/db/ActivityWeeklyFund.ts b/shared/db/ActivityWeeklyFund.ts new file mode 100644 index 000000000..aceba9c43 --- /dev/null +++ b/shared/db/ActivityWeeklyFund.ts @@ -0,0 +1,60 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; + +/** + * 周基金 +*/ + +class SignRecord { + @prop({ required: true }) + dayIndex: number; // 第几天的签到 + @prop({ required: true }) + todayIndex: number; // 签到当天是第几天 + @prop({ required: true }) + time: Date; // 时间戳 + + constructor(dayIndex: number, todayIndex: number) { + this.dayIndex = dayIndex; + this.todayIndex = todayIndex; + this.time = new Date(); + } +} + +@index({ roleId: 1, activityId: 1 }) + +export default class Activity_Weekly_Fund extends BaseModel { + @prop({ required: true }) + serverId: number; // 服Id + + @prop({ required: true }) + activityId: number; // 活动Id + + @prop({ required: true }) + roleId: string; // 用户Id + + @prop({ required: true }) + productID: string; // 商品id + + @prop({ required: true, type: SignRecord, _id: false }) + record: SignRecord[]; // 铸造记录 + + public static async findData(serverId: number, activityId: number, roleId: string) { + let result: ActivityWeeklyFundModelType = await ActivityWeeklyFundModel.findOne({ serverId, roleId, activityId }).lean(); + return result; + } + + public static async buy(serverId: number, activityId: number, roleId: string, productID: string) { + let result: ActivityWeeklyFundModelType = await ActivityWeeklyFundModel.findOneAndUpdate({ serverId, roleId, activityId }, { $setOnInsert: { record: [], productID } }, { new: true, upsert: true }).lean(); + return result; + } + + public static async sign(serverId: number, activityId: number, roleId: string, dayIndex: number, todayIndex: number) { + let result: ActivityWeeklyFundModelType = await ActivityWeeklyFundModel.findOneAndUpdate({ serverId, roleId, activityId, 'record.dayIndex': { $ne: dayIndex } }, { $push: { record: new SignRecord(dayIndex, todayIndex)} }, { new: true }).lean(); + return result; + } +} + +export const ActivityWeeklyFundModel = getModelForClass(Activity_Weekly_Fund); + +export interface ActivityWeeklyFundModelType extends Pick, keyof Activity_Weekly_Fund> { } +export type ActivityWeeklyFundModelTypeParam = Partial; // 将所有字段变成可选项 \ No newline at end of file diff --git a/shared/domain/activityField/weeklyFundField.ts b/shared/domain/activityField/weeklyFundField.ts new file mode 100644 index 000000000..fd6a60d6b --- /dev/null +++ b/shared/domain/activityField/weeklyFundField.ts @@ -0,0 +1,93 @@ +// 周基金 +import moment = require('moment'); +import { pick } from 'underscore'; +import { ActivityModelType } from '../../db/Activity'; +import { ActivityWeeklyFundModelType } from '../../db/ActivityWeeklyFund'; +import { ActivityBase } from './activityField'; + +interface WeeklyFundRewardInDb { + dayIndex: number; // 第几天 + reward: string; // 每天签到的奖励 type&id&count +} + +interface WeeklyFundDataInDb { + productID: string; // 商品id,商品表 + price: number; // 购买价格 + onceReward: string; // 购买后立刻可以获得的奖励 type&id&count + rewards: WeeklyFundRewardInDb[]; // 每天签到可领取的奖励 + rebate: number; // 显示用的返利倍数 +} + +class WeeklyFundReward { + dayIndex: number; // 第几天 + reward: string; // 每天签到的奖励 type&id&count + hasReceived: boolean = false; // 是否领取过 + + constructor(data: WeeklyFundRewardInDb) { + this.dayIndex = data.dayIndex; + this.reward = data.reward; + } + + public setHasReceived() { + this.hasReceived = true; + } +} + +export class WeeklyFundData extends ActivityBase { + productID: string; // 商品id,商品表 + price: number; // 购买价格 + onceReward: string; // 购买后立刻可以获得的奖励 type&id&count + rebate: number; // 显示用的返利倍数 + buyEndTime: number = 0; // 购买截止时间 + rewards: WeeklyFundReward[] = []; // 每天签到可领取的奖励 + + hasBought: boolean = false; // 是否购买了 + + constructor(activityData: ActivityModelType, createTime: number, serverTime: number) { + super(activityData, createTime, serverTime) + this.initData(activityData.data) + } + + public initData(data: string): void { + let dataObj: WeeklyFundDataInDb = JSON.parse(data); + if(!dataObj) return; + + this.productID = dataObj.productID; + this.price = dataObj.price; + this.onceReward = dataObj.onceReward; + this.rebate = dataObj.rebate; + for(let reward of (dataObj.rewards||[])) { + this.rewards.push(new WeeklyFundReward(reward)); + } + this.buyEndTime = this.nextRefreshTime; + this.nextRefreshTime = moment('2100-01-01').valueOf(); + this.endTime = moment('2100-01-01').valueOf(); + } + + public setPlayerRecord(playerData: ActivityWeeklyFundModelType) { + if(!playerData) return; + this.hasBought = true; + for(let { dayIndex } of playerData.record) { + let reward = this.rewards.find(cur => cur.dayIndex == dayIndex); + if(reward) reward.setHasReceived(); + } + } + + public findSignReward(dayIndex: number) { + return this.rewards.find(cur => cur.dayIndex == dayIndex); + } + + private hasReceivedAll() { + return !this.rewards.find(cur => !cur.hasReceived); + } + + public getShowResult() { + if(this.buyEndTime < Date.now() && !this.hasBought) return null; + if(this.hasReceivedAll()) return null + + return { + ...this.getBaseKeys(), + ...pick(this, ['productID', 'price', 'onceReward', 'rebate', 'buyEndTime', 'rewards', 'hasBought']) + } + } +} \ No newline at end of file diff --git a/shared/resource/jsons/dic_zyz_activityType.json b/shared/resource/jsons/dic_zyz_activityType.json index f4c997df1..35d086b02 100644 --- a/shared/resource/jsons/dic_zyz_activityType.json +++ b/shared/resource/jsons/dic_zyz_activityType.json @@ -274,5 +274,17 @@ "activityType": 50, "name": "BIND_PHONE", "string": "绑定手机" + }, + { + "id": 51, + "activityType": 51, + "name": "WEEKLY_FUND", + "string": "周基金" + }, + { + "id": 52, + "activityType": 52, + "name": "MONTHLY_FUND", + "string": "月基金" } ] \ No newline at end of file