报警增加代金券消耗和累计充值

This commit is contained in:
colter 2024-01-02 15:22:15 +08:00
parent 9e2efe6320
commit daeac2e263
6 changed files with 111 additions and 29 deletions

View File

@ -13,3 +13,5 @@ export const taConfig = {
};
export const taUrl = 'http://47.112.98.161:8992';
export const fromDate = '2023-12-28';

View File

@ -0,0 +1,5 @@
export enum EResourceId {
DJQ = 2226,
XIAN_YU = 202,
}

View File

@ -10,6 +10,13 @@ export interface IRecordInfo {
num: number;
}
export interface INotifyInfo {
uid: string;
num: number;
recharge: number;
djq: number;
}
export interface INotifyConfig {
useXianYu: number;
getXianYu: number;

View File

@ -4,15 +4,15 @@
import axios from 'axios';
import { Injectable } from '@nestjs/common';
import { EChangeType, IRecordInfo } from './interface';
import { EChangeType, INotifyInfo, IRecordInfo } from './interface';
@Injectable()
export class NotifyService {
private _itemTemplate = '[channel][uids]等玩家的[itemId][type量]已超过预警值,请注意处理';
private _rechargeTemplate = '[channel][uids]等玩家的充值已超过预警值,请注意处理';
private _itemTemplate = '[channel][itemId][type量]已触发报警,请注意处理\n';
private _rechargeTemplate = '[channel]充值已触发报警,请注意处理\n';
private records: Map<string, string[]> = new Map();
async notifyRecharge(data: IRecordInfo[], channel: string) {
async notifyRecharge(data: INotifyInfo[], channel: string) {
if (data.length === 0) return;
const key = `${channel}-recharge`;
@ -21,15 +21,15 @@ export class NotifyService {
const uids = data.map(d => d.uid).filter(uid => !old.includes(uid));
if (uids.length === 0) return;
const content = this.formatRecharge(channel, uids);
const content = this.formatRecharge(channel, data);
console.log(content);
await this.sendDD(content);
old.push(...uids);
this.records.set(key, old);
// old.push(...uids);
// this.records.set(key, old);
}
async notifyItemChange(data: IRecordInfo[], channel: string, itemId: number | string, type: EChangeType) {
async notifyItemChange(data: INotifyInfo[], channel: string, itemId: number | string, type: EChangeType) {
if (data.length === 0) return;
const key = `${channel}-${type}`;
@ -38,25 +38,27 @@ export class NotifyService {
const uids = data.map(d => d.uid).filter(uid => !old.includes(uid));
if (uids.length === 0) return;
const content = this.formatItem(channel, uids, itemId, type);
const content = this.formatItem(channel, data, itemId, type);
console.log(content);
await this.sendDD(content);
old.push(...uids);
this.records.set(key, old);
// old.push(...uids);
// this.records.set(key, old);
}
private formatItem(channel: string, uids: string[], itemId: string | number, type: EChangeType) {
private formatItem(channel: string, data: INotifyInfo[], itemId: string | number, type: EChangeType) {
return this._itemTemplate
.replace('channel', channel)
.replace('uids', uids.join(','))
.replace('itemId', itemId as string)
.replace('type', type === 'use' ? '消耗' : '获取')
.replace('type', type === 'use' ? '消耗' : '获取') + this.formatNotifyInfo(data);
}
private formatRecharge(channel: string, uids: string[]) {
private formatRecharge(channel: string, data: INotifyInfo[]) {
return this._rechargeTemplate
.replace('channel', channel)
.replace('uids', uids.join(','));
.replace('channel', channel) + this.formatNotifyInfo(data);
}
private formatNotifyInfo(data: INotifyInfo[]) {
return data.map(d => `[${d.uid}][总代金券消耗: ${d.djq}][总充值: ${d.recharge}]`).join('\n');
}
private async sendDD(content: string) {

View File

@ -5,10 +5,12 @@ import moment from 'moment';
import axios, { AxiosInstance } from 'axios';
import { Injectable } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { taConfig, taUrl } from '../../config/ta.config';
import { fromDate, taConfig, taUrl } from '../../config/ta.config';
import { NotifyService } from './notify.service';
import { INotifyConfig, IRecordInfo, ITaConfig } from './interface';
import { EChangeType, INotifyConfig, INotifyInfo, IRecordInfo, ITaConfig } from './interface';
import { __ROOT__ } from '../../config/config';
import { EResourceId } from './constant';
import { getEventName } from './util';
@Injectable()
export class TaService {
@ -41,10 +43,13 @@ export class TaService {
const { eventDb, apiSecret, channel } = config;
const sql = this.rechargeSql(eventDb, date, limit);
const res = await this.readData(apiSecret, sql);
await this._notifyService.notifyRecharge(res, channel);
if (res.length === 0) return;
const ni = await this.getNotifyInfo(apiSecret, eventDb, res);
await this._notifyService.notifyRecharge(ni, channel);
}
private async checkXianYu(config: ITaConfig, date: string, type: 'use' | 'get', limit: number) {
private async checkXianYu(config: ITaConfig, date: string, type: EChangeType, limit: number) {
if (!limit) {
console.log(`none checkGetXianYu config, limit: ${limit}`);
return;
@ -54,10 +59,13 @@ export class TaService {
const eventName = type === 'use' ? 'use_xian_yu' : 'get_xian_yu';
const sql = this.xianYuChangeSql(eventDb, date, eventName, limit);
const res = await this.readData(apiSecret, sql);
await this._notifyService.notifyItemChange(res, channel, '仙玉', type);
if (res.length === 0) return;
const ni = await this.getNotifyInfo(apiSecret, eventDb, res);
await this._notifyService.notifyItemChange(ni, channel, '仙玉', type);
}
private async checkItem(config: ITaConfig, date: string, itemId: number, type: 'use' | 'get', limit: number) {
private async checkItem(config: ITaConfig, date: string, itemId: number, type: EChangeType, limit: number) {
if (!limit) {
console.log(`none checkItem config, type: ${type}, limit: ${limit}`);
return;
@ -67,8 +75,41 @@ export class TaService {
const eventName = type === 'use' ? 'use_item' : 'get_item';
const sql = this.itemChangeSql(eventDb, date, itemId, eventName, limit);
const res = await this.readData(apiSecret, sql);
if (res.length === 0) return;
await this._notifyService.notifyItemChange(res, channel, itemId, type);
const ni = await this.getNotifyInfo(apiSecret, eventDb, res);
await this._notifyService.notifyItemChange(ni, channel, itemId, type);
}
private async getNotifyInfo(apiSecret: string, eventDb: string, infos: IRecordInfo[]) {
const uids = infos.map(r => r.uid);
const totalRecharge = await this.getTotalRecharge(apiSecret, eventDb, uids);
const totalDjq = await this.getTotalDjq(apiSecret, eventDb, uids, 'use');
const res: INotifyInfo[] = [];
for (const info of infos) {
const rechargeRecord = totalRecharge.find(t => t.uid === info.uid);
const djqRecord = totalDjq.find(t => t.uid === info.uid);
res.push({
...info,
djq: djqRecord?.num || 0,
recharge: rechargeRecord?.num || 0
});
}
return res;
}
private async getTotalRecharge(apiSecret: string, db: string, uids: string[]) {
const sql = this.totalRechargeSql(db, uids, fromDate);
return this.readData(apiSecret, sql);
}
private async getTotalDjq(apiSecret: string, db: string, uids: string[], type: EChangeType) {
const sql = this.itemTotalSql(db, EResourceId.DJQ, getEventName(type), uids, fromDate);
return this.readData(apiSecret, sql);
}
private readConfig() {
@ -86,7 +127,7 @@ export class TaService {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
// console.log('data', data);
// console.log('data', data)
return this.formatData(data);
}
@ -118,8 +159,18 @@ export class TaService {
GROUP BY "#account_id" HAVING sum ("pay_amount") > ${limit}
`;
}
private totalRechargeSql(db: string, uids: string[], fromDate: string) {
return `
SELECT "#account_id" AS "uid", sum("pay_amount") AS "num"
FROM ${db}
WHERE "$part_date" >= '${fromDate}'
AND "#event_name" = 'order_finish'
AND "#account_id" IN (${uids.map(u => `'${u}'`).join(',')})
GROUP BY "#account_id";
`;
}
private xianYuChangeSql(db: string, date: string, eventName: string, limit = 10 * 1000) {
private xianYuChangeSql(db: string, date: string, eventName: string, limit: number) {
return `
SELECT "#account_id" AS "uid", sum ("change_num") AS "num"
FROM ${db}
@ -128,12 +179,24 @@ export class TaService {
`;
}
private itemChangeSql(db: string, date: string, itemId: number, eventName: string, limit = 100000) {
private itemTotalSql(db: string, itemId: number, eventName: string, uids: string[], fromDate: string) {
return `
SELECT "#account_id" AS "uid", sum("change_num") AS "num"
FROM ${db}
WHERE "$part_date" >= '${fromDate}'
AND "#event_name" = '${eventName}'
AND "item_id" = ${itemId}
AND "#account_id" IN (${uids.map(u => `'${u}'`).join(',')})
GROUP BY "#account_id";
`;
}
private itemChangeSql(db: string, date: string, itemId: number, eventName: string, limit: number, dateC = '=') {
return `
SELECT "#account_id" AS "uid", sum ("change_num") AS "num"
FROM ${db}
WHERE "$part_date" = '${date}' AND "#event_name" = '${eventName}' AND "item_id" = ${itemId}
GROUP BY "#account_id" HAVING sum ("change_num") > ${limit}
WHERE "$part_date" ${dateC} '${date}' AND "#event_name" = '${eventName}' AND "item_id" = ${itemId}
GROUP BY "#account_id" HAVING sum ("change_num") >= ${limit}
`;
}
}

3
src/server/ta/util.ts Normal file
View File

@ -0,0 +1,3 @@
import { EChangeType } from './interface';
export const getEventName = (type: EChangeType) => type === 'get' ? 'get_item' : 'use_item';