|
@@ -6,6 +6,81 @@ import { MessageRecordService } from "../services/messageRecordService";
|
|
|
class MessageRecordController {
|
|
class MessageRecordController {
|
|
|
private messageRecordService: MessageRecordService;
|
|
private messageRecordService: MessageRecordService;
|
|
|
|
|
|
|
|
|
|
+ private static readonly MAX_RANGE_DAYS_GENERAL = 180;
|
|
|
|
|
+ private static readonly MAX_RANGE_DAYS_DIMENSION = 90;
|
|
|
|
|
+ private static readonly MAX_RANGE_DAYS_MULTI_DIMENSION = 31;
|
|
|
|
|
+
|
|
|
|
|
+ private parseDateRange(req: Request) {
|
|
|
|
|
+ const { startDate, endDate } = req.query;
|
|
|
|
|
+ const start = startDate ? new Date(startDate as string) : undefined;
|
|
|
|
|
+ const end = endDate ? new Date(endDate as string) : undefined;
|
|
|
|
|
+ return { start, end };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private validateDateRange(res: Response, start?: Date, end?: Date, maxDays: number = MessageRecordController.MAX_RANGE_DAYS_GENERAL): boolean {
|
|
|
|
|
+ if (!start || !end) {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
|
|
|
|
|
+ res.status(400).json({ success: false, message: "Invalid startDate/endDate format." });
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const requestedRangeDays = Math.ceil((end.getTime() - start.getTime()) / (24 * 60 * 60 * 1000));
|
|
|
|
|
+
|
|
|
|
|
+ if (requestedRangeDays > maxDays) {
|
|
|
|
|
+ res.status(422).json({
|
|
|
|
|
+ success: false,
|
|
|
|
|
+ code: "RANGE_TOO_LARGE",
|
|
|
|
|
+ message: `Requested date range exceeds max allowed ${maxDays} days.`,
|
|
|
|
|
+ maxRangeDays: maxDays,
|
|
|
|
|
+ requestedRangeDays,
|
|
|
|
|
+ suggestedAction: "Narrow date range or apply more filters.",
|
|
|
|
|
+ });
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private parsePagination(req: Request) {
|
|
|
|
|
+ const pageRaw = parseInt(req.query.page as string, 10);
|
|
|
|
|
+ const limitRaw = parseInt(req.query.limit as string, 10);
|
|
|
|
|
+ const page = Number.isNaN(pageRaw) ? MessageRecordService.DEFAULT_STATS_PAGE : Math.max(1, pageRaw);
|
|
|
|
|
+ const limit = Number.isNaN(limitRaw) ? MessageRecordService.DEFAULT_STATS_LIMIT : Math.min(MessageRecordService.MAX_STATS_LIMIT, Math.max(1, limitRaw));
|
|
|
|
|
+ return { page, limit };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private logStatsRequest(endpoint: string, req: Request, extra: Record<string, unknown> = {}) {
|
|
|
|
|
+ const startedAt = Date.now();
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ `[MessageStats] ${endpoint} start`,
|
|
|
|
|
+ JSON.stringify({
|
|
|
|
|
+ endpoint,
|
|
|
|
|
+ startDate: req.query.startDate || null,
|
|
|
|
|
+ endDate: req.query.endDate || null,
|
|
|
|
|
+ strategyName: req.query.strategyName || null,
|
|
|
|
|
+ page: req.query.page || null,
|
|
|
|
|
+ limit: req.query.limit || null,
|
|
|
|
|
+ ...extra,
|
|
|
|
|
+ })
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ return (resultRows: number, success: boolean, errorMessage?: string) => {
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ `[MessageStats] ${endpoint} end`,
|
|
|
|
|
+ JSON.stringify({
|
|
|
|
|
+ endpoint,
|
|
|
|
|
+ durationMs: Date.now() - startedAt,
|
|
|
|
|
+ resultRows,
|
|
|
|
|
+ success,
|
|
|
|
|
+ errorMessage: errorMessage || null,
|
|
|
|
|
+ })
|
|
|
|
|
+ );
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
constructor() {
|
|
constructor() {
|
|
|
this.messageRecordService = new MessageRecordService();
|
|
this.messageRecordService = new MessageRecordService();
|
|
|
}
|
|
}
|
|
@@ -60,7 +135,13 @@ class MessageRecordController {
|
|
|
return res.status(200).json({
|
|
return res.status(200).json({
|
|
|
success: true,
|
|
success: true,
|
|
|
data: paginatedRecords.records,
|
|
data: paginatedRecords.records,
|
|
|
- pagination: { total: paginatedRecords.total, page: paginatedRecords.page, limit: paginatedRecords.limit, totalPages: paginatedRecords.totalPages },
|
|
|
|
|
|
|
+ pagination: {
|
|
|
|
|
+ total: paginatedRecords.total,
|
|
|
|
|
+ page: paginatedRecords.page,
|
|
|
|
|
+ limit: paginatedRecords.limit,
|
|
|
|
|
+ totalPages: paginatedRecords.totalPages,
|
|
|
|
|
+ isTotalEstimated: paginatedRecords.isTotalEstimated,
|
|
|
|
|
+ },
|
|
|
});
|
|
});
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
console.error("Error fetching paginated records:", error);
|
|
console.error("Error fetching paginated records:", error);
|
|
@@ -140,22 +221,58 @@ class MessageRecordController {
|
|
|
*/
|
|
*/
|
|
|
public getOverallStatistics = async (req: Request, res: Response): Promise<Response> => {
|
|
public getOverallStatistics = async (req: Request, res: Response): Promise<Response> => {
|
|
|
try {
|
|
try {
|
|
|
- console.time("getOverallStatistics");
|
|
|
|
|
- const { startDate, endDate, strategyName } = req.query;
|
|
|
|
|
- const start = startDate ? new Date(startDate as string) : undefined;
|
|
|
|
|
- const end = endDate ? new Date(endDate as string) : undefined;
|
|
|
|
|
|
|
+ const done = this.logStatsRequest("overall", req);
|
|
|
|
|
+ const { start, end } = this.parseDateRange(req);
|
|
|
|
|
+ if (!this.validateDateRange(res, start, end, MessageRecordController.MAX_RANGE_DAYS_GENERAL)) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const { strategyName } = req.query;
|
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
|
|
|
|
|
|
const stats = await this.messageRecordService.getOverallStatistics(start, end, stratName);
|
|
const stats = await this.messageRecordService.getOverallStatistics(start, end, stratName);
|
|
|
- console.timeEnd("getOverallStatistics");
|
|
|
|
|
|
|
+ done(stats ? 1 : 0, true);
|
|
|
|
|
|
|
|
return res.status(200).json({ success: true, data: stats });
|
|
return res.status(200).json({ success: true, data: stats });
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
|
|
+ const done = this.logStatsRequest("overall", req);
|
|
|
|
|
+ done(0, false, error.message);
|
|
|
console.error("Error fetching overall statistics:", error);
|
|
console.error("Error fetching overall statistics:", error);
|
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * @route GET /api/message/statistics/summary
|
|
|
|
|
+ * @desc Retrieves first-screen summary payload for message dashboard.
|
|
|
|
|
+ * @access Private
|
|
|
|
|
+ */
|
|
|
|
|
+ public getStatisticsSummary = async (req: Request, res: Response): Promise<Response> => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const done = this.logStatsRequest("summary", req);
|
|
|
|
|
+ const { start, end } = this.parseDateRange(req);
|
|
|
|
|
+ if (!this.validateDateRange(res, start, end, MessageRecordController.MAX_RANGE_DAYS_GENERAL)) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const { strategyName } = req.query;
|
|
|
|
|
+ const stratName = strategyName ? (strategyName as string) : undefined;
|
|
|
|
|
+ const { page, limit } = this.parsePagination(req);
|
|
|
|
|
+
|
|
|
|
|
+ const summary = await this.messageRecordService.getStatisticsSummary(start, end, stratName, page, limit);
|
|
|
|
|
+ const trendCount = Array.isArray(summary.dailyTrends) ? summary.dailyTrends.length : 0;
|
|
|
|
|
+ const strategyCount = Array.isArray(summary.strategyStats) ? summary.strategyStats.length : 0;
|
|
|
|
|
+ done(trendCount + strategyCount, true);
|
|
|
|
|
+
|
|
|
|
|
+ return res.status(200).json({ success: true, data: summary });
|
|
|
|
|
+ } catch (error: any) {
|
|
|
|
|
+ const done = this.logStatsRequest("summary", req);
|
|
|
|
|
+ done(0, false, error.message);
|
|
|
|
|
+ console.error("Error fetching statistics summary:", error);
|
|
|
|
|
+ return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* @route GET /api/message/statistics/by-activity
|
|
* @route GET /api/message/statistics/by-activity
|
|
|
* @desc Retrieves message push statistics grouped by activity
|
|
* @desc Retrieves message push statistics grouped by activity
|
|
@@ -186,15 +303,21 @@ class MessageRecordController {
|
|
|
*/
|
|
*/
|
|
|
public getStatisticsByStrategy = async (req: Request, res: Response): Promise<Response> => {
|
|
public getStatisticsByStrategy = async (req: Request, res: Response): Promise<Response> => {
|
|
|
try {
|
|
try {
|
|
|
- console.time("getStatisticsByStrategy");
|
|
|
|
|
|
|
+ const done = this.logStatsRequest("by-strategy", req);
|
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
|
|
|
+ if (!this.validateDateRange(res, start, end, MessageRecordController.MAX_RANGE_DAYS_DIMENSION)) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
|
- const stats = await this.messageRecordService.getStatisticsByStrategy(start, end, stratName);
|
|
|
|
|
- console.timeEnd("getStatisticsByStrategy");
|
|
|
|
|
|
|
+ const { page, limit } = this.parsePagination(req);
|
|
|
|
|
+ const stats = await this.messageRecordService.getStatisticsByStrategy(start, end, stratName, page, limit);
|
|
|
|
|
+ done(Array.isArray(stats) ? stats.length : 0, true);
|
|
|
return res.status(200).json({ success: true, data: stats });
|
|
return res.status(200).json({ success: true, data: stats });
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
|
|
+ const done = this.logStatsRequest("by-strategy", req);
|
|
|
|
|
+ done(0, false, error.message);
|
|
|
console.error("Error fetching statistics by strategy:", error);
|
|
console.error("Error fetching statistics by strategy:", error);
|
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
|
}
|
|
}
|
|
@@ -208,16 +331,22 @@ class MessageRecordController {
|
|
|
*/
|
|
*/
|
|
|
public getStatisticsByTemplate = async (req: Request, res: Response): Promise<Response> => {
|
|
public getStatisticsByTemplate = async (req: Request, res: Response): Promise<Response> => {
|
|
|
try {
|
|
try {
|
|
|
- console.time("getStatisticsByTemplate");
|
|
|
|
|
|
|
+ const done = this.logStatsRequest("by-template", req);
|
|
|
// 从查询参数中获取 startDate, endDate 和 strategyName
|
|
// 从查询参数中获取 startDate, endDate 和 strategyName
|
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
|
|
|
+ if (!this.validateDateRange(res, start, end, MessageRecordController.MAX_RANGE_DAYS_DIMENSION)) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
|
- const stats = await this.messageRecordService.getStatisticsByTemplate(start, end, stratName);
|
|
|
|
|
- console.timeEnd("getStatisticsByTemplate");
|
|
|
|
|
|
|
+ const { page, limit } = this.parsePagination(req);
|
|
|
|
|
+ const stats = await this.messageRecordService.getStatisticsByTemplate(start, end, stratName, page, limit);
|
|
|
|
|
+ done(Array.isArray(stats) ? stats.length : 0, true);
|
|
|
return res.status(200).json({ success: true, data: stats });
|
|
return res.status(200).json({ success: true, data: stats });
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
|
|
+ const done = this.logStatsRequest("by-template", req);
|
|
|
|
|
+ done(0, false, error.message);
|
|
|
console.error("Error fetching statistics by template:", error);
|
|
console.error("Error fetching statistics by template:", error);
|
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
|
}
|
|
}
|
|
@@ -231,16 +360,22 @@ class MessageRecordController {
|
|
|
*/
|
|
*/
|
|
|
public getStatisticsByCc = async (req: Request, res: Response): Promise<Response> => {
|
|
public getStatisticsByCc = async (req: Request, res: Response): Promise<Response> => {
|
|
|
try {
|
|
try {
|
|
|
- console.time("getStatisticsByCc");
|
|
|
|
|
|
|
+ const done = this.logStatsRequest("by-cc", req);
|
|
|
// 从查询参数中获取 startDate, endDate 和 strategyName
|
|
// 从查询参数中获取 startDate, endDate 和 strategyName
|
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
|
|
|
+ if (!this.validateDateRange(res, start, end, MessageRecordController.MAX_RANGE_DAYS_DIMENSION)) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
|
- const stats = await this.messageRecordService.getStatisticsByCc(start, end, stratName);
|
|
|
|
|
- console.timeEnd("getStatisticsByCc");
|
|
|
|
|
|
|
+ const { page, limit } = this.parsePagination(req);
|
|
|
|
|
+ const stats = await this.messageRecordService.getStatisticsByCc(start, end, stratName, page, limit);
|
|
|
|
|
+ done(Array.isArray(stats) ? stats.length : 0, true);
|
|
|
return res.status(200).json({ success: true, data: stats });
|
|
return res.status(200).json({ success: true, data: stats });
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
|
|
+ const done = this.logStatsRequest("by-cc", req);
|
|
|
|
|
+ done(0, false, error.message);
|
|
|
console.error("Error fetching statistics by cc:", error);
|
|
console.error("Error fetching statistics by cc:", error);
|
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
|
}
|
|
}
|
|
@@ -254,16 +389,22 @@ class MessageRecordController {
|
|
|
*/
|
|
*/
|
|
|
public getStatisticsByImage = async (req: Request, res: Response): Promise<Response> => {
|
|
public getStatisticsByImage = async (req: Request, res: Response): Promise<Response> => {
|
|
|
try {
|
|
try {
|
|
|
- console.time("getStatisticsByImage");
|
|
|
|
|
|
|
+ const done = this.logStatsRequest("by-image", req);
|
|
|
// 从查询参数中获取 startDate, endDate 和 strategyName
|
|
// 从查询参数中获取 startDate, endDate 和 strategyName
|
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
|
|
|
+ if (!this.validateDateRange(res, start, end, MessageRecordController.MAX_RANGE_DAYS_DIMENSION)) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
|
- const stats = await this.messageRecordService.getStatisticsByImage(start, end, stratName);
|
|
|
|
|
- console.timeEnd("getStatisticsByImage");
|
|
|
|
|
|
|
+ const { page, limit } = this.parsePagination(req);
|
|
|
|
|
+ const stats = await this.messageRecordService.getStatisticsByImage(start, end, stratName, page, limit);
|
|
|
|
|
+ done(Array.isArray(stats) ? stats.length : 0, true);
|
|
|
return res.status(200).json({ success: true, data: stats });
|
|
return res.status(200).json({ success: true, data: stats });
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
|
|
+ const done = this.logStatsRequest("by-image", req);
|
|
|
|
|
+ done(0, false, error.message);
|
|
|
console.error("Error fetching statistics by image:", error);
|
|
console.error("Error fetching statistics by image:", error);
|
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
|
}
|
|
}
|
|
@@ -277,16 +418,21 @@ class MessageRecordController {
|
|
|
*/
|
|
*/
|
|
|
public getDailySentTrends = async (req: Request, res: Response): Promise<Response> => {
|
|
public getDailySentTrends = async (req: Request, res: Response): Promise<Response> => {
|
|
|
try {
|
|
try {
|
|
|
- console.time("getDailySentTrends");
|
|
|
|
|
|
|
+ const done = this.logStatsRequest("daily-trends", req);
|
|
|
// 从查询参数中获取 startDate, endDate 和 strategyName
|
|
// 从查询参数中获取 startDate, endDate 和 strategyName
|
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
const { startDate, endDate, strategyName } = req.query;
|
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
const start = startDate ? new Date(startDate as string) : undefined;
|
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
const end = endDate ? new Date(endDate as string) : undefined;
|
|
|
|
|
+ if (!this.validateDateRange(res, start, end, MessageRecordController.MAX_RANGE_DAYS_GENERAL)) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
const stratName = strategyName ? (strategyName as string) : undefined;
|
|
|
const stats = await this.messageRecordService.getDailySentTrends(start, end, stratName);
|
|
const stats = await this.messageRecordService.getDailySentTrends(start, end, stratName);
|
|
|
- console.timeEnd("getDailySentTrends");
|
|
|
|
|
|
|
+ done(Array.isArray(stats) ? stats.length : 0, true);
|
|
|
return res.status(200).json({ success: true, data: stats });
|
|
return res.status(200).json({ success: true, data: stats });
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
|
|
+ const done = this.logStatsRequest("daily-trends", req);
|
|
|
|
|
+ done(0, false, error.message);
|
|
|
console.error("Error fetching daily sent trends:", error);
|
|
console.error("Error fetching daily sent trends:", error);
|
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
|
}
|
|
}
|
|
@@ -300,22 +446,27 @@ class MessageRecordController {
|
|
|
*/
|
|
*/
|
|
|
public getMultiDimensionalStatistics = async (req: Request, res: Response): Promise<Response> => {
|
|
public getMultiDimensionalStatistics = async (req: Request, res: Response): Promise<Response> => {
|
|
|
try {
|
|
try {
|
|
|
- console.time("getMultiDimensionalStatistics");
|
|
|
|
|
|
|
+ const done = this.logStatsRequest("multi-dimensional", req);
|
|
|
const { startDate, endDate, templateName, strategyName, cc, image } = req.query;
|
|
const { startDate, endDate, templateName, strategyName, cc, image } = req.query;
|
|
|
|
|
|
|
|
const filters: { [key: string]: any } = {};
|
|
const filters: { [key: string]: any } = {};
|
|
|
if (startDate) filters.startDate = new Date(startDate as string);
|
|
if (startDate) filters.startDate = new Date(startDate as string);
|
|
|
if (endDate) filters.endDate = new Date(endDate as string);
|
|
if (endDate) filters.endDate = new Date(endDate as string);
|
|
|
|
|
+ if (!this.validateDateRange(res, filters.startDate, filters.endDate, MessageRecordController.MAX_RANGE_DAYS_MULTI_DIMENSION)) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
if (templateName) filters.templateName = templateName;
|
|
if (templateName) filters.templateName = templateName;
|
|
|
if (strategyName) filters.strategyName = strategyName;
|
|
if (strategyName) filters.strategyName = strategyName;
|
|
|
if (cc) filters.cc = cc;
|
|
if (cc) filters.cc = cc;
|
|
|
if (image) filters.image = image;
|
|
if (image) filters.image = image;
|
|
|
|
|
|
|
|
const stats = await this.messageRecordService.getMultiDimensionalStatistics(filters);
|
|
const stats = await this.messageRecordService.getMultiDimensionalStatistics(filters);
|
|
|
- console.timeEnd("getMultiDimensionalStatistics");
|
|
|
|
|
|
|
+ done(Array.isArray(stats) ? stats.length : 0, true);
|
|
|
|
|
|
|
|
return res.status(200).json({ success: true, data: stats });
|
|
return res.status(200).json({ success: true, data: stats });
|
|
|
} catch (error: any) {
|
|
} catch (error: any) {
|
|
|
|
|
+ const done = this.logStatsRequest("multi-dimensional", req);
|
|
|
|
|
+ done(0, false, error.message);
|
|
|
console.error("Error fetching multi-dimensional statistics:", error);
|
|
console.error("Error fetching multi-dimensional statistics:", error);
|
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
return res.status(500).json({ success: false, message: "Server error", error: error.message });
|
|
|
}
|
|
}
|