✨ feat(活动): 节日活动高级签到邮件补发
This commit is contained in:
@@ -161,6 +161,10 @@ export class GmHandler {
|
|||||||
if(groupShops.length > 0) {
|
if(groupShops.length > 0) {
|
||||||
pinus.app.rpc.systimer.systimerRemote.initSumSchedule.broadcast();
|
pinus.app.rpc.systimer.systimerRemote.initSumSchedule.broadcast();
|
||||||
}
|
}
|
||||||
|
let signIns = activities.filter(cur => cur.type == ACTIVITY_TYPE.COMMON_SIGN_IN);
|
||||||
|
if(signIns.length > 0) {
|
||||||
|
pinus.app.rpc.systimer.systimerRemote.initVipSignInMailSchedule.broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
return resResult(STATUS.SUCCESS, {
|
return resResult(STATUS.SUCCESS, {
|
||||||
activity: activities
|
activity: activities
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Application, ChannelService } from 'pinus';
|
import { Application, ChannelService } from 'pinus';
|
||||||
import { guildActivityStart, gateActivityEnd, cityActivityEnd, raceActivityEnd, guildActivitySchedule, auctionSchedule, initMaintenance, stopMaintenance, addMailsToSchedule, updateTimeLimitRank, setLadderCountDown, cancelLadderCountDown, initSumSchedule, setPvpSeasonSchedule, initGVGConfigSchedule, gvgBattleStartSchedule, gvgBattleEndSchedule, initHiddenDataSchedule } from '../../../services/timeTaskService';
|
import { guildActivityStart, gateActivityEnd, cityActivityEnd, raceActivityEnd, guildActivitySchedule, auctionSchedule, initMaintenance, stopMaintenance, addMailsToSchedule, updateTimeLimitRank, setLadderCountDown, cancelLadderCountDown, initSumSchedule, setPvpSeasonSchedule, initGVGConfigSchedule, gvgBattleStartSchedule, gvgBattleEndSchedule, initHiddenDataSchedule, initVipSignInMailSchedule } from '../../../services/timeTaskService';
|
||||||
import PvpDefenseType from '../../../db/PvpDefense';
|
import PvpDefenseType from '../../../db/PvpDefense';
|
||||||
import { DicGuildActivity } from '../../../pubUtils/dictionary/DicGuildActivity';
|
import { DicGuildActivity } from '../../../pubUtils/dictionary/DicGuildActivity';
|
||||||
import { gameData, reloadResources } from '../../../pubUtils/data';
|
import { gameData, reloadResources } from '../../../pubUtils/data';
|
||||||
@@ -302,6 +302,14 @@ export class SystimerRemote {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async initVipSignInMailSchedule() {
|
||||||
|
try {
|
||||||
|
await initVipSignInMailSchedule();
|
||||||
|
} catch(e) {
|
||||||
|
errlogger.error(`remote ${__filename} \n ${e.stack}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async fun() {
|
public async fun() {
|
||||||
try {
|
try {
|
||||||
console.log('预留一个函数,用于之后线上维护时需要使用');
|
console.log('预留一个函数,用于之后线上维护时需要使用');
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import moment = require('moment');
|
import moment = require('moment');
|
||||||
import { ACTIVITY_TYPE, SERVER_OPEN_TIME, SIGNIN_VIP_OPEN_LIMIT, STATUS } from '../../consts';
|
import { ACTIVITY_TYPE, MAIL_TYPE, SERVER_OPEN_TIME, SIGNIN_VIP_OPEN_LIMIT, STATUS } from '../../consts';
|
||||||
import { ActivityModelType } from '../../db/Activity';
|
import { ActivityModelType } from '../../db/Activity';
|
||||||
import { ActivitySignInModel, ActivitySignInModelType } from '../../db/ActivitySignIn';
|
import { ActivitySignInModel, ActivitySignInModelType } from '../../db/ActivitySignIn';
|
||||||
import { SignInData } from '../../domain/activityField/signInField';
|
import { SignInData } from '../../domain/activityField/signInField';
|
||||||
import { getRoleCreateTime, getServerCreateTime } from '../redisService';
|
import { getRoleCreateTime, getServerCreateTime } from '../redisService';
|
||||||
import { getActivitiesByType, getActivityById } from './activityService';
|
import { getActivitiesByType, getActivityById } from './activityService';
|
||||||
|
import { RewardInter } from '../../pubUtils/interface';
|
||||||
|
import { stringToRewardInter } from './giftPackageService';
|
||||||
|
import { sendMailByContent } from '../mailService';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取活动数据
|
* 获取活动数据
|
||||||
@@ -136,3 +139,26 @@ export async function checkSignInCanBuy(roleId: string, serverId: number, activi
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 补发签到邮件
|
||||||
|
export async function repairSignInMail(playerData: SignInData) {
|
||||||
|
if(!playerData || playerData.productID == '&') return;
|
||||||
|
let playerRecords = await ActivitySignInModel.findByActivity(playerData.activityId, 1);
|
||||||
|
let hasRepaireRoleIds: string[] = []
|
||||||
|
for(let playerRecord of playerRecords) {
|
||||||
|
if(playerRecord.hasRepair) continue;
|
||||||
|
let notSendGoods: RewardInter[] = [];
|
||||||
|
let records = playerRecord.records||[];
|
||||||
|
for(let item of playerData.list) {
|
||||||
|
let curRec = records.find(rec => rec.dayIndex == item.dayIndex);
|
||||||
|
if(!curRec) {
|
||||||
|
notSendGoods.push(...stringToRewardInter(item.reward));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(notSendGoods.length > 0) {
|
||||||
|
await sendMailByContent(MAIL_TYPE.REPAIRE_SIGN_IN, playerRecord.roleId, { goods: notSendGoods });
|
||||||
|
hasRepaireRoleIds.push(playerRecord.roleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await ActivitySignInModel.repairSignIn(playerData.activityId, hasRepaireRoleIds);
|
||||||
|
}
|
||||||
@@ -53,6 +53,11 @@ import { RewardInter } from '../pubUtils/interface';
|
|||||||
import { stringToRewardInter } from './activity/giftPackageService';
|
import { stringToRewardInter } from './activity/giftPackageService';
|
||||||
import { autoCreateServerSchedule } from './serverService';
|
import { autoCreateServerSchedule } from './serverService';
|
||||||
import { setHiddenData } from './memoryCache/hiddenData';
|
import { setHiddenData } from './memoryCache/hiddenData';
|
||||||
|
import { SignInData } from '../domain/activityField/signInField';
|
||||||
|
import * as util from 'util';
|
||||||
|
import { ActivitySignInModel } from '../db/ActivitySignIn';
|
||||||
|
import { repairSignInMail } from './activity/signInService';
|
||||||
|
|
||||||
|
|
||||||
const PER_SECOND = 1 * 1000;
|
const PER_SECOND = 1 * 1000;
|
||||||
const PER_DAY = 24 * 60 * 60;
|
const PER_DAY = 24 * 60 * 60;
|
||||||
@@ -126,6 +131,9 @@ export async function init() {
|
|||||||
|
|
||||||
// 月基金每月未领取
|
// 月基金每月未领取
|
||||||
initMonthlyFundSchedule();
|
initMonthlyFundSchedule();
|
||||||
|
|
||||||
|
// 节日活动高级签到补发
|
||||||
|
initVipSignInMailSchedule()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每日刷新
|
// 每日刷新
|
||||||
@@ -998,6 +1006,21 @@ async function initMonthlyFundSchedule() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 高级签到自动补发
|
||||||
|
export async function initVipSignInMailSchedule() {
|
||||||
|
let activities = await ActivityModel.findOpenTypeByTime(ACTIVITY_TYPE.COMMON_SIGN_IN);
|
||||||
|
for(let activityData of activities) {
|
||||||
|
let playerData = new SignInData(activityData, 0, 0);
|
||||||
|
if(!playerData || playerData.productID == '&') continue;
|
||||||
|
|
||||||
|
const jobKey = `vipSignMailJob${playerData.activityId}`;
|
||||||
|
if(scheduledJobs[jobKey]) scheduledJobs[jobKey].cancel();
|
||||||
|
scheduleJob(jobKey, playerData.endTime, async () => {
|
||||||
|
await repairSignInMail(playerData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function monthlyFundSchedule(roundIndex: number) {
|
export async function monthlyFundSchedule(roundIndex: number) {
|
||||||
let activityMap = new Map<number, ActivityModelType>();
|
let activityMap = new Map<number, ActivityModelType>();
|
||||||
let playerDatas = await ActivityMonthlyFundModel.findNotReceivedReward(roundIndex);
|
let playerDatas = await ActivityMonthlyFundModel.findNotReceivedReward(roundIndex);
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ export enum MAIL_TYPE {
|
|||||||
MONTHLY_FUND = 45, // 补发月基金奖励
|
MONTHLY_FUND = 45, // 补发月基金奖励
|
||||||
ARTIFACT_OVER = 46, // 宝物数量超过
|
ARTIFACT_OVER = 46, // 宝物数量超过
|
||||||
GVG_BATTLE_PLAYER_SETTLE_RANK_REWARD = 47, // 激战期个人占领排行榜奖励
|
GVG_BATTLE_PLAYER_SETTLE_RANK_REWARD = 47, // 激战期个人占领排行榜奖励
|
||||||
|
REPAIRE_SIGN_IN = 48, // 高级签到补发奖励
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SEND_NAME = '系统';
|
export const SEND_NAME = '系统';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import BaseModel from './BaseModel';
|
import BaseModel from './BaseModel';
|
||||||
import { index, getModelForClass, prop, DocumentType, ReturnModelType, mongoose } from '@typegoose/typegoose';
|
import { index, getModelForClass, prop, DocumentType, ReturnModelType, mongoose } from '@typegoose/typegoose';
|
||||||
import { CounterAllModal } from './CounterAll';
|
import { CounterAllModal } from './CounterAll';
|
||||||
import { COUNTER } from '../consts';
|
import { ACTIVITY_TIME_TYPE, COUNTER } from '../consts';
|
||||||
import { ActivityGroupModel } from './ActivityGroup';
|
import { ActivityGroupModel } from './ActivityGroup';
|
||||||
import { UpdateActivityParam } from '../domain/backEndField/params';
|
import { UpdateActivityParam } from '../domain/backEndField/params';
|
||||||
|
|
||||||
@@ -90,6 +90,12 @@ export default class Activity extends BaseModel {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
public static async findOpenTypeByTime(type: number) {
|
||||||
|
let result: ActivityModelType[] = await ActivityModel.find({ type, isEnable: true, timeType: ACTIVITY_TIME_TYPE.DATE_TIME, beginTime: { $lte: new Date }, endTime: { $gte: new Date() } }).lean();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//debug测试用接口
|
//debug测试用接口
|
||||||
public static async debugFindActivityByType(type: number) {
|
public static async debugFindActivityByType(type: number) {
|
||||||
let result: ActivityModelType[] = await ActivityModel.findOne({ type }).lean(true);
|
let result: ActivityModelType[] = await ActivityModel.findOne({ type }).lean(true);
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ export default class Activity_Sign_In extends BaseModel {
|
|||||||
roundIndex: number; // 周期数,从活动设置的开始时间计算
|
roundIndex: number; // 周期数,从活动设置的开始时间计算
|
||||||
@prop({ required: true, type: Activity_Sign_In_Record, _id: false })
|
@prop({ required: true, type: Activity_Sign_In_Record, _id: false })
|
||||||
records: Activity_Sign_In_Record[]; // 领取记录
|
records: Activity_Sign_In_Record[]; // 领取记录
|
||||||
|
@prop({ required: false })
|
||||||
|
hasRepair: boolean; // 是否补发了
|
||||||
|
|
||||||
//签到记录
|
//签到记录
|
||||||
public static async addSignInRecord(activityId: number, roleId: string, roundIndex: number, dayIndex: number) {
|
public static async addSignInRecord(activityId: number, roleId: string, roundIndex: number, dayIndex: number) {
|
||||||
@@ -48,6 +50,16 @@ export default class Activity_Sign_In extends BaseModel {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据活动id查询记录
|
||||||
|
public static async findByActivity(activityId: number, roundIndex: number) {
|
||||||
|
let result: ActivitySignInModelType[] = await ActivitySignInModel.find({ activityId, roundIndex }).lean();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async repairSignIn(activityId: number, roleIds: string[]) {
|
||||||
|
await ActivitySignInModel.updateMany({ activityId, roleId: { $in: roleIds } }, { $set: { hasRepair: true } });
|
||||||
|
}
|
||||||
|
|
||||||
//删除签到记录
|
//删除签到记录
|
||||||
public static async deleteActivity(activityId: number, roleId: string, roundIndex: number) {
|
public static async deleteActivity(activityId: number, roleId: string, roundIndex: number) {
|
||||||
await ActivitySignInModel.deleteMany({ roleId, activityId, roundIndex });
|
await ActivitySignInModel.deleteMany({ roleId, activityId, roundIndex });
|
||||||
|
|||||||
@@ -334,5 +334,12 @@
|
|||||||
"sendName": "学宫驿使",
|
"sendName": "学宫驿使",
|
||||||
"content": "亲爱的百家传人,逐鹿中原激战期内,您在积分上为联军做出重要贡献,荣获第%d名,奖励现已发送至邮箱,请查收",
|
"content": "亲爱的百家传人,逐鹿中原激战期内,您在积分上为联军做出重要贡献,荣获第%d名,奖励现已发送至邮箱,请查收",
|
||||||
"time": 720
|
"time": 720
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 48,
|
||||||
|
"title": "&",
|
||||||
|
"sendName": "学宫驿使",
|
||||||
|
"content": "亲爱的百家传人,您在本期集会活动中有高级签到的奖励未领取,现发送至邮箱,请查收",
|
||||||
|
"time": 2160
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
Reference in New Issue
Block a user