diff --git a/game-server/app/servers/battle/handler/auctionHandler.ts b/game-server/app/servers/battle/handler/auctionHandler.ts index 54fc8f1f1..e8e9f1136 100644 --- a/game-server/app/servers/battle/handler/auctionHandler.ts +++ b/game-server/app/servers/battle/handler/auctionHandler.ts @@ -1,3 +1,5 @@ +import { AUCTION_BID_STATUS } from './../../../consts/constModules/auctionConst'; +import { pick } from 'lodash'; 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"; @@ -82,7 +84,7 @@ export class AuctionHandler { newPrice = maxPrice; await addItems(roleId, roleName, sid, [{ id: gid, count }]); } - bidRoles.push({roleId, price: newPrice, time: new Date()}); + 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])) }); res.releaseCallback(); @@ -122,15 +124,52 @@ export class AuctionHandler { } async getDividend(msg: { sourceType: number }, session: BackendSession) { - return resResult(STATUS.SUCCESS); + const roleId = session.get('roleId'); + const sid = session.get('sid'); + const roleName = session.get('roleName'); + const guildCode = session.get('guildCode'); + const { sourceType } = msg; + const dividendData = await DividendModel.findReadyDividend(guildCode, sourceType); + if (!dividendData) return resResult(STATUS.DIVIDEND_NOT_READY); + const { dividends } = dividendData; + const dividend = dividends.find(item => { return item.roleId === roleId }); + if (!dividend) return resResult(STATUS.DIVIDEND_GUILD_PLAYER_ONLY); + await addItems(roleId, roleName, sid, [{ id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD), count: dividend.total }]); + await DividendModel.updateReceiveStatus(dividendData.code, roleId); + return resResult(STATUS.SUCCESS, { dividend }); } - async myOffers(msg: {}, session: BackendSession) { - return resResult(STATUS.SUCCESS); + async myWatching(msg: {}, session: BackendSession) { + const roleId = session.get('roleId'); + const serverId = session.get('serverId'); + const begin = todayGuildBegin(); + const lots = await LotModel.watchingLotsByBegin(serverId, roleId, begin); + return resResult(STATUS.SUCCESS, { lots }); } async offerRecs(msg: { count: number }, session: BackendSession) { - return resResult(STATUS.SUCCESS); + const roleId = session.get('roleId'); + const serverId = session.get('serverId'); + const lotsData = await LotModel.recentBidLots(serverId, roleId, msg.count); + const bidRecs = lotsData.map(lot => { + const bidRec = lot.bidRoles.find(role => { return role.roleId === roleId }); + const { curBuyer } = lot; + return { ...bidRec, status: curBuyer === roleId ? AUCTION_BID_STATUS.SUC : AUCTION_BID_STATUS.RETURN }; + }); + return resResult(STATUS.SUCCESS, { bidRecs }); + } + + // ! 测试接口 + async debugSetDividendReady(msg: { magicWord: string, sourceType: number}, session: BackendSession) { + const { magicWord, sourceType } = msg; + if (magicWord !== DEBUG_MAGIC_WORD) { + return resResult(STATUS.TOKEN_ERR); + } + + const guildCode: string = session.get('guildCode'); + if (!guildCode) return resResult(STATUS.GUILD_NOT_FOUND) + const dividend = await DividendModel.updateDividendReady(guildCode, sourceType); + return resResult(STATUS.SUCCESS, { dividend }); } // ! 测试接口 diff --git a/game-server/test/auction.test.ts b/game-server/test/auction.test.ts index 935e71458..291aa09e5 100644 --- a/game-server/test/auction.test.ts +++ b/game-server/test/auction.test.ts @@ -3,7 +3,7 @@ import 'mocha'; import { PinusWSClient } from 'pinus-robot-plugin'; import { expect } from 'chai'; import { checkSuccessResponse } from './CheckPatten'; -import { DEBUG_MAGIC_WORD, AUCTION_SOURCE } from '../app/consts'; +import { DEBUG_MAGIC_WORD, AUCTION_SOURCE, CURRENCY_BY_TYPE, CURRENCY_TYPE } from '../app/consts'; import { LOT_STATUS } from '../../shared/consts'; const GOOD_ID_TIEJIAN = 1; @@ -191,22 +191,69 @@ describe('拍卖行测试', function() { }); it('领取分红', function(done) { - pinusClient.request('battle.auctionHandler.getDividend', {}, (res) => { - checkSuccessResponse(res, false); - done(); + pinusClient.on('onItemUpdate', (res) => { + checkSuccessResponse(res); + expect(res.data.goods).to.be.an('array'); + for (let info of res.data.goods) { + expect(info.id).to.be.equal(CURRENCY_BY_TYPE.get(CURRENCY_TYPE.GOLD)); + } + }); + pinusClient.request('battle.auctionHandler.debugSetDividendReady', { magicWord: DEBUG_MAGIC_WORD, sourceType: AUCTION_SOURCE.GATE }, (res) => { + checkSuccessResponse(res); + checkDividend(res.data.dividend); + pinusClient.request('battle.auctionHandler.getDividend', { sourceType: AUCTION_SOURCE.GATE }, (res) => { + checkSuccessResponse(res); + expect(res.data.dividend).to.be.an('object'); + expect(res.data.dividend.roleId).to.be.a('string'); + expect(res.data.dividend.baseNum).to.be.a('number'); + expect(res.data.dividend.posNum).to.be.a('number'); + expect(res.data.dividend.weekendNum).to.be.a('number'); + expect(res.data.dividend.total).to.be.a('number'); + expect(res.data.dividend.status).to.be.a('number'); + setTimeout(() => { + done(); + }, 100); + }); }); }); it('查看我的关注', function(done) { - pinusClient.request('battle.auctionHandler.myOffers', {}, (res) => { - checkSuccessResponse(res, false); - done(); + pinusClient.request('battle.auctionHandler.getAuction', {}, (res) => { + checkSuccessResponse(res); + expect(res.data.lots).to.be.an('array'); + checkLots(res.data.lots); + expect(res.data.dividends).to.be.an('array'); + checkDividends(res.data.dividends); + if (res.data.lots.length === 0) { + console.warn('没有可关注的拍品'); + done(); + return; + } + const code = res.data.lots[0].code; + pinusClient.request('battle.auctionHandler.watchLot', { code }, (res) => { + checkSuccessResponse(res); + checkLot(res.data.lot); + expect(res.data.lot.watchingRoles.indexOf(roleInfo.roleId)).to.be.above(-1); + pinusClient.request('battle.auctionHandler.myWatching', {}, (res) => { + checkSuccessResponse(res); + checkLots(res.data.lots); + done(); + }); + }); }); + }); it('查看我的拍卖纪录', function(done) { pinusClient.request('battle.auctionHandler.offerRecs', { count: 10 }, (res) => { - checkSuccessResponse(res, false); + checkSuccessResponse(res); + expect(res.data.bidRecs).to.be.an('array'); + for (let bidRec of res.data.bidRecs) { + expect(bidRec.roleId).to.be.a('string'); + expect(bidRec.price).to.be.a('number'); + expect(Date.parse(bidRec.time)).to.be.a('number'); + expect(bidRec.status).to.be.a('number'); + } done(); }); }); diff --git a/shared/consts/constModules/auctionConst.ts b/shared/consts/constModules/auctionConst.ts index 1fd1f1e58..a8a67a6b1 100644 --- a/shared/consts/constModules/auctionConst.ts +++ b/shared/consts/constModules/auctionConst.ts @@ -41,4 +41,16 @@ export const LOT_STATUS = { SOLD: 2, // 已拍出 } +export const ROLE_RECEIVE_STATUS = { + NO: 0, // 没领取 + YES: 1, // 领取了 +} + +export const AUCTION_BID_STATUS = { + LEAD: 0, // 领先 + RETURN: 1, // 退还 + SUC: 2, // 竞拍成功 +} + export const OFFER_RATIO = 1.1; +export const BID_REC_COUNT = 100; diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index 772152f9c..5ac361185 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -194,6 +194,8 @@ export const STATUS = { GUILD_LOT_NOT_FOUND: { code: 21001, simStr: '拍品未找到' }, LOT_OFFER_SERIAL: { code: 21002, simStr: '不能连续出价' }, + DIVIDEND_NOT_READY: { code: 21003, simStr: '还不可以领取分红' }, + DIVIDEND_GUILD_PLAYER_ONLY: { code: 21004, simStr: '需要参加军团活动才能领取' }, // 军团活动 21100-21199 GUILD_ACTIVITY_NOT_OPEN: { code: 21100, simStr: '活动未开放' }, diff --git a/shared/db/Dividend.ts b/shared/db/Dividend.ts index 8c9bc9c7a..a431e0235 100644 --- a/shared/db/Dividend.ts +++ b/shared/db/Dividend.ts @@ -2,6 +2,7 @@ import { LotRec, DividendRec } from './../domain/dbGeneral'; import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, modelOptions } from '@typegoose/typegoose'; import { genCode } from '../pubUtils/util'; +import { DIVIDEND_STATUS, ROLE_RECEIVE_STATUS } from '../consts'; /** * 分红记录表 @@ -22,11 +23,11 @@ export default class Dividend extends BaseModel { sourceCode: string; // 来源的唯一标识,如活动编号 @prop({ required: true, default: '' }) code: string; // 分红记录唯一标识 - @prop({ required: true, type: LotRec, default: [] }) + @prop({ required: true, type: LotRec, default: [], _id: false }) lots: LotRec[]; @prop({ required: true, default: 0 }) totalPrice: number; // 分红总金额 - @prop({ required: true, type: DividendRec, default: [] }) + @prop({ required: true, type: DividendRec, default: [], _id: false }) dividends: DividendRec[]; @prop({ required: true, default: 0 }) status: number; // 0:未开始;1:进行中;2:已结束;3:已发放 @@ -64,6 +65,21 @@ export default class Dividend extends BaseModel { const result = await DividendModel.findOneAndUpdate({ 'lots.code': lotCode }, { 'lots.$.gid': gid, 'lots.$.price': price, $inc: { totalPrice: incPrice} }, { new: true }).select('-_id -__v').lean(); return result; } + + public static async findReadyDividend(guildCode: string, sourceType: number) { + 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(); + return result; + } + + public static async updateDividendReady(guildCode: string, sourceType: number) { + const result: DividendType = await DividendModel.findOneAndUpdate({ guildCode, sourceType }, { status: DIVIDEND_STATUS.END }, { new: true }).select('-_id -__v').lean(); + return result; + } } export const DividendModel = getModelForClass(Dividend); diff --git a/shared/db/Lot.ts b/shared/db/Lot.ts index dddd53ab5..b2c3a9a82 100644 --- a/shared/db/Lot.ts +++ b/shared/db/Lot.ts @@ -2,6 +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'; /** * 竞拍物品表 @@ -9,6 +10,7 @@ import { genCode } from '../pubUtils/util'; @modelOptions({ schemaOptions: { id: false } }) @index({ code: 1 }) @index({ guildCode: 1, begin: -1 }) +@index({ serverId: 1, begin: -1, watchingRoles: 1 }) export default class Lot extends BaseModel { @prop({ required: true, default: 0 }) auctionStage: number; // 0:初始添加,1:军团拍卖,2:世界拍卖,3:拍卖结束 @@ -90,6 +92,16 @@ export default class Lot extends BaseModel { const result: LotType = await LotModel.findOneAndUpdate({ code }, { $pull: { watchingRoles: roleId } }, { new: true }).select('-_id -__v').lean(); return result; } + + public static async watchingLotsByBegin(serverId: number, roleId: string, begin: Date) { + const results: LotType[] = await LotModel.find({ serverId, begin, watchingRoles: roleId }).select('-_id -__v').lean(); + return results; + } + + 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(); + return results; + } } export const LotModel = getModelForClass(Lot);