后台:更新开服邮件

This commit is contained in:
luying
2021-12-07 10:34:52 +08:00
parent d33eb67429
commit 103314a8bf
18 changed files with 5902 additions and 218 deletions

View File

@@ -7,7 +7,7 @@ import { STATUS } from '../../../consts/statusCode';
import { GMMailModel } from '../../../db/GMMail';
import { delGuildActivityRank, getRoleOnlineInfo } from '../../../services/redisService';
import { SendMailFun } from '../../../services/mailService';
import { GM_MAIL_STATUS, GM_MAIL_TYPE, MAIL_TIME_TYPE } from '../../../consts';
import { GM_MAIL_STATUS, GM_MAIL_TYPE, MAIL_TIME_TYPE, REF_CIRCLE_MAIL_TIME } from '../../../consts';
import { RewardInter } from '../../../pubUtils/interface';
import { MarqueeModel } from '../../../db/Marquee';
import { ServerlistModel } from '../../../db/Serverlist';
@@ -21,7 +21,6 @@ import { ActivityGroupTypeModel } from '../../../db/ActivityGroupType';
import { GuildActivityCityModel } from '../../../db/GuildActivityCity';
import { GuildActivityRecordModel } from '../../../db/GuildActivityRec';
import { getTimeFunM, nowSeconds } from '../../../pubUtils/timeUtil';
import { sendUngotDividend } from '../../../services/auctionService';
import moment = require('moment');
let timer: NodeJS.Timer;
export default function (app: Application) {
@@ -46,7 +45,7 @@ export class GmHandler {
let needSend = false;
if(isPass) {
if(timeType == MAIL_TIME_TYPE.CIRCLE) {
let refTime = moment(moment().format('YYYY-MM-DD 03:00:00')).unix();
let refTime = moment(moment().format(`YYYY-MM-DD ${REF_CIRCLE_MAIL_TIME}:00:00`)).unix();
let sendTime = moment(moment().format('YYYY-MM-DD '+circleHour)).unix();
if(sendTime < refTime) sendTime += 86400;
let now = nowSeconds();

View File

@@ -2,8 +2,13 @@ import { Application, BackendSession, pinus } from 'pinus';
import { getRandSingleEelm, resResult } from '../../../pubUtils/util';
import { STATUS } from '../../../consts/statusCode';
import moment = require('moment');
import { UpdateRegionParams } from '../../../domain/backEndField/params';
import { CreateServerParam, UpdateRegionParams } from '../../../domain/backEndField/params';
import { RegionModel } from '../../../db/Region';
import { gameData } from '../../../pubUtils/data';
import { ServerlistModel } from '../../../db/Serverlist';
import { nowSeconds } from '../../../pubUtils/timeUtil';
import { GM_MAIL_TYPE, MAIL_TIME_TYPE, REF_CIRCLE_MAIL_TIME } from '../../../consts';
import { SendMailFun } from '../../../services/mailService';
let timer: NodeJS.Timer;
export default function (app: Application) {
return new GmHandler(app);
@@ -17,12 +22,50 @@ export class GmHandler {
let params = new UpdateRegionParams(msg);
let uid = session.get('uid');
if(!params.checkParams()) return resResult(STATUS.WRONG_PARMS);
let update = params.getUpdateParam();
if(params.id == 'new') {
let update = params.getUpdateParam();
await RegionModel.createNewRegion(update, uid);
} else {
let oldRegion = await RegionModel.findRegionById(params.id);
if(!oldRegion) return resResult(STATUS.WRONG_PARMS);
let update = params.getUpdateParam(oldRegion);
await RegionModel.updateRegion(params.id, update, uid);
}
return resResult(STATUS.SUCCESS);
}
async createNewServer(msg: CreateServerParam, session: BackendSession) {
let params = new CreateServerParam(msg);
let uid = session.get('uid');
if(!params.checkParams()) return resResult(STATUS.WRONG_PARMS);
let curRegion = await RegionModel.findRegionByEnv(params.env);
if(!curRegion) return resResult(STATUS.WRONG_PARMS);
let { latestServer = 0 } = curRegion;
let dicServerName = gameData.serverNames.get(latestServer + 1);
if(!dicServerName) return resResult(STATUS.DIC_DATA_NOT_FOUND);
let newServer = await ServerlistModel.newServer(params, curRegion, dicServerName, uid);
let mails = [ params.openMail, params.circleMail ];
for(let mail of mails) {
let needSend = false;
if(mail.timeType == MAIL_TIME_TYPE.CIRCLE) {
let refTime = moment(moment().format(`YYYY-MM-DD ${REF_CIRCLE_MAIL_TIME}:00:00`)).unix();
let sendTime = moment(moment().format('YYYY-MM-DD '+ mail.circleHour)).unix();
if(sendTime < refTime) sendTime += 86400;
let now = nowSeconds();
if(refTime < now && sendTime > now) {
needSend = true;
}
} else {
needSend = true;
}
if(needSend) {
let f = new SendMailFun();
await f.setWithGmMail(mail);
await f.sendToServer([newServer.id]);
}
}
return resResult(STATUS.SUCCESS);
}
}

View File

@@ -57,16 +57,14 @@ export async function setMedianCe() {
let servers = await ServerlistModel.getAllServerList();
for (let server of servers) {
if (server.serverType == 'official') {
let medianRole = await RoleModel.getMedianRole(server.id);
if (!medianRole) {
await ServerlistModel.updateByServerId(server.id, { medianCe: GUILDACTIVITY.GATEACTIVITY_ENEMYCE });
} else {
let { topLineup } = medianRole;
let topHero = topLineup.sort((a, b) => b.ce - a.ce);
let medianCe = reduceCe(topHero[0].ce);
await ServerlistModel.updateByServerId(server.id, { medianCe });
}
let medianRole = await RoleModel.getMedianRole(server.id);
if (!medianRole) {
await ServerlistModel.updateByServerId(server.id, { medianCe: GUILDACTIVITY.GATEACTIVITY_ENEMYCE });
} else {
let { topLineup } = medianRole;
let topHero = topLineup.sort((a, b) => b.ce - a.ce);
let medianCe = reduceCe(topHero[0].ce);
await ServerlistModel.updateByServerId(server.id, { medianCe });
}
}
return servers;

View File

@@ -10,7 +10,7 @@ import { STATUS } from '../consts/statusCode';
import { resResult } from '../pubUtils/util';
import { GM_MAIL_TYPE, ITID, MAIL_STATUS, MAIL_TIME_TYPE, MAIL_TYPE, SEND_NAME, SEND_TITLE } from "../consts";
import { MailParam } from '../domain/roleField/mail';
import { GMMailType, GMMailModel } from "../db/GMMail";
import { GMMailType, GMMailModel, GMMailTypeParam } from "../db/GMMail";
import { getGuildChannelSid, getWorldChannelSid } from "./chatChannelService";
import { GMMailRecordModel } from "../db/GMMailRecord";
import { BAG } from "../pubUtils/dicParam";
@@ -77,7 +77,7 @@ export class SendMailFun {
private sendName: string = SEND_NAME;
private title: string = SEND_TITLE;
private content: string = '';
private gmmail: GMMailType;
private gmmail: GMMailTypeParam;
private hasGoods: boolean = false; // 是否内含奖励
private goods: RewardInter[] = []; // 发送的奖励
private sendTime: number;
@@ -109,7 +109,7 @@ export class SendMailFun {
}
// 从GMMail表读取数据
public async setWithGmMail(gmmail: GMMailType) {
public async setWithGmMail(gmmail: GMMailTypeParam) {
this.gmmail = gmmail;
this.contentId = 0;
if(gmmail.timeType == MAIL_TIME_TYPE.IMMEDIATE) {

View File

@@ -21,6 +21,7 @@ export const TEEN_DAILY_MAX_TIME = 1.5 * 60 * 60; // 未成年人工作日每天
export const GUEST_DAY = 15; // 同一设备15天内不得重复体验游客模式
export const REFRESH_TIME = 5; // 统一一天刷新时间
export const REF_CIRCLE_MAIL_TIME = 3; // 统一一天刷新定期邮件时间
export const PUSH_BATCH = 100; // 推送分批人数
export const PUSH_INTERVAL = 5 * 1000; // 分批时间5秒一批
export enum TIME_OUTPUT_TYPE {

View File

@@ -1,5 +1,5 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType } from '@typegoose/typegoose';
import { index, getModelForClass, prop, DocumentType, ReturnModelType, mongoose } from '@typegoose/typegoose';
/**
* 自增 ID

40
shared/db/CounterAll.ts Normal file
View File

@@ -0,0 +1,40 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, ReturnModelType, mongoose } from '@typegoose/typegoose';
/**
* 自增 ID
*/
@index({ name: 1 })
export default class CounterAll extends BaseModel {
@prop({ required: true })
name: string;
@prop({ required: true, default: 1 })
seq: number;
public static async getNewCounter(param:{name: string, def: number}, lean = true) {
let {name, def:defaultVal} = param;
let counter: CounterType = await CounterAllModal.findOneAndUpdate({ name }, { $inc: { seq: 1 } }, { new: true, upsert: true }).lean(lean);
if(!counter || (counter&&counter.seq == 1) && defaultVal != 1) {
counter = await CounterAllModal.findOneAndUpdate({ name }, { $set: { seq: defaultVal } }, { new: true, upsert: true }).lean(lean);
}
return counter?.seq;
}
public static async getCounter(param:{name: string, def: number}, lean = true) {
let {name, def:defaultVal} = param;
let counter: CounterType = await CounterAllModal.findOne({ name }).lean(lean);
return counter?.seq||defaultVal;
}
}
export let CounterAllModal: ReturnModelType<typeof CounterAll, {}>;
export function loadCounterModal(connect: mongoose.Connection) {
CounterAllModal = getModelForClass(CounterAll, {
existingConnection: connect
});
}
export interface CounterType extends Pick<DocumentType<CounterAll>, keyof CounterAll>{};

View File

@@ -31,15 +31,14 @@ export default class Notice extends BaseModel {
showStartTime: Date;
@prop({ required: true, select: false })
showEndTime: Date;
@prop({ required: true, select: false })
serverType: string; // 服务器类型
@prop({ required: true, select: false })
isEnable: boolean;
public static async getAllNotice(serverType: string) {
public static async getAllNotice() {
let curTime = new Date();
let notices: NoticeType[] = await NoticeModel.find({ showStartTime: { $lte: curTime }, showEndTime: { $gte: curTime }, isEnable: true, serverType })
let notices: NoticeType[] = await NoticeModel.find({ showStartTime: { $lte: curTime }, showEndTime: { $gte: curTime }, isEnable: true })
.sort({ sort: -1, createTime: -1 })
.lean({ virtuals: true });
return notices;
@@ -77,7 +76,7 @@ export default class Notice extends BaseModel {
sort[sortField] = -1;
}
}
const result: NoticeType[] = await NoticeModel.find(searchObj).limit(pageSize).skip((page - 1) * pageSize).sort(sort).select('+sort +showStartTime +showEndTime +serverType +isEnable').lean({ getters: true, virtuals: true });
const result: NoticeType[] = await NoticeModel.find(searchObj).limit(pageSize).skip((page - 1) * pageSize).sort(sort).select('+sort +showStartTime +showEndTime +isEnable').lean({ getters: true, virtuals: true });
return result;
}

View File

@@ -30,7 +30,7 @@ export default class Region extends BaseModel {
gameHost: string; // 长链接地址
@prop({ required: true })
gamePort: number; // 长链接地址
gmPort: number; // 长链接地址
@prop({ required: true })
latestServer: number; // 最新服
@@ -57,12 +57,17 @@ export default class Region extends BaseModel {
}
public static async getAllRegion() {
const rec: RegionType[] = await RegionModel.find().select('-_id -stategty').lean();
const rec: RegionType[] = await RegionModel.find().select('-_id -stategy').lean();
return rec;
}
public static async findRegionById(id: number) {
const rec: RegionType = await RegionModel.findOne({ id }).lean();
const rec: RegionType = await RegionModel.findOne({ id }).select('-_id').lean();
return rec;
}
public static async findRegionByEnv(env: string) {
const rec: RegionType = await RegionModel.findOne({ env }).select('-_id').lean();
return rec;
}
}

View File

@@ -21,11 +21,13 @@ export default class ServerStategy {
@prop({ required: true, default: 0 })
stopRegisterTime: number; // 关闭注册时间
constructor(stategy: ServerStategyUpdate) {
constructor(stategy: ServerStategyUpdate & { hasOpenMail: boolean, hasCircleMail: boolean}) {
this.maxPlayerCnt = stategy.maxPlayerCnt;
this.timers = stategy.timers;
this.activityGroupId = stategy.activityGroupId;
this.stopRegisterTime = stategy.stopRegisterTime;
if(stategy.hasCircleMail) this.circleMail = stategy.circleMail;
if(stategy.hasOpenMail) this.openMail = stategy.openMail;
}
}
export interface ServerStategyType extends Pick<DocumentType<ServerStategy>, keyof ServerStategy> { };

View File

@@ -1,9 +1,10 @@
import BaseModel from './BaseModel';
import { index, getModelForClass, prop, DocumentType, modelOptions, ReturnModelType, mongoose } from '@typegoose/typegoose';
import { GameModel } from './Game';
import { CounterModel } from './Counter';
import { CounterAllModal } from './CounterAll';
import { COUNTER, SERVER_STATUS } from '../consts';
import { getServerName, getServerGroupName } from '../pubUtils/data';
import { CreateServerParam } from '../domain/backEndField/params';
import { RegionType } from './Region';
import { DicServerName } from '../pubUtils/dictionary/DicServerName';
/**
* 游戏字段接口
@@ -12,9 +13,6 @@ import { getServerName, getServerGroupName } from '../pubUtils/data';
@modelOptions({ schemaOptions: { id: false } })
export default class Serverlist extends BaseModel {
@prop({ required: true, default: 1 })
gameId: number; // 游戏id Game表的id
@prop({ required: true, default: 1 })
regionId: number; // 大区id
@@ -22,7 +20,7 @@ export default class Serverlist extends BaseModel {
env: string; // 环境变量
@prop({ required: true })
serverType: string;
prefix: string; // 前缀
@prop({ required: true })
id: number; // 小区id 自增
@@ -39,12 +37,6 @@ export default class Serverlist extends BaseModel {
@prop({ required: true })
groupName: string; // 战区区名
@prop({ required: true })
host: string; // pinus连接地址
@prop({ required: false, default: 3014 })
port: number; // pinus端口
@prop({ required: true, default: 1, enum: SERVER_STATUS })
serverStatus: number; // 服务器状态
@@ -63,14 +55,20 @@ export default class Serverlist extends BaseModel {
@prop({ required: true })
openTime: Date;
@prop({ required: true })
stopRegisterTime: Date;
@prop({ required: true, default: true })
canRegister: boolean;
@prop({ required: true, default: 0 })
maxPlayerCnt: number; // 最大玩家人数
playerCnt: number; // 当前玩家人数
@prop({ required: true, default: 0 })
medianCe: number; // 中位数武将战力、缩小10000倍后的结果
public static async getAllServerList() {
let id = await CounterModel.getCounter(COUNTER.SERVER);
let id = await CounterAllModal.getCounter(COUNTER.SERVER);
let result: ServerlistType[] = [];
let n = Math.ceil(id/1000);
for(let i = 0; i < n; i++) {
@@ -105,28 +103,22 @@ export default class Serverlist extends BaseModel {
return server;
}
public static async newServer(params: { serverType: string, openTime: Date, name?: string }, stategy: any, uid = 1 ) {
let { serverType, name } = params;
let serverEnvs = await GameModel.getServerEnvList();
let curEnv = serverEnvs.find(cur => cur.serverType == serverType);
if(!curEnv) return false;
let { gameHost: host } = curEnv;
public static async newServer(params: CreateServerParam, region: RegionType, dicServerName: DicServerName, uid = 1 ) {
let { prefix, id: regionId, env } = region;
// 分大区
let groupId = await CounterModel.getCounter(COUNTER.SERVER_GROUP);
let groupServerCount = await ServerlistModel.countByCondition({ serverType, groupId });
if(groupServerCount > 10) {
groupId = await CounterModel.getNewCounter(COUNTER.SERVER_GROUP);
}
let groupName = getServerGroupName(groupId)||"";
let serverId = await CounterModel.getNewCounter({ name: `${COUNTER.SERVER_BY_TYPE.name}_${serverType}`, def: COUNTER.SERVER_BY_TYPE.def });
let id = await CounterModel.getNewCounter(COUNTER.SERVER);
if(!name) name = getServerName(id)||"";
let id = await CounterAllModal.getNewCounter(COUNTER.SERVER);
let { openTime: openTimeNum, stopRegisterTime: hour, activityGroupId } = params;
let { id: serverId, sname: name, groupId, groupName } = dicServerName;
let openTime = new Date(openTimeNum * 1000);
let stopRegisterTime = new Date(openTimeNum + hour * 60 * 60);
const doc = new ServerlistModel();
const update = Object.assign(doc.toJSON(), params, { id, serverId, host, groupId, groupName, name, createdBy: uid, updatedBy: uid }, { activityGroupId: stategy.activityGroupId, maxPlayerCnt: stategy.maxPlayerCnt});
const update = Object.assign(doc.toJSON(), {
id, regionId, env, prefix,
serverId, name, groupId, groupName, activityGroupId,
openTime, stopRegisterTime,
createdBy: uid, updatedBy: uid
});
let server: ServerlistType = await ServerlistModel.findOneAndUpdate({ id }, { $setOnInsert: update }, { new: true, upsert: true }).lean({ getters: true, virtuals: true });
return server;

View File

@@ -7,6 +7,7 @@ import { loadGMUserGroupModel } from "./GMUserGroup";
import { loadRegionModel } from "./Region";
import { loadServerlistModel } from "./Serverlist";
import { loadGMMailModel } from './GMMail';
import { loadCounterModal } from "./CounterAll";
export function loadGmDb(connect: mongoose.Connection) {
loadApiModel(connect);
@@ -17,4 +18,5 @@ export function loadGmDb(connect: mongoose.Connection) {
loadRegionModel(connect);
loadServerlistModel(connect);
loadGMMailModel(connect);
loadCounterModal(connect);
}

View File

@@ -2,6 +2,7 @@ import { GM_MAIL_TYPE, MAIL_TIME_TYPE, SERVER_TIMER } from "../../consts";
import { isArray } from 'underscore';
import GMMail from "../../db/GMMail";
import ServerStategy from "../../db/ServerStategy";
import { RegionType } from "../../db/Region";
export class UpdateMailParams {
hasGoods: boolean = false; // 是否有道具
@@ -79,6 +80,9 @@ export class UpdateRegionParams {
circleMail?: GMMail;
stopRegisterTime: number = 0;
hasOpenMail: boolean = false;
hasCircleMail: boolean = false;
constructor(obj: UpdateRegionParams) {
for(let key in obj) {
this[key] = obj[key];
@@ -92,13 +96,45 @@ export class UpdateRegionParams {
return true;
}
getUpdateParam() {
let stategy = new ServerStategy(this);
return {
name: this.name,
prefix: this.prefix,
remark: this.remark,
stategy
getUpdateParam(oldRegion?: RegionType) {
if(!oldRegion) {
let stategy = new ServerStategy(this);
return {
name: this.name,
prefix: this.prefix,
remark: this.remark,
stategy
}
} else {
let stategy = new ServerStategy(this);
return {
name: this.name||oldRegion.name,
prefix: this.prefix||oldRegion.prefix,
remark: this.remark||oldRegion.remark,
stategy: { ...(oldRegion.stategy||{}), ...stategy }
}
}
}
}
export class CreateServerParam {
env: string = '';
openTime: number = 0;
activityGroupId: number[] = [];
openMail?: GMMail;
circleMail?: GMMail;
stopRegisterTime: number = 0;
constructor(obj: CreateServerParam) {
for(let key in obj) {
this[key] = obj[key];
}
}
checkParams() {
if(!this.env || !this.openTime || !this.stopRegisterTime || !isArray(this.activityGroupId) || this.activityGroupId.length <= 0 ) {
return false
}
return true;
}
}

View File

@@ -7,22 +7,18 @@ export class ServerParam {
serverId: number; // 显示的区号
serverStr: string; // 显示的区号 S1
name: string; // 区名
host: string; // pinus地址
port: number; // pinus端口
host: string = ''; // pinus地址
port: number = 0; // pinus端口
status: number; // 状态
openTime: number; // 开服时间
serverType: string; // 分区类型 官服 测试服 开发服
constructor(server: ServerlistType) {
this.id = server.id;
this.serverId = server.serverId;
this.serverStr = `S${server.serverId}`;
this.name = server.name;
this.host = server.host;
this.port = server.port;
this.status = server.status;
this.openTime = getSeconds(server.openTime);
this.serverType = server.serverType;
}
}

View File

@@ -83,7 +83,7 @@ import { dicRecruit, loadRecruit } from './dictionary/DicRecruit';
import { loadRMB, dicRMB } from './dictionary/DicRMB';
import { dicActivityType, loadActivityType } from './dictionary/DicActivityType';
import { DicTaskType, dicTaskTypeDesc, loadTaskType } from './dictionary/DicTaskType';
import { dicServerName, dicServerGroupName, loadServerName } from "./dictionary/DicServerName";
import { dicServerName, loadServerName } from "./dictionary/DicServerName";
import { dicAp, loadAp, dicApMaxLevel } from './dictionary/DicAp';
import { dicApBuy, dicApMaxBuyTimes, loadApBuy } from "./dictionary/DicApBuy";
import { dicKingExpRatio, loadKingExpRatio } from './dictionary/DicKingExpRatio';
@@ -224,7 +224,6 @@ export const gameData = {
activityType: dicActivityType,
taskTypeDesc: dicTaskTypeDesc,
serverNames: dicServerName,
serverGroupNames: dicServerGroupName,
ap: dicAp,
apMaxLevel: dicApMaxLevel,
apBuy: dicApBuy,
@@ -718,22 +717,6 @@ function getCeRatio() {
});
}
// 根据groupId获得当前大区名
export function getServerGroupName(groupId: number) {
let name = gameData.serverGroupNames.get(groupId);
if(!name) {
let maxId = 0;
gameData.serverGroupNames.forEach((gname, id) => {
if(id > maxId) {
maxId = id;
name = gname;
}
})
}
return name;
}
// 根据服务器id获得当前大区名
export function getServerName(id: number) {
let name = gameData.serverNames.get(id);

View File

@@ -1,4 +1,4 @@
// 武将特技表
// 服务器名
import { readFileAndParse } from '../util'
import { FILENAME } from '../../consts'
@@ -6,32 +6,21 @@ export interface DicServerName {
// id
readonly id: number;
// 小区名
readonly name: string;
readonly sname: string;
// 大区id
readonly groupId: number;
// 大区名
readonly groupName: string;
}
export const dicServerName = new Map<number, string>();
export const dicServerGroupName = new Map<number, string>();
export const dicServerName = new Map<number, DicServerName>();
export function loadServerName() {
dicServerName.clear();
dicServerGroupName.clear();
{
let arr = readFileAndParse(FILENAME.DIC_SERVER_NAME);
let arr = readFileAndParse(FILENAME.DIC_SERVER_NAME);
arr.forEach(o => {
let { id, sname } = o;
dicServerName.set(id, sname);
});
arr = undefined;
}
{
let arr = readFileAndParse(FILENAME.DIC_SERVER_GROUP_NAME);
arr.forEach(o => {
let { id, groupName } = o;
dicServerGroupName.set(id, groupName);
});
arr = undefined;
}
arr.forEach(o => {
dicServerName.set(o.id, o);
});
arr = undefined;
}

File diff suppressed because it is too large Load Diff

View File

@@ -80,9 +80,8 @@ export default class GameController extends Controller {
public async getnotice() {
const { ctx } = this;
let { serverType } = ctx.request.body;
let notice = await NoticeModel.getAllNotice(serverType);
let notice = await NoticeModel.getAllNotice();
let result = notice.map(cur => {
let { id, title, tag, type, content, time } = cur;
return {