diff --git a/game-server/app/servers/activity/handler/groupShopHandler.ts b/game-server/app/servers/activity/handler/groupShopHandler.ts new file mode 100644 index 000000000..26496e022 --- /dev/null +++ b/game-server/app/servers/activity/handler/groupShopHandler.ts @@ -0,0 +1,106 @@ +import { Application, BackendSession, HandlerService, } from "pinus"; +import { resResult } from "../../../pubUtils/util"; +import { STATUS, ITEM_CHANGE_REASON, GROUP_SHOP_PRICE_STATUS, PUSH_ROUTE, } from "../../../consts"; +import { getGroupShopData, getGroupShopDataShow, getGroupShopPriceStatus } from "../../../services/activity/groupShopService"; +import { addItems, getGoldObject, handleCost } from "../../../services/role/rewardService"; +import { ActivityGroupShopUserRecModel, GroupShopBuyRecord } from "../../../db/ActivityGroupShopUserRec"; +import { ActivityGroupShopRecModel, GroupShopRecord } from "../../../db/ActivityGroupShopRec"; +import { pick } from "underscore"; +import { addRoleToGroupShopChannel, leaveGroupShopChannel } from "../../../services/chatChannelService"; +import { sendMessageToGroupShopWithSuc } from "../../../services/pushService"; + +export default function (app: Application) { + new HandlerService(app, {}); + return new GroupShopHandler(app); +} + +export class GroupShopHandler { + constructor(private app: Application) { + } + + /** + * @description 1. 进入团购主页面 + * @param {{}} msg + * @param {BackendSession} session + * @memberof GroupShopHandler + */ + async getGroupShopPage(msg: { activityId: number }, session: BackendSession) { + const { activityId } = msg; + const roleId: string = session.get('roleId'); + const sid: string = session.get('sid'); + + let playerData = await getGroupShopDataShow(activityId, roleId); + if (!playerData) { + return resResult(STATUS.ACTIVITY_MISSING); + } + await addRoleToGroupShopChannel(roleId, sid); + + return resResult(STATUS.SUCCESS, { playerData }); + } + + /** + * @description 2. 离开团购主页面 + * @param {{}} msg + * @param {BackendSession} session + * @memberof GroupShopHandler + */ + async leaveGroupShopPage(msg: { activityId: number }, session: BackendSession) { + const roleId: string = session.get('roleId'); + const sid: string = session.get('sid'); + + await leaveGroupShopChannel(roleId, sid) + return resResult(STATUS.SUCCESS); + } + + /** + * @description 3. 购买 + * @param {{}} msg + * @param {BackendSession} session + * @memberof GroupShopHandler + */ + async buy(msg: { activityId: number, price: number, id: number, buyCnt: number }, session: BackendSession) { + const { activityId, price: clientPrice, id, buyCnt } = msg; + const roleId: string = session.get('roleId'); + const roleName: string = session.get('roleName'); + const sid: string = session.get('sid'); + + let playerData = await getGroupShopData(activityId, roleId); + if (!playerData) return resResult(STATUS.ACTIVITY_MISSING); + + let item = playerData.findItemById(id); + if (!item) return resResult(STATUS.ACTIVITY_GROUP_SHOP_ITEM_NOT_FOUND); + if(!item.checkBuyCnt(buyCnt)) return resResult(STATUS.ACTIVITY_GROUP_SHOP_BUY_CNT_MAX); + + let curDiscount = item.getCurDiscount(); + let priceStatus = getGroupShopPriceStatus(clientPrice, curDiscount.price); + if(priceStatus == GROUP_SHOP_PRICE_STATUS.NOT_ENOUGH) return resResult(STATUS.ACTIVITY_GROUP_SHOP_PRICE_ERR); + let cost = [getGoldObject(curDiscount.price)]; + let result = await handleCost(roleId, sid, cost, ITEM_CHANGE_REASON.ACT_GROUP_SHOP_BUY); + if(!result) return resResult(STATUS.BATTLE_GOLD_NOT_ENOUGH); + + // 玩家添加次数 + let playerRecord = await ActivityGroupShopUserRecModel.incBuyCnt(activityId, roleId, id, item.gid, buyCnt, new GroupShopBuyRecord(curDiscount, buyCnt)); + playerData.setPlayerRecord([playerRecord]); + // 全服添加次数 + let serverRecord = await ActivityGroupShopRecModel.incBuyCnt(activityId, id, item.gid, buyCnt); + let isRankUp = playerData.incAllRecord(serverRecord); + + item = playerData.findItemById(id); + let nextDiscount = item.getCurDiscount(); + if(isRankUp) { + await ActivityGroupShopRecModel.addRecord(activityId, id, new GroupShopRecord(nextDiscount)); + // 推送频道 + await sendMessageToGroupShopWithSuc(PUSH_ROUTE.GROUP_SHOP_UPDATE, { activityId, id, curDiscount: nextDiscount }); + } + let reward = [{ id: item.gid, count: item.count * buyCnt }]; + let goods = await addItems(roleId, roleName, sid, reward, ITEM_CHANGE_REASON.ACT_GROUP_SHOP_BUY); + + return resResult(STATUS.SUCCESS, { + curItem: pick(item, ['id', 'gid', 'sum', 'hasBoughtCnt']), + goods, + status: priceStatus, + oldDiscount: curDiscount, + nextDiscount + }); + } +} \ No newline at end of file diff --git a/game-server/app/servers/connector/handler/entryHandler.ts b/game-server/app/servers/connector/handler/entryHandler.ts index beb8e7e77..f60f26413 100644 --- a/game-server/app/servers/connector/handler/entryHandler.ts +++ b/game-server/app/servers/connector/handler/entryHandler.ts @@ -11,7 +11,7 @@ import { COM_BTL_QUALITY, HERO_SELECT, DEBUG_MAGIC_WORD, REDIS_KEY, TASK_TYPE, E import { nowSeconds, getZeroPoint } from '../../../pubUtils/timeUtil'; import { rmRoleFromQueue, roleLeave, getRoleOnlineInfo, roleLogin, getOnlineRoleByUserCode } from '../../../services/redisService'; -import { addRoleToGuildChannel, addRoleToSysChannel, addRoleToWorldChannel, leaveGuildAuctionChannel, leaveGuildChannel, leaveSysChannel, leaveWorldAuctionChannel, leaveWorldChannel, recentGuildMsgs, recentPrivateChatInfos, recentSysMsgs, recentWorldMsgs } from '../../../services/chatService'; +import { addRoleToGuildChannel, addRoleToSysChannel, addRoleToWorldChannel, leaveGroupShopChannel, leaveGuildAuctionChannel, leaveGuildChannel, leaveSysChannel, leaveWorldAuctionChannel, leaveWorldChannel, recentGuildMsgs, recentPrivateChatInfos, recentSysMsgs, recentWorldMsgs } from '../../../services/chatService'; import { reportOneOnline, savePlayTime } from '../../../services/authenticateService'; import { checkTaskInEntry, } from '../../../services/task/taskService'; import { pushData, kickUser, getModuleData, assignServer, leaveServer } from '../../../services/connectorService'; @@ -205,6 +205,7 @@ export class EntryHandler { await leaveGuildChannel(roleId, sid, guildCode); await leaveGuildAuctionChannel(roleId, sid, guildCode); await leaveWorldAuctionChannel(roleId, sid, serverId); + await leaveGroupShopChannel(roleId, sid); RoleModel.updateRoleInfo(roleId, { quitTime: nowSeconds() }); // if(teamCode) { // 如果有寻宝中的队伍,那么等于战败 // setComBtlOnUserLeave(roleId, teamCode) diff --git a/game-server/app/services/activity/activityService.ts b/game-server/app/services/activity/activityService.ts index c712a01fc..6be20f55b 100644 --- a/game-server/app/services/activity/activityService.ts +++ b/game-server/app/services/activity/activityService.ts @@ -39,6 +39,7 @@ import { isArray } from 'underscore'; import { getGuideGachaData } from './gachaService'; import { getPopNoticeData } from './popNoticeService'; import { _getActivities, _getActivitiesByServerId, _getActivitiesByType, _getActivityById } from './activityRemoteService'; +import { getGroupShopDataShow } from './groupShopService'; /** * 获取活动数据 @@ -222,6 +223,11 @@ export async function getActivity(serverId: number, roleId: string, guildCode: s activityData = await getPopNoticeData(serverId, activityId, roleId); break } + case ACTIVITY_TYPE.GROUP_SHOP: + { + activityData = await getGroupShopDataShow(activityId, roleId); + break + } default: { console.log('未知活动类型.........', activityType) break; diff --git a/game-server/app/services/activity/groupShopService.ts b/game-server/app/services/activity/groupShopService.ts new file mode 100644 index 000000000..4701fd775 --- /dev/null +++ b/game-server/app/services/activity/groupShopService.ts @@ -0,0 +1,41 @@ +import { GROUP_SHOP_PRICE_STATUS } from "../../consts"; +import { ActivityGroupShopRecModel } from "../../db/ActivityGroupShopRec"; +import { ActivityGroupShopUserRecModel } from "../../db/ActivityGroupShopUserRec"; +import { GroupShopData } from "../../domain/activityField/groupShopField"; +import { getRoleCreateTime, getServerCreateTime } from "../redisService"; +import { getActivityById } from "./activityService"; + +/** + * 玩家活动数据 + * + * @param {number} serverId 区Id + * @param {number} activityId 活动Id + * @param {string} roleId 角色Id + * + */ + export async function getGroupShopData(activityId: number, roleId: string) { + let activityData = await getActivityById(activityId); + let createTime = await getRoleCreateTime(roleId); + + let playerData = new GroupShopData(activityData, createTime, 0); + let serverRecords = await ActivityGroupShopRecModel.findByActivity(activityId); + playerData.setRecords(serverRecords); + let playerRecords = await ActivityGroupShopUserRecModel.findByActivityAndRoleId(activityId, roleId); + playerData.setPlayerRecord(playerRecords); + + return playerData; +} + +export async function getGroupShopDataShow(activityId: number, roleId: string) { + let playerData = await getGroupShopData(activityId, roleId); + if(playerData && playerData.canShow && playerData.canShow()) { + return playerData.getShowResult(); + } + return null +} + +export function getGroupShopPriceStatus(clientPrice: number, price: number) { + if(clientPrice == price) return GROUP_SHOP_PRICE_STATUS.NORMAL; + if(clientPrice < price) return GROUP_SHOP_PRICE_STATUS.NOT_ENOUGH; + return GROUP_SHOP_PRICE_STATUS.OVER; +} \ No newline at end of file diff --git a/game-server/app/services/chatChannelService.ts b/game-server/app/services/chatChannelService.ts index 5ee113ff6..e2e4ed7b5 100644 --- a/game-server/app/services/chatChannelService.ts +++ b/game-server/app/services/chatChannelService.ts @@ -56,6 +56,11 @@ export async function addRoleToWorldAuctionChannel(roleId: string, sid: string, await addRoleToChannel(roomId, roleId, sid); } +export async function addRoleToGroupShopChannel(roleId: string, sid: string) { + const roomId = groupRoomId(CHANNEL_PREFIX.GROUP_SHOP); + await addRoleToChannel(roomId, roleId, sid); +} + async function leaveChannel(roomId: string, roleId: string, sid: string) { const channelSid = await channelServer(roomId); await pinus.app.rpc.chat.chatRemote.leaveChannel.toServer(channelSid, roomId, roleId, sid); @@ -86,6 +91,11 @@ export async function leaveWorldAuctionChannel(roleId: string, sid: string, serv await leaveChannel(roomId, roleId, sid); } +export async function leaveGroupShopChannel(roleId: string, sid: string) { + const roomId = groupRoomId(CHANNEL_PREFIX.GROUP_SHOP); + await leaveChannel(roomId, roleId, sid); +} + export async function leaveGuildChannel(roleId: string, sid: string, guildCode: string) { if (!guildCode) return; const roomId = groupRoomId(CHANNEL_PREFIX.GUILD, guildCode); @@ -122,6 +132,12 @@ export async function getWorldAuctionChannelSid(serverId: number) { return channelSid; } +export async function getGroupShopSid() { + const roomId = groupRoomId(CHANNEL_PREFIX.GROUP_SHOP); + const channelSid = await channelServer(roomId); + return channelSid; +} + async function delChannel(roomId: string) { const channelSid = await channelServer(roomId); await pinus.app.rpc.chat.chatRemote.deleteChannel.toServer(channelSid, roomId); diff --git a/game-server/app/services/chatService.ts b/game-server/app/services/chatService.ts index 72ea99a9d..c7f693e3f 100644 --- a/game-server/app/services/chatService.ts +++ b/game-server/app/services/chatService.ts @@ -38,8 +38,8 @@ export function privateRoomId(roleId: string, targetRoleId: string) { * @param {string} channelId * @returns */ -export function groupRoomId(channel: string, channelId: string | number) { - return `${channel}_${channelId}`; +export function groupRoomId(channel: string, channelId?: string | number) { + return channelId?`${channel}_${channelId}`: `${channel}`; } function msgCounterName(roomId: string) { diff --git a/game-server/app/services/pushService.ts b/game-server/app/services/pushService.ts index 36aabe56f..e5b8e2dd3 100644 --- a/game-server/app/services/pushService.ts +++ b/game-server/app/services/pushService.ts @@ -1,7 +1,7 @@ import { Channel, pinus } from "pinus"; import { CHANNEL_PREFIX, PUSH_BATCH, PUSH_INTERVAL, PUSH_ROUTE, STATUS } from "../consts"; import { genCode, resResult } from "../pubUtils/util"; -import { getCityChannelSid, getGuildChannelSid, getWorldChannelSid, groupRoomId } from "./chatService"; +import { getCityChannelSid, getGuildChannelSid, getWorldChannelSid, groupRoomId, getGroupShopSid } from "./chatService"; import { getAllOnlineRoles, getRoleOnlineInfo } from "./redisService"; import { errlogger, infologger } from '../util/logger'; import { MsgEncrypt } from "../pubUtils/sysUtil"; @@ -64,6 +64,12 @@ export async function sendMessageToCity(cityId: number, route: string, data: any await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, data); } +export async function sendMessageToGroupShopWithSuc(route: string, data: any) { + let channelSid = await getGroupShopSid(); + let roomId = groupRoomId(CHANNEL_PREFIX.GROUP_SHOP); + await pinus.app.rpc.chat.chatRemote.pushMessage.toServer(channelSid, roomId, route, resResult(STATUS.SUCCESS, data)); +} + export async function sendMessageToUserWithSuc(roleId: string, route: string, data: any, sid?: string) { await sendMessageToUser(roleId, route, resResult(STATUS.SUCCESS, data), sid); } diff --git a/shared/consts/constModules/activityConst.ts b/shared/consts/constModules/activityConst.ts index 9f3548b43..b53371951 100644 --- a/shared/consts/constModules/activityConst.ts +++ b/shared/consts/constModules/activityConst.ts @@ -59,6 +59,7 @@ export enum ACTIVITY_TYPE { SHOP = 44, // 限时商店 GUIDE_GACHA = 45, // 500抽 POP_NOTICE = 46, // 打脸公告 + GROUP_SHOP = 49, // 团购 } /** @@ -240,4 +241,10 @@ export enum POP_NOTICE_TIME_SHOW_TYPE { READ_STR = 1, // 读time字段字符串 READ_COUNTDOWN = 2, // 读倒计时 NO = 3, // 不显示 +} + +export enum GROUP_SHOP_PRICE_STATUS { + NOT_ENOUGH = 0, // 客户端的价格不足当前价格 + NORMAL = 1, // 正好 + OVER = 2, // 客户端的价格高于当前价格 } \ No newline at end of file diff --git a/shared/consts/constModules/chatConst.ts b/shared/consts/constModules/chatConst.ts index 5720a1243..21dfaf914 100644 --- a/shared/consts/constModules/chatConst.ts +++ b/shared/consts/constModules/chatConst.ts @@ -21,6 +21,7 @@ export const CHANNEL_PREFIX = { CITY: 'city', // 军团活动,诸侯混战,按城池分channel GUILD_AUCTION: 'g_auction', // 军团拍卖 WORLD_AUCTION: 'w_auction', // 军团拍卖 + GROUP_SHOP: 'groupShop', // 团购页面 } export const getChannelType = function(prefix: string) { @@ -164,4 +165,5 @@ export const PUSH_ROUTE = { LADDER_CHECK_STOP: 'onLadderCheckStop', LADDER_BATTLE_STOP: 'onLadderBattleStop', LADDER_RANK_UPDATE: 'onLadderRankUpdate', + GROUP_SHOP_UPDATE: 'onGroupShopUpdate', } \ No newline at end of file diff --git a/shared/consts/constModules/sysConst.ts b/shared/consts/constModules/sysConst.ts index 23c5b92db..2e5b5b88a 100644 --- a/shared/consts/constModules/sysConst.ts +++ b/shared/consts/constModules/sysConst.ts @@ -1041,6 +1041,7 @@ export enum ITEM_CHANGE_REASON { USE_VOUCHER = 150, // 使用代金券 LADDER_BUY_CNT = 151, // 名将擂台购买次数 LADDER_BATTLE_REWARD = 152, // 名将擂台关卡奖励 + ACT_GROUP_SHOP_BUY = 153, // 团购 } export enum TA_EVENT { diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index ce6e4288a..3aee439c0 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -504,6 +504,11 @@ export const STATUS = { ACTIVITY_POP_UP_MUST_BUY: { code: 50037, simStr: '该礼包必须购买' }, DAILY_COIN_BOX_NOT_FOUND: { code: 50038, simStr: '未找到该宝箱' }, DAILY_COIN_BOX_CANNOT_RECEIVE: {code: 50013, simStr: '该宝箱不可领取' }, + + ACTIVITY_GROUP_SHOP_BUY_CNT_MAX: { code: 50039, simStr: '购买次数超过最大值' }, + ACTIVITY_GROUP_SHOP_ITEM_NOT_FOUND: { code: 50040, simStr: '未找到该商品' }, + ACTIVITY_GROUP_SHOP_PRICE_ERR: { code: 50041, simStr: '提供的折扣未达到该价格' }, + // GM后台相关状态 60000 - 69999 GM_ERR_PASSWORD: { code: 60001, simStr: '账号或密码错误' }, GM_MISS_API: { code: 60002, simStr: '未找到该接口' }, diff --git a/shared/db/ActivityGroupShopRec.ts b/shared/db/ActivityGroupShopRec.ts new file mode 100644 index 000000000..edc309445 --- /dev/null +++ b/shared/db/ActivityGroupShopRec.ts @@ -0,0 +1,80 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; +import { GroupShopDiscount } from '../domain/activityField/groupShopField'; +import { nowSeconds } from '../pubUtils/timeUtil'; + +export class GroupShopRecord { + + @prop({ required: true }) + time: number; // 达成时间 + + @prop({ required: true }) + sum: number; // 达成时的总额 + + @prop({ required: true }) + discountId: number; // 达成时的折扣 + + @prop({ required: true }) + discount: number; // 达成时的折扣 + + @prop({ required: true }) + price: number; // 达成时的价格 + + constructor(curDiscount: GroupShopDiscount) { + this.time = nowSeconds(); + if(curDiscount) { + this.sum = curDiscount.sum; + this.discountId = curDiscount.id; + this.discount = curDiscount.discount; + this.price = curDiscount.price; + } + } +} + +/** + * 活动系统 - 团购总记录 +*/ +@index({ activityId: 1 }) + +export default class Activity_Group_Shop_Rec extends BaseModel { + + @prop({ required: true }) + activityId: number; // 活动Id + + @prop({ required: true }) + id: number; // item 唯一id + + @prop({ required: true }) + gid: number; // 物品id + + @prop({ required: true }) + sum: number; // 总购买次数 + + @prop({ required: true, type: GroupShopRecord, _id: false }) + records: GroupShopRecord[]; // 记录 + + + public static async findByActivity(activityId: number) { + let result: ActivityGroupShopRecType[] = await ActivityGroupShopRecModel.find({ activityId }).lean(); + return result; + } + + public static async incBuyCnt(activityId: number, id: number, gid: number, inc: number) { + let result: ActivityGroupShopRecType = await ActivityGroupShopRecModel.findOneAndUpdate( + { activityId, id }, { $inc: { sum: inc }, $set: { gid } }, { new: true, upsert: true } + ).lean(); + return result; + } + + public static async addRecord(activityId: number, id: number, record: GroupShopRecord) { + let result: ActivityGroupShopRecType = await ActivityGroupShopRecModel.findOneAndUpdate( + { activityId, id }, { $push: { records: record } }, { new: true, upsert: true } + ).lean(); + return result; + } +} + +export const ActivityGroupShopRecModel = getModelForClass(Activity_Group_Shop_Rec); + +export interface ActivityGroupShopRecType extends Pick, keyof Activity_Group_Shop_Rec> { } +export type ActivityGroupShopRecTypeParam = Partial; // 将所有字段变成可选项 \ No newline at end of file diff --git a/shared/db/ActivityGroupShopUserRec.ts b/shared/db/ActivityGroupShopUserRec.ts new file mode 100644 index 000000000..8d0d42227 --- /dev/null +++ b/shared/db/ActivityGroupShopUserRec.ts @@ -0,0 +1,86 @@ +import BaseModel from './BaseModel'; +import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose'; +import { nowSeconds } from '../pubUtils/timeUtil'; +import { GroupShopDiscount } from '../domain/activityField/groupShopField'; + +/** + * 活动系统 - 团购玩家记录 +*/ +@index({ activityId: 1 }) +@index({ activityId: 1, roleId: 1 }) +@index({ activityId: 1, roleId: 1, id: 1, discountId: 1 }) + +export class GroupShopBuyRecord { + + @prop({ required: true }) + time: number; // 购买时间 + + @prop({ required: true }) + sum: number; // 达成时的总额 + + @prop({ required: true }) + discountId: number; // 达成时的折扣 + + @prop({ required: true }) + discount: number; // 达成时的折扣 + + @prop({ required: true }) + price: number; // 达成时的价格 + + @prop({ required: true }) + buyCnt: number; // 购买次数 + + @prop({ required: true }) + refundPrice: number; // 退费价格 + + constructor(curDiscount: GroupShopDiscount, buyCnt: number) { + this.time = nowSeconds(); + if(curDiscount) { + this.sum = curDiscount.sum; + this.discountId = curDiscount.id; + this.discount = curDiscount.discount; + this.price = curDiscount.price; + } + this.buyCnt = buyCnt; + this.refundPrice = 0; + } +} + +export default class Activity_Group_Shop_User_Rec extends BaseModel { + + @prop({ required: true }) + activityId: number; // 活动Id + + @prop({ required: true }) + roleId: string; // 玩家Id + + @prop({ required: true }) + id: number; // 唯一id + + @prop({ required: true }) + gid: number; // 物品id + + @prop({ required: true }) + buyCnt: number; // 购买次数 + + @prop({ required: true, type: GroupShopBuyRecord, _id: false }) + records: GroupShopBuyRecord[]; // 购买次数 + + public static async findByActivityAndRoleId(activityId: number, roleId: string) { + let result: ActivityGroupShopUserRecType[] = await ActivityGroupShopUserRecModel.find({ roleId, activityId }).lean(); + return result; + } + + public static async incBuyCnt(activityId: number, roleId: string, id: number, gid: number, inc: number, record: GroupShopBuyRecord) { + let result: ActivityGroupShopUserRecType = await ActivityGroupShopUserRecModel.findOneAndUpdate( + { roleId, activityId, id }, { $inc: { buyCnt: inc }, $setOnInsert: { gid }, $push: { records: record } }, { new: true, upsert: true } + ).lean(); + return result; + } + +} + +export const ActivityGroupShopUserRecModel = getModelForClass(Activity_Group_Shop_User_Rec); + +export interface ActivityGroupShopUserRecType extends Pick, keyof Activity_Group_Shop_User_Rec> { } +export type ActivityGroupShopUserRecTypeParam = Partial; // 将所有字段变成可选项 \ No newline at end of file diff --git a/shared/domain/activityField/groupShopField.ts b/shared/domain/activityField/groupShopField.ts new file mode 100644 index 000000000..894141c3e --- /dev/null +++ b/shared/domain/activityField/groupShopField.ts @@ -0,0 +1,174 @@ +import { ActivityModelType } from '../../db/Activity'; +import { ActivityGroupShopRecType } from '../../db/ActivityGroupShopRec'; +import { ActivityGroupShopUserRecType } from '../../db/ActivityGroupShopUserRec'; +import { ActivityBase } from './activityField'; + +// 数据库 +interface GroupShopTimerInDb { + time: number; // 活动开始之后的时间 + sum: number; // 如果次数不足sum次则强行设成sum次 +} + +interface GroupShopDiscountInDb { + id: number; // 折扣id + sum: number; // 累计购买次数 + discount: number; // 显示折扣 + price: number; // 真实价格 +} + +interface GroupShopItemInDb { + id: number; // 唯一id + gid: number; // 物品id + count: number; // 一次购买能购买多少 + max: number; // 单人可以购买多少次 + price: number; // 无折扣单价 + discount: GroupShopDiscountInDb[]; + timers: GroupShopTimerInDb[]; // 定时器 +} + +interface GroupShopInDb { + items: GroupShopItemInDb[]; +} + +// 数据 +class GroupShopTimer { + time: number; // 活动开始之后的时间 + itemId: number; // items唯一id + sum: number; // 如果次数不足sum次则强行设成sum次 + + constructor(id: number, data: GroupShopTimerInDb) { + this.time = data.time; + this.sum = data.sum; + this.itemId = id; + } +} + +export class GroupShopDiscount { + id: number = 0; // 折扣唯一id + sum: number = 0; // 累计购买次数 + discount: number = 0; // 显示折扣 + price: number = 0; // 真实价格 + + constructor(price: number, data?: GroupShopDiscountInDb) { + if(data) { + this.id = data.id; + this.sum = data.sum; + this.discount = data.discount; + this.price = data.price; + } else { + this.price = price; + } + } +} + +class GroupShopItem { + id: number; // 唯一id + gid: number; // 物品id + count: number; // 一次购买能购买多少 + max: number; // 单人可以购买多少次 + price: number; // 无折扣单价 + discount: GroupShopDiscount[] = []; + sum: number = 0; // 总价格 + curDiscount: GroupShopDiscount; + hasBoughtCnt: number = 0; // 玩家购买次数 + + constructor(item: GroupShopItemInDb) { + this.id = item.id; + this.gid = item.gid; + this.count = item.count; + this.max = item.max; + this.price = item.price; + if(item.discount && item.discount.length > 0) { + for(let discount of item.discount) { + this.discount.push(new GroupShopDiscount(item.price, discount)); + } + } + } + + setSum(sum: number) { + this.sum = sum; + this.checkDiscountBySum(sum); + } + + checkDiscountBySum(sum: number) { + for(let obj of this.discount) { + if(obj.sum > sum) break; + this.curDiscount = new GroupShopDiscount(this.price, obj); + } + } + + setPlayerCnt(cnt: number) { + this.hasBoughtCnt += cnt; + } + + checkBuyCnt(buyCnt: number) { + return this.hasBoughtCnt + buyCnt <= this.max; + } + + getCurDiscount() { + return this.curDiscount? this.curDiscount: new GroupShopDiscount(this.price); + } +} + +// 团购活动数据 +export class GroupShopData extends ActivityBase { + items: GroupShopItem[] = []; + timer: GroupShopTimer[] = []; + private itemMap: Map = new Map(); // id => index + + constructor(activityData: ActivityModelType, createTime: number, serverTime: number) { + super(activityData, createTime, serverTime); + this.initData(activityData.data) + } + + public initData(data: string) { + let dataObj: GroupShopInDb = JSON.parse(data); + if(!dataObj.items || dataObj.items.length <= 0) return; + + for(let item of dataObj.items) { + this.items.push(new GroupShopItem(item)); + this.itemMap.set(item.id, this.items.length - 1); + if(item.timers && item.timers.length > 0) { + for(let timer of item.timers) { + this.timer.push(new GroupShopTimer(item.id, timer)); + } + } + } + } + + public findItemById(id: number) { + let index = this.itemMap.get(id); + return this.items[index]; + } + + public setRecords(data: ActivityGroupShopRecType[]) { + for(let { id, sum } of data) { + let item = this.findItemById(id); + if(item) item.setSum(sum); + } + } + + public incAllRecord(data: ActivityGroupShopRecType) { + if(!data) return false; + let item = this.findItemById(data.id); + let oldDiscountId = item.getCurDiscount().id; + item.setSum(data.sum); + let newDiscountId = item.getCurDiscount().id; + return oldDiscountId != newDiscountId; + } + + + public setPlayerRecord(data: ActivityGroupShopUserRecType[]) { + for(let { id, buyCnt } of data) { + let item = this.findItemById(id); + if(item) item.setPlayerCnt(buyCnt); + } + } + public getShowResult() { + return { + ...this.getBaseKeys(), + items: this.items, + } + } + +} \ 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 f4582f534..ae5a5a13f 100644 --- a/shared/resource/jsons/dic_zyz_activityType.json +++ b/shared/resource/jsons/dic_zyz_activityType.json @@ -250,5 +250,11 @@ "activityType": 46, "name": "POP_NOTICE", "string": "打脸公告" + }, + { + "id": 49, + "activityType": 49, + "name": "GROUP_SHOP", + "string": "团购" } ] \ No newline at end of file diff --git a/shared/resource/jsons/server_const.json b/shared/resource/jsons/server_const.json index e9d1ce6c6..8a7d9bb03 100644 --- a/shared/resource/jsons/server_const.json +++ b/shared/resource/jsons/server_const.json @@ -33,6 +33,6 @@ "DEBUG_TIME": 1, "CHECK_WORD": 1, "CAN_PAY": 1, - "SKIP_ENCODE": 0, + "SKIP_ENCODE": 1, "NEED_REBATE": 0 } \ No newline at end of file