import { DividendModel } from './../db/Dividend'; import { LOT_CODE_LEN, AUCTION_STAGE, AUCTION_TIME, DIVIDEND_CODE_LEN, DIVIDEND_STATUS, LOT_STATUS, MAIL_TYPE, CURRENCY_BY_TYPE, CURRENCY_TYPE, ROLE_RECEIVE_STATUS, AUCTION_BID_STATUS, DEBUG_MAGIC_WORD, AUCTION_SOURCE, TA_EVENT, getAuctionSourceTypeName, PUSH_ROUTE, GUILD_JOB, AUCTION_BID_TIME, AUCTION_BID_EXTEND_TIME } from './../consts'; import { DividendRec, } from "../domain/dbGeneral"; import { genCode, getRandEelmWithWeight, getRandSingleEelm } from '../pubUtils/util'; import Lot, { LotModel, LotParam, LotType } from '../db/Lot'; import { getCurDay, getSeconds, getTimeFunD, getTimeFunM, nowSeconds } from '../pubUtils/timeUtil'; import { gameData, getGoodById } from '../pubUtils/data'; import { DividendParam, DividendType } from '../db/Dividend'; import { sendMailByContent } from './mailService'; import { FrontendOrBackendSession, pinus } from 'pinus'; import { participants } from './guildActivity/guildActivityService'; import * as dicParam from '../pubUtils/dicParam'; import { RewardInter } from '../pubUtils/interface'; import { reportTAEvent } from './sdkService'; import { getAllServers } from './redisService'; import { sendMessageToGuildWithSuc, sendMessageToServer, sendMessageToServerWithSuc } from './pushService'; import { isDebugTime } from '../pubUtils/sdkUtil'; import { pick } from 'underscore'; import { AuctionRewardInter } from '../domain/battleField/auction'; import { CounterLotsModel } from '../db/CounterAuction'; import { isGoodsHidden } from './dataService'; import { scheduleJob } from 'node-schedule'; import { clearLotTimer, setLotTimer } from './memoryCache/auctionData'; // ! 获取底价,假数据 export function getBasePrice(gid: number, count: number) { const good = getGoodById(gid); return (good ? good.quality * 100 : 100) * count; } // ! 获取一口价,假数据 export function getMaxPrice(gid: number, count: number) { const good = getGoodById(gid); return (good ? good.quality * 200 : 200) * count; } export async function auctionStage() { const curTime = await getCurrentTimeWithSetDay(); if (curTime < (await todayGuildBegin()).getTime()) return AUCTION_STAGE.DEFAULT; if (curTime < (await todayWorldBegin()).getTime() && curTime > (await todayGuildBegin()).getTime()) return AUCTION_STAGE.GUILD; if (curTime > (await todayWorldBegin()).getTime() && curTime < (await todayWorldEnd()).getTime()) return AUCTION_STAGE.WORLD; if (curTime > (await todayWorldEnd()).getTime()) return AUCTION_STAGE.END; } export async function debugAuctionLots(session: FrontendOrBackendSession, begin: Date) { const serverId = session.get('serverId'); const lots = await LotModel.findWorldLotsByBegin(serverId, begin); return lots; } export async function officialAuctionLots(session: FrontendOrBackendSession, begin: Date) { const serverId = session.get('serverId'); const guildCode = session.get('guildCode'); let guildLots = await LotModel.findGuildLotsByBegin(guildCode, begin); let serverLots = await LotModel.findWorldLotsByBegin(serverId, begin); return processLotsFormat([...guildLots, ...serverLots]); } // 拍卖行开始时间 今天20:20 export async function auctionBegin() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_OPEN); return getTimeFunD(now).getAfterDayAndSetHour(0, hour, minute); } // 军团拍卖行结束时间 20:30 export async function guildAuctionEnd() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_CLOSE); return getTimeFunD(now).getAfterDayAndSetHour(0, hour, minute); } // 拍卖行结束时间 22:00 export async function auctionEnd() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.WORLD_CLOSE); return getTimeFunD(now).getAfterDayAndSetHour(0, hour, minute); } // 今天军团拍卖行开始时间 20:20 export async function todayGuildBegin() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_OPEN); return getTimeFunD(now).getAfterDayAndSetHour(0, hour, minute); } async function getCurrentTime() { let now = Date.now(); if(isDebugTime()) { let guilds = pinus.app.getServersByType('guild'); let guild = getRandSingleEelm(guilds); now = await pinus.app.rpc.guild.guildActivityRemote.getCurrentTime.toServer(guild.id); } return now } async function getCurrentTimeWithSetDay() { let now = new Date(); if(isDebugTime()) { let guilds = pinus.app.getServersByType('guild'); let guild = getRandSingleEelm(guilds); let currentTime = await pinus.app.rpc.guild.guildActivityRemote.getCurrentTime.toServer(guild.id); now.setDate(new Date(currentTime).getDate()); } return now.getTime(); } // 明天军团拍卖行开始时间 20:20 export async function tomorrowGuildBegin() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_OPEN); // console.log(hour, minute) return getTimeFunD(now).getAfterDayAndSetHour(1, hour, minute); } // 明天军团拍卖行开始时间 20:20 export async function tomorrowGuildEnd() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_CLOSE); // console.log(hour, minute) return getTimeFunD(now).getAfterDayAndSetHour(1, hour, minute); } // 昨天军团拍卖行开始时间 20:20 export async function yestodayGuildBegin() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_OPEN); return getTimeFunD(now).getAfterDayAndSetHour(-1, hour, minute); } // 今天世界拍卖行开始时间 20:40 export async function todayWorldBegin() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.WORLD_OPEN); return getTimeFunD(now).getAfterDayAndSetHour(0, hour, minute); } // 今天世界拍卖行结束时间 22:00 export async function todayWorldEnd() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.WORLD_CLOSE); return getTimeFunD(now).getAfterDayAndSetHour(0, hour, minute); } // 拍卖行预览时间 20:00 export async function guildAuctionPreview() { let now = await getCurrentTime(); let { hour, minute } = gameData.auctionTime.get(AUCTION_TIME.GUILD_PREVIEW); return getTimeFunD(now).getAfterDayAndSetHour(0, hour, minute); } // 演武台。8点以前是今天的,8点以后是明天的 export async function getBossAuctionBegin() { if((await getCurrentTimeWithSetDay()) < (await guildAuctionPreview()).getTime()) { return await todayGuildBegin(); } else { return await tomorrowGuildBegin(); } } // 演武台。8点以前是今天的,8点以后是明天的 export async function getBossAuctionEnd() { if((await getCurrentTimeWithSetDay()) < (await guildAuctionPreview()).getTime()) { return await guildAuctionEnd(); } else { return await tomorrowGuildEnd(); } } /** * @description 生成拍卖数据 * @export * @param {string} guildCode * @param {number} sourceType * @param {string} sourceCode * @param {number} serverId * @param {ItemReward[]} rewards */ export async function genAuction(guildCode: string, sourceType: number, sourceCode: string, serverId: number, rewards: Map) { let begin = await auctionBegin(); let end = await auctionEnd(); if(sourceType == AUCTION_SOURCE.BOSS) { // 军团boss本 begin = await getBossAuctionBegin(); end = await getBossAuctionEnd(); } const guildEnd = await guildAuctionEnd(); const lotsData: LotParam[] = []; for(let [id, items] of rewards) { let seq = await CounterLotsModel.getNewCounter(id * 100000 + serverId, begin, items.length); for(let i = 0; i < items.length; i++) { let { goods: {id, count}, maxPrice, basePrice, sort } = items[i]; let code = genCode(LOT_CODE_LEN); lotsData.push({ seq: seq - i, auctionStage: AUCTION_STAGE.DEFAULT, sourceType, sourceCode, serverId, guildCode, code, gid: id, count, begin, end, status: LOT_STATUS.DEFAULT, maxPrice, curPrice: basePrice, prePrice: 0, sort, bidRoles: [], watchingRoles: [] }) } } const lots = await LotModel.createRecs(lotsData); const dividendCode = genCode(DIVIDEND_CODE_LEN); const participantsData = await participants(guildCode, sourceType, sourceCode); const dividends: DividendRec[] = participantsData.map(data => { const { roleId, baseNum } = data; return { roleId, posNum: 0, // 职位分红 baseNum, hasJoin: true, weekendNum: 0, // 额外分红,周末 total: baseNum, // 总分红 status: 0, // 0:未领取,1:已领取 }; }); const dividendData: DividendParam = { guildCode, sourceType, sourceCode, serverId, code: dividendCode, dividends, totalPrice: 0, begin, lots: lots.map(lot => { const { code, gid } = lot; return { code, gid, price: 0, time: guildEnd, max: false, count: lot.count } }), }; const dividend = await DividendModel.createDividend(dividendData); await sendMessageToGuildWithSuc(guildCode, PUSH_ROUTE.AUCTION_ADD, { lots: processLotsFormat(lots) }); await sendMessageToGuildWithSuc(guildCode, PUSH_ROUTE.DIVIDEND_ADD, { dividends: processDividendFormat([dividend]) }); return { lots, dividend }; } export function getRewardToDbFromMap(map: Map) { let rewards: { id: number, count: number }[] = []; for(let [_, arr] of map) { for(let { goods } of arr) { rewards.push(goods) } } return rewards } function posDividend(totalPrice: number, roleRatio: number, totalRatio: number) { const dividend = Math.floor(totalPrice * roleRatio / totalRatio); const maxDividend = Math.floor(totalPrice * dicParam.GUILD_AUCTION.DIVIDEND_MAXRATIO); return dividend <= maxDividend ? dividend : Math.floor(maxDividend * roleRatio / getMaxPosRatio()); } function getMaxPosRatio() { return gameData.guildPosition.get(GUILD_JOB.DAJIANGJUN).sellRatio; } function weekendDividend(posNum: number, date: Date) { const day = date.getDay(); return (day === 0 || day === 6) ? Math.floor(posNum * dicParam.GUILD_AUCTION.DIVIDEND_WEEKEND_RATE) : 0; } function dividendRate(data: { roleId: string, job: number }) { return gameData.guildPosition.get(data.job).sellRatio; } function totalDividendRatio(participantsData: { roleId: string, job: number }[]) { const result = participantsData.reduce((sum, data) => { return sum + dividendRate(data); }, 0); return result; } export async function calculateDividend(dividend: DividendType) { if (!dividend) return null; const { code, guildCode, sourceType, sourceCode, lots, totalPrice, status, begin } = dividend; if (status === DIVIDEND_STATUS.SENT) return dividend; const calcuTotalPrice = lots.reduce((acc, lot) => { return acc + lot.price }, 0) * dicParam.GUILD_AUCTION.DIVIDEND_RATE; if (calcuTotalPrice !== totalPrice) { await DividendModel.updateDividend(code, { totalPrice: calcuTotalPrice }); // 更新 totalPrice } const participantsData = await participants(guildCode, sourceType, sourceCode); const totalRatio = totalDividendRatio(participantsData); const dividends: DividendRec[] = participantsData.map(data => { const { roleId, baseNum } = data; const posNum = posDividend(calcuTotalPrice, dividendRate(data), totalRatio); const weekendNum = weekendDividend(posNum, begin); return { roleId, posNum, // 职位分红 baseNum, hasJoin: true, weekendNum, // 额外分红,周末 total: posNum + baseNum + weekendNum, // 总分红 status: 0, // 0:未领取,1:已领取 }; }); return await DividendModel.updateDividend(code, { dividends }); } export async function startGuildAuction() { try { console.log('schedule startGuildAuction called:', new Date()); const begin = await todayGuildBegin(); let lots = await LotModel.updateLotsStageByBegin(begin, AUCTION_STAGE.GUILD); let dividends = await DividendModel.updateDividendsStatus(begin, DIVIDEND_STATUS.ING); if(isDebugTime()) { let day = getCurDay(); let time = getTimeFunM().getTimeWithWeek(day, 20, 20, 0); pinus.app.rpc.guild.guildActivityRemote.setCurrentTime.broadcast(time); await pushCurrentTime(time); } await pushAuctionUpdate(lots, dividends); return true; } catch (e) { console.error('startGuildAuction err: ', e); return false; } } export async function sendLotsRewardToMlail(lots: LotType[]) { let lotByRole = new Map(); for(let lot of lots) { if(!lotByRole.has(lot.curBuyer)) { lotByRole.set(lot.curBuyer, []); } lotByRole.get(lot.curBuyer).push({ id: lot.gid, count: lot.count, price: lot.curPrice }); } for(let [roleId, goods ] of lotByRole) { await sendMailByContent(MAIL_TYPE.AUTION_REWARD, roleId, { goods }); for(let { id, count, price } of goods) { let dicGoods = gameData.goods.get(id); reportTAEvent(roleId, TA_EVENT.AUCTION_ITEM_GET, { item_name: dicGoods?.name, item_count: count, deel_price: price }); } } } export async function startWorldAuction() { try { console.log('schedule startWorldAuction called:', new Date()); const begin = await todayGuildBegin(); let lots = await LotModel.setLotSoldByBegin(begin, AUCTION_STAGE.GUILD); // 正在竞拍的拍品 await sendLotsRewardToMlail(lots); lots = await LotModel.keepUnSoldLotsToWorld(begin); if(isDebugTime()) { let day = getCurDay(); let time = getTimeFunM().getTimeWithWeek(day, 20, 30, 0); pinus.app.rpc.guild.guildActivityRemote.setCurrentTime.broadcast(time); await pushCurrentTime(time); } await pushAuctionUpdate(lots, []); return true; } catch (e) { console.error('startWorldAuction err: ', e); return false; } } export async function startDividend() { console.log('schedule startDividend called:', new Date()); const begin = await todayGuildBegin(); console.log('begin', begin) let dividends = await DividendModel.updateDividendsStatus(begin, DIVIDEND_STATUS.END); await pushAuctionUpdate([], dividends); } export async function stopAuction() { try { console.log('schedule stopAuction called:', new Date()); const begin = await todayGuildBegin(); let lots = await LotModel.setLotSoldByBegin(begin, AUCTION_STAGE.WORLD); // 正在竞拍的拍品 await sendLotsRewardToMlail(lots); lots = await LotModel.updateLotsStageByBegin(begin, AUCTION_STAGE.END); if(isDebugTime()) { let day = getCurDay(); let time = getTimeFunM().getTimeWithWeek(day, 22, 0, 0); pinus.app.rpc.guild.guildActivityRemote.setCurrentTime.broadcast(time); await pushCurrentTime(time); } await pushAuctionUpdate(lots, []); return true; } catch (e) { console.error('stopAuction err: ', e); return false; } } // debug函数,修改客户端当前时间 export async function pushCurrentTime(time: number) { let serverlists = await getAllServers() for(let serverId of serverlists) { await sendMessageToServer(serverId, PUSH_ROUTE.PUSH_CURRENT_TIME, { time }); } } async function debugDividends() { const begin = await yestodayGuildBegin(); const dividends = await DividendModel.findDividendsByBegin(begin); const todayBegin = await todayGuildBegin(); const todayDividends = await DividendModel.findDividendsByBegin(todayBegin); return [...dividends, ...todayDividends]; } async function officialDividends() { const begin = await yestodayGuildBegin(); const dividends = await DividendModel.findDividendsByBegin(begin); return dividends; } async function updateDebugDividendsStatus(status: number) { const begin = await yestodayGuildBegin(); await DividendModel.updateDividendsStatus(begin, status); const todayBegin = await todayGuildBegin(); await DividendModel.updateDividendsStatus(todayBegin,status); } async function updateOfficialDividendsStatus(status: number) { const begin = await yestodayGuildBegin(); await DividendModel.updateDividendsStatus(begin, status); } export async function sendUngotDividendJob() { try { return await sendUngotDividend(); } catch (e) { console.error('sendUngotDividend err: ', e); return false; } } export function auctionBidStatus(roleId: string, lot: LotParam) { const { curBuyer, status } = lot; return curBuyer !== roleId ? AUCTION_BID_STATUS.RETURN : status === LOT_STATUS.SOLD || status === LOT_STATUS.MAX ? AUCTION_BID_STATUS.SUC : AUCTION_BID_STATUS.LEAD; } export function guildBidStatus(lot: { max: boolean, gid: number, count: number, price: number, dividendStatus: number }) { const { max, gid, count, price: lotPrice, dividendStatus } = lot; return max || ((dividendStatus == DIVIDEND_STATUS.END || dividendStatus == DIVIDEND_STATUS.SENT) && lotPrice !== 0) } export async function sendUngotDividend(debug = false) { try { console.log('schedule sendUngotDividend called:', new Date()); const dividends = debug === true ? await debugDividends() : await officialDividends(); const rewards = new Map(); for (let dividend of dividends) { if (!dividend.dividends || dividend.status === DIVIDEND_STATUS.SENT) 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); reportTAEvent(dividendRec.roleId, TA_EVENT.AUCTION_DIVIDEND, { type: getAuctionSourceTypeName(dividend.sourceType), count: dividendRec.total }) } } for (let [roleId, count] of rewards) { if(count > 0) { await sendMailByContent(MAIL_TYPE.GUILD_DIVIDEND, roleId, { params: [JSON.stringify(count)], goods: [{ id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count }] }); } } debug === true ? await updateDebugDividendsStatus(DIVIDEND_STATUS.SENT) : await updateOfficialDividendsStatus(DIVIDEND_STATUS.SENT); return true; } catch (e) { console.error('sendUngotDividend err: ', e); return false; } } /** * 获取拍卖行数据 * @param guildCode * @param session * @param magicWord */ export async function getAuction(guildCode: string, session: FrontendOrBackendSession, magicWord?: string) { const begin = await todayGuildBegin(); const tomorrowBegin = await tomorrowGuildBegin(); let lots = magicWord === DEBUG_MAGIC_WORD ? await debugAuctionLots(session, begin) : await officialAuctionLots(session, begin); let dividends: DividendType[] = []; if(guildCode) { dividends = await DividendModel.findGuildDividendsByBegin(guildCode, [begin, tomorrowBegin]); } return { lots, dividends: processDividendFormat(dividends) }; } export async function pushAuctionOver(lot: LotType) { if(lot.auctionStage == AUCTION_STAGE.GUILD) { await sendMessageToGuildWithSuc(lot.guildCode, PUSH_ROUTE.AUCTION_OVER, { lot: processSingleLotFormat(lot) }); } else if (lot.auctionStage == AUCTION_STAGE.WORLD) { await sendMessageToServerWithSuc(lot.serverId, PUSH_ROUTE.AUCTION_OVER, { lot: processSingleLotFormat(lot) }); } } export async function pushAuctionUpdate(lots: LotType[], dividends: DividendType[]) { let serverIds: number[] = []; for(let lot of lots) { if(serverIds.indexOf(lot.serverId) == -1) serverIds.push(lot.serverId); } for(let serverId of serverIds) { await sendMessageToServerWithSuc(serverId, PUSH_ROUTE.AUCTION_UPDATE, { }); } let dividendsResult = new Map(); for(let dividend of dividends) { if(!dividendsResult.has(dividend.guildCode)) { dividendsResult.set(dividend.guildCode, []); } dividendsResult.get(dividend.guildCode).push(dividend); } for(let [guildCode, dividends] of dividendsResult) { await sendMessageToGuildWithSuc(guildCode, PUSH_ROUTE.DIVIDEND_UPDATE, { dividends: processDividendFormat(dividends) }) } } export async function checkAuctionStage(auctionStage: number, magicWord: string) { if(magicWord == DEBUG_MAGIC_WORD) return true const curTime = await getCurrentTimeWithSetDay(); if(auctionStage != AUCTION_STAGE.GUILD && auctionStage != AUCTION_STAGE.WORLD) return false; if(auctionStage == AUCTION_STAGE.GUILD) { if(curTime < (await todayGuildBegin()).getTime()) return false; if(curTime > (await todayWorldBegin()).getTime()) return false } if(auctionStage == AUCTION_STAGE.WORLD) { if(curTime < (await todayWorldBegin()).getTime()) return false; if(curTime > (await todayWorldEnd()).getTime()) return false } return true } export async function isAuctionBidding() { const curTime = await getCurrentTimeWithSetDay(); const guildAuctionBeginTime = (await todayWorldBegin()).getTime(); return guildAuctionBeginTime - curTime <= AUCTION_BID_TIME * 1000; } /** * * @param max 玩家是否直接选择一口价 * @param maxFlag 竞拍是否达到一口价的价格了 * @param isBidding 是否在竞价时间重 */ export async function getLotStatus(auctionStage: number, max: boolean, maxFlag: boolean) { if(max) return LOT_STATUS.MAX; if(maxFlag) return LOT_STATUS.SOLD; if(auctionStage == AUCTION_STAGE.GUILD && await isAuctionBidding()) return LOT_STATUS.BIDDING; return LOT_STATUS.ING } export async function extendLotTime(lot: LotType) { clearLotTimer(lot.code); if(lot.status == LOT_STATUS.BIDDING) { let timer = setTimeout(async () => { await sendSingleLot(lot.code); }, lot.end.getTime() - Date.now()); setLotTimer(lot.code, timer); } } export async function sendSingleLot(code: string) { console.log('schedule sendSingleLot called:', new Date()); let lot = await LotModel.setLotSold(code, AUCTION_STAGE.GUILD); // 正在竞拍的拍品 if(!lot) return; await sendLotsRewardToMlail([lot]); await pushAuctionOver(lot); return true; } export function processSingleDividendFormat(dividend: DividendType) { if(!dividend) return null; let newDividend = { ...dividend, begin: getSeconds(dividend.begin)} return pick(newDividend, ['serverId', 'guildCode', 'sourceType', 'sourceCode', 'code', 'totalPrice', 'dividends', 'status', 'begin']) } export function processDividendFormat(dividends: DividendType[]) { return dividends.map(processSingleDividendFormat); } export function processSingleLotFormat(lot: LotType) { if(!lot) return null; let newLot = { ...lot, begin: getSeconds(lot.begin), end: getSeconds(lot.end)} return pick(newLot, ['auctionStage', 'sourceType', 'sourceCode', 'serverId', 'guildCode', 'code', 'gid', 'count', 'prePrice', 'curPrice', 'curBuyer', 'maxPrice', 'bidRoles', 'watchingRoles', 'begin', 'end', 'status', 'sort']) } export function processLotsFormat(lots: LotType[]) { return lots.map(processSingleLotFormat); } /** * 根据军团活动排名获得奖励 * @param aid 活动id * @param rank 排名 */ function getGuildAuction(aid: number, rank: number, struLv: number, cityId: number = 0) { let ranksReward = gameData.guildAuction.get(`${aid}_${struLv}_${cityId}`) || []; return ranksReward.find(cur => { return rank >= cur.min && (rank <= cur.max || cur.max == 0); }); } export function getGuildAuctionBasicNum(aid: number, rank: number, struLv: number, cityId: number = 0) { let dic = getGuildAuction(aid, rank, struLv, cityId); return dic?.basicDividend||0; } export function getGuildAuctionRewards(aid: number, rank: number, struLv: number, cityId: number = 0) { let dic = getGuildAuction(aid, rank, struLv, cityId); if(dic) { return getAuctionRewardByPoolId(dic.rewards); } else { return new Map(); } } export function getAuctionRewardByPoolId(poolId: number) { let pools = gameData.auctionPool.get(poolId); let rewards: Map = new Map(); for(let { count, basicPool } of pools) { let { rewardBasicPool, basePrice, maxPrice, sort } = basicPool for(let i = 0; i < count; i++) { let result = getRandEelmWithWeight(rewardBasicPool); if(result && result.dic) { let { id, count } = result.dic; if(isGoodsHidden(id)) continue; if(!rewards.has(id)) { rewards.set(id, []); } rewards.get(id).push({ goods: {id, count}, basePrice, maxPrice, sort }); } } } return rewards; } export function biddingLotTimeout() { scheduleJob('', () => {}) }