diff --git a/game-server/app/servers/battle/handler/auctionHandler.ts b/game-server/app/servers/battle/handler/auctionHandler.ts index 4bfc58246..7342dff74 100644 --- a/game-server/app/servers/battle/handler/auctionHandler.ts +++ b/game-server/app/servers/battle/handler/auctionHandler.ts @@ -3,9 +3,9 @@ import { DividendModel } from './../../../db/Dividend'; import { Application, BackendSession, ChannelService } from "pinus"; import { AUCTION_STAGE, DEBUG_MAGIC_WORD, STATUS, OFFER_RATIO, CURRENCY_BY_TYPE, CURRENCY_TYPE, DATA_NAME, LOT_STATUS } from "../../../consts"; import { LotModel } from "../../../db/Lot"; -import { ItemReward } from "../../../domain/dbGeneral"; +import { ItemReward, LotRec } from "../../../domain/dbGeneral"; import { resResult } from "../../../pubUtils/util"; -import { auctionStage, calculateDividend, genAuction, sendUngotDividend, startGuildAuction, startWorldAuction, stopAuction, todayGuildBegin } from "../../../services/auctionService"; +import { auctionStage, calculateDividend, genAuction, sendUngotDividend, startGuildAuction, startWorldAuction, stopAuction, todayGuildBegin, getBasePrice } from "../../../services/auctionService"; import { addItems, handleCost } from '../../../services/rewardService'; import { getSimpleRoleInfo } from '../../../services/roleService'; import { getRoleOnlineInfo } from '../../../services/redisService'; @@ -51,7 +51,7 @@ export class AuctionHandler { } const lot = await LotModel.findLot(code); - if (!lot || lot.status === LOT_STATUS.SOLD) { + if (!lot || lot.status === LOT_STATUS.SOLD || lot.status === LOT_STATUS.MAX) { res.releaseCallback(); return resResult(STATUS.GUILD_LOT_NOT_FOUND); } @@ -84,12 +84,15 @@ export class AuctionHandler { await addItems(roleId, roleName, sid, [{ id: gid, count }]); } bidRoles.push({ roleId, price: newPrice, time: new Date() }); - const newLot = await LotModel.updateLot({ code, curBuyer: roleId, curPrice: newPrice, bidRoles, status: maxFlag ? LOT_STATUS.SOLD : LOT_STATUS.ING, watchingRoles: Array.from(new Set([...watchingRoles, roleId])) }); + const newLot = await LotModel.updateLot({ code, curBuyer: roleId, curPrice: newPrice, bidRoles, status: max ? LOT_STATUS.MAX : (maxFlag ? LOT_STATUS.SOLD : LOT_STATUS.ING), watchingRoles: Array.from(new Set([...watchingRoles, roleId])) }); res.releaseCallback(); const incPrice = newPrice - (curBuyer ? curPrice : 0); - const dividend = await DividendModel.updateLot(code, gid, newPrice, incPrice); - const newDividend = await calculateDividend(dividend); + let newDividend = null; + if (auctionStage() === AUCTION_STAGE.GUILD) { + const dividend = await DividendModel.updateLot(code, gid, newPrice, incPrice, max); + newDividend = await calculateDividend(dividend); + } return resResult(STATUS.SUCCESS, { lot: newLot, dividend: newDividend }); } catch (e) { console.log('offer got err:', e); @@ -159,6 +162,25 @@ export class AuctionHandler { return resResult(STATUS.SUCCESS, { bidRecs }); } + async guildLotRecs(msg: { count: number }, session: BackendSession) { + const guildCode = session.get('guildCode'); + const dividends = await DividendModel.findDividendsByGuild(guildCode, msg.count); + let lotsData: LotRec[] = []; + dividends.forEach(dividend => { + const lots = dividend.lots.map(lot => { + return { ...lot, sourceType: dividend.sourceType }; + }) + lotsData = [...lotsData, ...lots]; + }); + const lotRecs = lotsData.map(lot => { + const price = lot.price === 0 ? getBasePrice(lot.gid, lot.count) : lot.price; + const sold = lot.price !== 0; + return { ...lot, price, sold }; + }); + + return resResult(STATUS.SUCCESS, { lotRecs }); + } + // ! 测试接口 async debugSetDividendStatus(msg: { magicWord: string, sourceType: number, status: number }, session: BackendSession) { const { magicWord, sourceType, status } = msg; diff --git a/game-server/app/services/auctionService.ts b/game-server/app/services/auctionService.ts index ed4d59472..c6e6bffd2 100644 --- a/game-server/app/services/auctionService.ts +++ b/game-server/app/services/auctionService.ts @@ -13,7 +13,7 @@ import { getMailContent } from './mailService'; import { pinus } from 'pinus'; // ! 获取底价,假数据 -function getBasePrice(gid: number, count: number) { +export function getBasePrice(gid: number, count: number) { const good = getGoodById(gid); return (good ? good.quality * 100 : 100) * count; } @@ -36,6 +36,10 @@ export function auctionBegin() { return getNextTime(new Date(), AUCTION_TIME.GUILD_BEGIN_HOUR, AUCTION_TIME.GUILD_BEGIN_MIN); } +export function guildAuctionEnd() { + return getNextTime(new Date(), AUCTION_TIME.GUILD_END_HOUR, AUCTION_TIME.GUILD_END_MIN); +} + export function auctionEnd() { return getNextTime(new Date(), AUCTION_TIME.WORLD_END_HOUR, AUCTION_TIME.WORLD_END_MIN); } @@ -67,6 +71,7 @@ export function todayWorldEnd() { */ export async function genAuction(guildCode: string, sourceType: number, sourceCode: string, serverId: number, rewards: ItemReward[]) { const begin = auctionBegin(); + const guildEnd = guildAuctionEnd(); const end = auctionEnd(); const lotsData: LotParam[] = rewards.map(reward => { const { id, count } = reward; @@ -82,7 +87,7 @@ export async function genAuction(guildCode: string, sourceType: number, sourceCo 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 } + return { code, gid, price: 0, time: guildEnd, max: false, count: lot.count } }), }; const dividend = await DividendModel.createDividend(dividendData); @@ -172,6 +177,7 @@ export async function startWorldAuction() { try { console.log('schedule startWorldAuction called:', new Date()); const begin = todayGuildBegin(); + await LotModel.setLotSoldByBegin(begin); await LotModel.updateLotsStageByBegin(begin, AUCTION_STAGE.WORLD); return true; } catch (e) { @@ -184,6 +190,7 @@ export async function stopAuction() { try { console.log('schedule stopAuction called:', new Date()); const begin = todayGuildBegin(); + await LotModel.setLotSoldByBegin(begin); await LotModel.updateLotsStageByBegin(begin, AUCTION_STAGE.END); await DividendModel.updateDividendsStatus(begin, DIVIDEND_STATUS.END); return true; diff --git a/game-server/test/auction.test.ts b/game-server/test/auction.test.ts index 3e6762057..689e9f1ac 100644 --- a/game-server/test/auction.test.ts +++ b/game-server/test/auction.test.ts @@ -132,7 +132,9 @@ describe('拍卖行测试', function() { pinusClient.request('battle.auctionHandler.offer', { code: unsoldLots[0].code, max: false }, (res) => { checkSuccessResponse(res); checkLot(res.data.lot); - checkDividend(res.data.dividend); + if (res.data.dividend) { + checkDividend(res.data.dividend); + } expect(res.data.lot.curBuyer).to.be.equal(roleInfo.roleId); done(); }); @@ -201,6 +203,13 @@ describe('拍卖行测试', function() { pinusClient.request('battle.auctionHandler.debugSetDividendStatus', { magicWord: DEBUG_MAGIC_WORD, sourceType: AUCTION_SOURCE.GATE, status: DIVIDEND_STATUS.END }, (res) => { checkSuccessResponse(res); checkDividend(res.data.dividend); + // TODO: 找个测试领取分红的方法 + const dividend = res.data.dividend.dividends.find(d => { return d.roleId === roleInfo.roleId }); + if (!dividend) { + console.warn('未测试到领取分红的情况'); + done(); + return; + } pinusClient.request('battle.auctionHandler.getDividend', { sourceType: AUCTION_SOURCE.GATE }, (res) => { checkSuccessResponse(res); expect(res.data.dividend).to.be.an('object'); @@ -267,6 +276,11 @@ describe('拍卖行测试', function() { pinusClient.request('battle.auctionHandler.offerRecs', { count: 10 }, (res) => { checkSuccessResponse(res); expect(res.data.bidRecs).to.be.an('array'); + if (res.data.bidRecs.length === 0) { + console.warn('没有我的拍卖纪录'); + done(); + return; + } for (let bidRec of res.data.bidRecs) { expect(bidRec.roleId).to.be.a('string'); expect(bidRec.price).to.be.a('number'); @@ -278,6 +292,28 @@ describe('拍卖行测试', function() { }); }); + + it('获取军团拍卖记录', function(done) { + pinusClient.request('battle.auctionHandler.guildLotRecs', { count: 10 }, (res) => { + checkSuccessResponse(res); + expect(res.data.lotRecs).to.be.an('array'); + if (res.data.lotRecs.length === 0) { + console.warn('没有军团拍卖纪录'); + done(); + return; + } + for (let lotRec of res.data.lotRecs) { + expect(lotRec.price).to.be.a('number'); + expect(Date.parse(lotRec.time)).to.be.a('number'); + expect(lotRec.gid).to.be.a('number'); + expect(lotRec.sourceType).to.be.a('number'); + expect(lotRec.max).to.be.a('boolean'); + expect(lotRec.sold).to.be.a('boolean'); + } + done(); + }); + }); + it('测试接口,军团拍卖定时', function(done) { pinusClient.request('battle.auctionHandler.debugScheduleStartGuild', { magicWord: DEBUG_MAGIC_WORD }, (res) => { checkSuccessResponse(res, false); diff --git a/shared/consts/constModules/auctionConst.ts b/shared/consts/constModules/auctionConst.ts index b416516ed..4f6066e1d 100644 --- a/shared/consts/constModules/auctionConst.ts +++ b/shared/consts/constModules/auctionConst.ts @@ -38,7 +38,8 @@ export const DIVIDEND_STATUS = { export const LOT_STATUS = { DEFAULT: 0, // 未开始 ING: 1, // 竞拍中 - SOLD: 2, // 已拍出 + SOLD: 2, // 竞拍成功 + MAX: 3, // 一口价 } export const ROLE_RECEIVE_STATUS = { @@ -54,6 +55,7 @@ export const AUCTION_BID_STATUS = { export const OFFER_RATIO = 1.1; export const BID_REC_COUNT = 100; +export const GUILD_LOTS_REC_COUNT = 100; export const DIVIDENDWEEKENDRATE = 0.2; export const DIVIDENDMAXRATIO = 0.1; export const DIVIDENDPOSITIONMAXRATIO = 3; diff --git a/shared/db/Dividend.ts b/shared/db/Dividend.ts index 4ae87180a..33f2da43f 100644 --- a/shared/db/Dividend.ts +++ b/shared/db/Dividend.ts @@ -61,13 +61,18 @@ export default class Dividend extends BaseModel { return results; } + public static async findDividendsByGuild(guildCode: string, count: number) { + const results = await DividendModel.find({ guildCode }).limit(count).sort({ _id: -1 }).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; } - public static async updateLot(lotCode: string, gid: number, price: number, incPrice: number) { - const result = await DividendModel.findOneAndUpdate({ 'lots.code': lotCode }, { 'lots.$.gid': gid, 'lots.$.price': price, $inc: { totalPrice: incPrice} }, { new: true }).select('-_id -__v').lean(); + public static async updateLot(lotCode: string, gid: number, price: number, incPrice: number, max: boolean) { + const result = await DividendModel.findOneAndUpdate({ 'lots.code': lotCode }, { 'lots.$.gid': gid, 'lots.$.price': price, 'lots.$.time': new Date(), 'lots.$.max': max, $inc: { totalPrice: incPrice} }, { new: true }).select('-_id -__v').lean(); return result; } diff --git a/shared/db/Lot.ts b/shared/db/Lot.ts index fa740ca6d..c12bbcc6c 100644 --- a/shared/db/Lot.ts +++ b/shared/db/Lot.ts @@ -2,7 +2,7 @@ import { BidRec } from './../domain/dbGeneral'; import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose'; import { genCode } from '../pubUtils/util'; -import { BID_REC_COUNT } from '../consts'; +import { BID_REC_COUNT, GUILD_LOTS_REC_COUNT, LOT_STATUS } from '../consts'; /** * 竞拍物品表 @@ -43,7 +43,7 @@ export default class Lot extends BaseModel { @prop({ required: true }) end: Date; // 竞拍结束时间 @prop({ required: true, default: 0 }) - status: number; // 拍品状态,0:无人竞拍;1:竞拍中;2:已拍 + status: number; // 拍品状态,0:无人竞拍;1:竞拍中;2:已竞拍;3:一口价 public static async createRec(data: LotParam) { const code = genCode(8); @@ -62,6 +62,11 @@ export default class Lot extends BaseModel { return result; } + public static async findLots(codes: string[]) { + const result = await LotModel.find({ code: {$in: codes} }).select('-_id -__v').lean(); + return result; + } + public static async findGuildLotsByBegin(guildCode: string, begin: Date) { const results = await LotModel.find({ guildCode, begin }).select('-_id -__v').lean(); return results; @@ -77,6 +82,11 @@ export default class Lot extends BaseModel { return results; } + public static async recentGuildLots(guildCode: string, count = GUILD_LOTS_REC_COUNT ) { + const results = await LotModel.find({ guildCode }).sort({ _id: -1 }).limit(count).select('-_id -__v').lean(); + return results; + } + public static async updateLot(data: LotParam) { const code = data.code!; const result: LotType = await LotModel.findOneAndUpdate({ code }, { ...data }, { new: true }).select('-_id -__v').lean(); @@ -99,7 +109,7 @@ export default class Lot extends BaseModel { } public static async recentBidLots(serverId: number, roleId: string, count = BID_REC_COUNT) { - const results: LotType[] = await LotModel.find({ serverId, 'bidRoles.roleId': roleId }).select('-_id -__v').limit(count).lean(); + const results: LotType[] = await LotModel.find({ serverId, 'bidRoles.roleId': roleId }).select('-_id -__v').sort({ _id: -1 }).limit(count).lean(); return results; } @@ -112,6 +122,11 @@ export default class Lot extends BaseModel { const results = await LotModel.updateMany({ begin }, { auctionStage }).select('-_id -__v').lean(); return results; } + + public static async setLotSoldByBegin(begin: Date) { + const results = await LotModel.updateMany({ begin, status: LOT_STATUS.ING }, { status: LOT_STATUS.SOLD }).select('-_id -__v').lean(); + return results; + } } export const LotModel = getModelForClass(Lot); diff --git a/shared/domain/dbGeneral.ts b/shared/domain/dbGeneral.ts index f23c9865b..00b1c7e9b 100644 --- a/shared/domain/dbGeneral.ts +++ b/shared/domain/dbGeneral.ts @@ -254,7 +254,13 @@ export class LotRec { @prop({ required: true, default: 0 }) gid: number; // 物品 id @prop({ required: true, default: 0 }) + count: number; // 物品数量 + @prop({ required: true, default: 0 }) price: number; // 物品成交价 + @prop({ required: true, default: null }) + time: Date; // 出价时间 + @prop({ required: true, default: 0 }) + max: boolean; // 出价时间 } /**