diff --git a/game-server/app/servers/battle/handler/auctionHandler.ts b/game-server/app/servers/battle/handler/auctionHandler.ts index 9d55fe66a..4bfc58246 100644 --- a/game-server/app/servers/battle/handler/auctionHandler.ts +++ b/game-server/app/servers/battle/handler/auctionHandler.ts @@ -5,7 +5,7 @@ import { AUCTION_STAGE, DEBUG_MAGIC_WORD, STATUS, OFFER_RATIO, CURRENCY_BY_TYPE, import { LotModel } from "../../../db/Lot"; import { ItemReward } from "../../../domain/dbGeneral"; import { resResult } from "../../../pubUtils/util"; -import { auctionStage, calculateDividend, genAuction, todayGuildBegin } from "../../../services/auctionService"; +import { auctionStage, calculateDividend, genAuction, sendUngotDividend, startGuildAuction, startWorldAuction, stopAuction, todayGuildBegin } from "../../../services/auctionService"; import { addItems, handleCost } from '../../../services/rewardService'; import { getSimpleRoleInfo } from '../../../services/roleService'; import { getRoleOnlineInfo } from '../../../services/redisService'; @@ -143,7 +143,8 @@ export class AuctionHandler { const serverId = session.get('serverId'); const begin = todayGuildBegin(); const lots = await LotModel.watchingLotsByBegin(serverId, roleId, begin); - return resResult(STATUS.SUCCESS, { lots }); + const stage = auctionStage(); + return resResult(STATUS.SUCCESS, { lots: stage === AUCTION_STAGE.END ? [] : lots }); } async offerRecs(msg: { count: number }, session: BackendSession) { @@ -199,4 +200,40 @@ export class AuctionHandler { return resResult(STATUS.SUCCESS, result); } + + // ! 测试接口 + async debugScheduleStartGuild(msg: { magicWord: string }, session: BackendSession) { + const result = await startGuildAuction(); + if (result === true) { + return resResult(STATUS.SUCCESS); + } + return resResult(STATUS.INTERNAL_ERR); + } + + // ! 测试接口 + async debugScheduleStartWorld(msg: { magicWord: string }, session: BackendSession) { + const result = await startWorldAuction(); + if (result === true) { + return resResult(STATUS.SUCCESS); + } + return resResult(STATUS.INTERNAL_ERR); + } + + // ! 测试接口 + async debugScheduleStopAuction(msg: { magicWord: string }, session: BackendSession) { + const result = await stopAuction(); + if (result === true) { + return resResult(STATUS.SUCCESS); + } + return resResult(STATUS.INTERNAL_ERR); + } + + // ! 测试接口 + async debugScheduleSendUngotDividend(msg: { magicWord: string }, session: BackendSession) { + const result = await sendUngotDividend(); + if (result === true) { + return resResult(STATUS.SUCCESS); + } + return resResult(STATUS.INTERNAL_ERR); + } } diff --git a/game-server/app/services/auctionService.ts b/game-server/app/services/auctionService.ts index 58fd19f4d..ed4d59472 100644 --- a/game-server/app/services/auctionService.ts +++ b/game-server/app/services/auctionService.ts @@ -1,13 +1,16 @@ -import { DIVIDENDWEEKENDRATE, DIVIDENDMAXRATIO, DIVIDENDPOSITIONMAXRATIO } from './../consts/constModules/auctionConst'; +import { MailModel, MailType } from './../db/Mail'; import { DividendModel } from './../db/Dividend'; -import { LOT_CODE_LEN, AUCTION_STAGE, AUCTION_TIME, DIVIDEND_CODE_LEN, DIVIDEND_STATUS, LOT_STATUS } from './../consts'; +import { LOT_CODE_LEN, AUCTION_STAGE, AUCTION_TIME, DIVIDEND_CODE_LEN, DIVIDEND_STATUS, LOT_STATUS, MAIL_TYPE, CURRENCY_BY_TYPE, CURRENCY_TYPE, STATUS, DIVIDENDWEEKENDRATE, DIVIDENDMAXRATIO, DIVIDENDPOSITIONMAXRATIO, ROLE_RECEIVE_STATUS } from './../consts'; import { DividendRec, ItemReward } from "../domain/dbGeneral"; -import { genCode } from '../pubUtils/util'; +import { genCode, resResult } from '../pubUtils/util'; import { LotModel, LotParam } from '../db/Lot'; -import { getNextTime, getTodayZeroDate } from '../pubUtils/timeUtil'; +import { getNextTime, getTodayZeroDate, getZeroDateByDeltaDay } from '../pubUtils/timeUtil'; import { gameData, getGoodById } from '../pubUtils/data'; import { DividendParam, DividendType } from '../db/Dividend'; import { RolePosition } from '../domain/battleField/guild'; +import { pushMail } from '../pubUtils/interface'; +import { getMailContent } from './mailService'; +import { pinus } from 'pinus'; // ! 获取底价,假数据 function getBasePrice(gid: number, count: number) { @@ -41,6 +44,10 @@ export function todayGuildBegin() { return getNextTime(getTodayZeroDate(), AUCTION_TIME.GUILD_BEGIN_HOUR, AUCTION_TIME.GUILD_BEGIN_MIN); } +export function yestodayGuildBegin() { + return getNextTime(getZeroDateByDeltaDay(-1), AUCTION_TIME.GUILD_BEGIN_HOUR, AUCTION_TIME.GUILD_BEGIN_MIN); +} + export function todayWorldBegin() { return getNextTime(getTodayZeroDate(), AUCTION_TIME.WORLD_BEGIN_HOUR, AUCTION_TIME.WORLD_BEGIN_MIN); } @@ -147,3 +154,73 @@ export async function calculateDividend(dividend: DividendType) { }); return await DividendModel.updateDividend(code, { dividends }); } + +export async function startGuildAuction() { + try { + console.log('schedule startGuildAuction called:', new Date()); + const begin = todayGuildBegin(); + await LotModel.updateLotsStageByBegin(begin, AUCTION_STAGE.GUILD); + await DividendModel.updateDividendsStatus(begin, DIVIDEND_STATUS.ING); + return true; + } catch (e) { + console.error('startGuildAuction err: ', e); + return false; + } +} + +export async function startWorldAuction() { + try { + console.log('schedule startWorldAuction called:', new Date()); + const begin = todayGuildBegin(); + await LotModel.updateLotsStageByBegin(begin, AUCTION_STAGE.WORLD); + return true; + } catch (e) { + console.error('startWorldAuction err: ', e); + return false; + } +} + +export async function stopAuction() { + try { + console.log('schedule stopAuction called:', new Date()); + const begin = todayGuildBegin(); + await LotModel.updateLotsStageByBegin(begin, AUCTION_STAGE.END); + await DividendModel.updateDividendsStatus(begin, DIVIDEND_STATUS.END); + return true; + } catch (e) { + console.error('stopAuction err: ', e); + return false; + } +} + +export async function sendUngotDividend() { + try { + console.log('schedule sendUngotDividend called:', new Date()); + const begin = yestodayGuildBegin(); + const dividends = await DividendModel.findDividendsByBegin(begin); + const rewards = new Map(); + for (let dividend of dividends) { + if (!dividend.dividends) continue; + for (let dividendRec of dividend.dividends) { + if (dividendRec.status === ROLE_RECEIVE_STATUS.YES) continue; + const sum = rewards.get(dividendRec.roleId) || 0; + rewards.set(dividendRec.roleId, sum + dividendRec.total); + } + } + + let mails: MailType[] = []; + let pushMessage: pushMail[] = []; + for (let [roleId, count] of rewards) { + // TODO: 邮件类型修改 + await getMailContent(roleId, MAIL_TYPE.GUILD_BOSS_REWARD, [JSON.stringify(count)], [{ id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count }], mails, pushMessage); + } + await MailModel.addMails(mails); + pushMessage.forEach(({route, data, uids })=>{ + pinus.app.channelService.pushMessageByUids(route, resResult(STATUS.SUCCESS, { mails: data }), uids); + }); + return true; + } catch (e) { + console.error('sendUngotDividend err: ', e); + return false; + } +} diff --git a/game-server/app/services/timeTaskService.ts b/game-server/app/services/timeTaskService.ts index c3d84d82e..b6954b8cb 100644 --- a/game-server/app/services/timeTaskService.ts +++ b/game-server/app/services/timeTaskService.ts @@ -21,6 +21,7 @@ import { getMailContent, sendMail } from './mailService'; import { reportOnline } from '../pubUtils/httpUtil'; import User, { UserModel } from '../db/User'; import { getGuildActivityByDic, getGuildActivityRank } from './guildActivityService'; +import { sendUngotDividend, startGuildAuction, startWorldAuction, stopAuction } from './auctionService'; const PER_SECOND = 1 * 1000; const PER_DAY = 24 * 60 * 60; const SETTLE_DIFF = 29 * 60; @@ -68,6 +69,8 @@ export async function init() { scheduleJob('reportOnline', '0 0/5 * * * *', reportOnlineSchedule); guildActivitySchedule(); + // 拍卖行刷新:拍卖阶段刷新,分红发放 + auctionSchedule(); } function setPvpSeasonSchdule() { @@ -389,4 +392,11 @@ export async function guildActivitySeconds() { for(let { id } of servers) { await pinus.app.rpc.guild.guildActivityRemote.sendRankToGuilds.toServer(id); } -} \ No newline at end of file +} + +function auctionSchedule() { + scheduleJob('startGuildAuction', '0 0 20 20 * ?', startGuildAuction); + scheduleJob('startWorldAuction', '0 0 20 30 * ?', startWorldAuction); + scheduleJob('stopAuction', '0 0 22 00 * ?', stopAuction); + scheduleJob('sendUngotDividend', '0 0 5 00 * ?', sendUngotDividend); +} diff --git a/game-server/test/auction.test.ts b/game-server/test/auction.test.ts index 27ff832f4..3e6762057 100644 --- a/game-server/test/auction.test.ts +++ b/game-server/test/auction.test.ts @@ -198,7 +198,7 @@ describe('拍卖行测试', function() { expect(info.id).to.be.equal(CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD)); } }); - pinusClient.request('battle.auctionHandler.debugSetDividendStatus', { magicWord: DEBUG_MAGIC_WORD, sourceType: AUCTION_SOURCE.GATE, status: DIVIDEND_STATUS.ING }, (res) => { + pinusClient.request('battle.auctionHandler.debugSetDividendStatus', { magicWord: DEBUG_MAGIC_WORD, sourceType: AUCTION_SOURCE.GATE, status: DIVIDEND_STATUS.END }, (res) => { checkSuccessResponse(res); checkDividend(res.data.dividend); pinusClient.request('battle.auctionHandler.getDividend', { sourceType: AUCTION_SOURCE.GATE }, (res) => { @@ -277,4 +277,32 @@ describe('拍卖行测试', function() { done(); }); }); + + it('测试接口,军团拍卖定时', function(done) { + pinusClient.request('battle.auctionHandler.debugScheduleStartGuild', { magicWord: DEBUG_MAGIC_WORD }, (res) => { + checkSuccessResponse(res, false); + done(); + }); + }); + + it('测试接口,世界拍卖定时', function(done) { + pinusClient.request('battle.auctionHandler.debugScheduleStartWorld', { magicWord: DEBUG_MAGIC_WORD }, (res) => { + checkSuccessResponse(res, false); + done(); + }); + }); + + it('测试接口,拍卖结束定时', function(done) { + pinusClient.request('battle.auctionHandler.debugScheduleStopAuction', { magicWord: DEBUG_MAGIC_WORD }, (res) => { + checkSuccessResponse(res, false); + done(); + }); + }); + + it('测试接口,结算分红定时', function(done) { + pinusClient.request('battle.auctionHandler.debugScheduleSendUngotDividend', { magicWord: DEBUG_MAGIC_WORD }, (res) => { + checkSuccessResponse(res, false); + done(); + }); + }); }); diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index ccc2618c4..a2248913f 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -380,7 +380,8 @@ export const MAIL_TYPE = { GUILD_TRAIN_REWARD: 10, WISH_POOL_REWARD: 11, PVP_RESULT: 12, - PVP_RANK_REWARD: 13 + PVP_RANK_REWARD: 13, + GUILD_DIVIDEND: 14, // 拍卖行分红 }; export const CHAT_SERVER = 'chat-server-1'; diff --git a/shared/db/Dividend.ts b/shared/db/Dividend.ts index be03f8001..4ae87180a 100644 --- a/shared/db/Dividend.ts +++ b/shared/db/Dividend.ts @@ -56,6 +56,11 @@ export default class Dividend extends BaseModel { return results; } + public static async findDividendsByBegin(begin: Date) { + const results = await DividendModel.find({ begin }).select('-_id -__v').lean(); + return results; + } + public static async updateDividend(code: string, update: DividendParam) { const result = await DividendModel.findOneAndUpdate({ code }, { ...update }, { new: true }).select('-_id -__v').lean(); return result; @@ -67,12 +72,12 @@ export default class Dividend extends BaseModel { } public static async findReadyDividend(guildCode: string, sourceType: number) { - const result: DividendType = await DividendModel.findOne({ guildCode, sourceType, status: DIVIDEND_STATUS.ING }).select('-_id -__v').lean(); + const result: DividendType = await DividendModel.findOne({ guildCode, sourceType, status: DIVIDEND_STATUS.END }).select('-_id -__v').lean(); return result; } public static async updateReceiveStatus(code: string, roleId: string) { - const result: DividendType = await DividendModel.findOneAndUpdate({ code, status: DIVIDEND_STATUS.END, 'lots.roleId': roleId }, { 'lots.status': ROLE_RECEIVE_STATUS.YES }, { new: true }).select('-_id -__v').lean(); + const result: DividendType = await DividendModel.findOneAndUpdate({ code, status: DIVIDEND_STATUS.END, 'lodividendsts.roleId': roleId }, { 'dividends.$.status': ROLE_RECEIVE_STATUS.YES }, { new: true }).select('-_id -__v').lean(); return result; } @@ -80,6 +85,10 @@ export default class Dividend extends BaseModel { const result: DividendType = await DividendModel.findOneAndUpdate({ guildCode, sourceType }, { status }, { new: true }).select('-_id -__v').lean(); return result; } + + public static async updateDividendsStatus(begin: Date, status: number) { + await DividendModel.updateMany({ begin }, { status }); + } } export const DividendModel = getModelForClass(Dividend); diff --git a/shared/db/Lot.ts b/shared/db/Lot.ts index 3216c8575..fa740ca6d 100644 --- a/shared/db/Lot.ts +++ b/shared/db/Lot.ts @@ -107,6 +107,11 @@ export default class Lot extends BaseModel { const result: LotType = await LotModel.findOneAndUpdate({ code }, { auctionStage }).select('-_id -__v').lean(); return result; } + + public static async updateLotsStageByBegin(begin: Date, auctionStage: number) { + const results = await LotModel.updateMany({ begin }, { auctionStage }).select('-_id -__v').lean(); + return results; + } } export const LotModel = getModelForClass(Lot); diff --git a/shared/pubUtils/timeUtil.ts b/shared/pubUtils/timeUtil.ts index b0f1c9e16..dc5838b0e 100644 --- a/shared/pubUtils/timeUtil.ts +++ b/shared/pubUtils/timeUtil.ts @@ -112,6 +112,14 @@ export function getTodayZeroDate() { return date; } +export function getZeroDateByDeltaDay(delta: number) { + var date = new Date(new Date().getTime() + delta * PER_DAY * PER_SECOND); + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + return date; +} + export function getAge(birthday: string) { let d = new Date(birthday + ' 00:00:00'); let _year = d.getFullYear();