befly 3.56.0 → 3.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apis/tongJi/_daily.js +159 -0
- package/apis/tongJi/_tongJi.js +13 -33
- package/apis/tongJi/dailyReport.js +76 -0
- package/apis/tongJi/dailyStats.js +182 -0
- package/apis/tongJi/errorList.js +20 -58
- package/apis/tongJi/errorReport.js +10 -34
- package/apis/tongJi/errorStats.js +171 -198
- package/checks/config.js +1 -1
- package/package.json +1 -1
- package/apis/tongJi/infoReport.js +0 -91
- package/apis/tongJi/infoStats.js +0 -190
- package/apis/tongJi/onlineReport.js +0 -102
- package/apis/tongJi/onlineStats.js +0 -85
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { getDateYmdNumber } from "#befly/utils/datetime.js";
|
|
2
2
|
|
|
3
|
-
import { getErrorStatsDayBucketCountKey, getErrorStatsDayBucketsKey, getErrorStatsDayTypeCountKey, getErrorStatsDayTypesKey, getErrorStatsPeriodCountKey, getTongJiMonthStartDate, getTongJiNumber, getTongJiRecentDateList, getTongJiWeekStartDate } from "./_tongJi.js";
|
|
3
|
+
import { getErrorStatsDayBucketCountKey, getErrorStatsDayBucketsKey, getErrorStatsDayTypeCountKey, getErrorStatsDayTypesKey, getErrorStatsPeriodCountKey, getTongJiDateRangeList, getTongJiMonthStartDate, getTongJiNumber, getTongJiRecentDateList, getTongJiWeekStartDate } from "./_tongJi.js";
|
|
4
4
|
|
|
5
5
|
const ERROR_STATS_DAY_LIMIT = 30;
|
|
6
6
|
|
|
7
|
+
function sumCounts(items) {
|
|
8
|
+
return items.reduce((sum, item) => sum + item.count, 0);
|
|
9
|
+
}
|
|
10
|
+
|
|
7
11
|
async function getErrorStatsRedisSummary(befly, periodType, periodValue) {
|
|
8
12
|
return {
|
|
9
13
|
count: getTongJiNumber(await befly.redis.getString(getErrorStatsPeriodCountKey(periodType, periodValue)))
|
|
@@ -12,96 +16,70 @@ async function getErrorStatsRedisSummary(befly, periodType, periodValue) {
|
|
|
12
16
|
|
|
13
17
|
async function getErrorStatsRedisTrend(befly, bucketDate) {
|
|
14
18
|
const bucketSet = await befly.redis.smembers(getErrorStatsDayBucketsKey(bucketDate));
|
|
15
|
-
const trend =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const itemBucketTime = getTongJiNumber(bucketTime);
|
|
19
|
+
const trend = await Promise.all(
|
|
20
|
+
bucketSet.map(async (bucketTime) => {
|
|
21
|
+
const itemBucketTime = getTongJiNumber(bucketTime);
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
return {
|
|
24
|
+
bucketTime: itemBucketTime,
|
|
25
|
+
bucketDate: bucketDate,
|
|
26
|
+
count: getTongJiNumber(await befly.redis.getString(getErrorStatsDayBucketCountKey(bucketDate, itemBucketTime)))
|
|
27
|
+
};
|
|
28
|
+
})
|
|
29
|
+
);
|
|
26
30
|
|
|
27
31
|
trend.sort((a, b) => a.bucketTime - b.bucketTime);
|
|
28
32
|
return trend;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
async function getErrorStatsRedisDays(befly, recentDateList) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return days;
|
|
36
|
+
return Promise.all(
|
|
37
|
+
recentDateList.map(async (item) => {
|
|
38
|
+
return {
|
|
39
|
+
bucketDate: item,
|
|
40
|
+
count: getTongJiNumber(await befly.redis.getString(getErrorStatsPeriodCountKey("day", item)))
|
|
41
|
+
};
|
|
42
|
+
})
|
|
43
|
+
);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
async function getErrorStatsRedisTopTypes(befly, bucketDate) {
|
|
45
47
|
const typeSet = await befly.redis.smembers(getErrorStatsDayTypesKey(bucketDate));
|
|
46
|
-
const topTypes =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (b.count !== a.count) {
|
|
64
|
-
return b.count - a.count;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return String(a.errorType).localeCompare(String(b.errorType), "zh-CN");
|
|
68
|
-
});
|
|
48
|
+
const topTypes = await Promise.all(
|
|
49
|
+
typeSet.map(async (errorType) => {
|
|
50
|
+
const name = String(errorType || "unknown");
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
errorType: name,
|
|
54
|
+
count: getTongJiNumber(await befly.redis.getString(getErrorStatsDayTypeCountKey(bucketDate, name)))
|
|
55
|
+
};
|
|
56
|
+
})
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return topTypes
|
|
60
|
+
.filter((item) => item.count > 0)
|
|
61
|
+
.toSorted((a, b) => {
|
|
62
|
+
if (b.count !== a.count) {
|
|
63
|
+
return b.count - a.count;
|
|
64
|
+
}
|
|
69
65
|
|
|
70
|
-
|
|
66
|
+
return String(a.errorType).localeCompare(String(b.errorType), "zh-CN");
|
|
67
|
+
})
|
|
68
|
+
.slice(0, 5);
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
const todaySummary = await getErrorStatsRedisSummary(befly, "day", bucketDate);
|
|
75
|
-
const yesterdayDate = recentDateList[recentDateList.length - 2] || bucketDate;
|
|
76
|
-
const dayBeforeYesterdayDate = recentDateList[recentDateList.length - 3] || yesterdayDate;
|
|
77
|
-
const yesterdaySummary = await getErrorStatsRedisSummary(befly, "day", yesterdayDate);
|
|
78
|
-
const dayBeforeYesterdaySummary = await getErrorStatsRedisSummary(befly, "day", dayBeforeYesterdayDate);
|
|
79
|
-
const weekSummary = await getErrorStatsRedisSummary(befly, "week", weekStartDate);
|
|
80
|
-
const monthSummary = await getErrorStatsRedisSummary(befly, "month", monthStartDate);
|
|
81
|
-
const trend = await getErrorStatsRedisTrend(befly, bucketDate);
|
|
82
|
-
const days = await getErrorStatsRedisDays(befly, recentDateList);
|
|
83
|
-
const topTypes = await getErrorStatsRedisTopTypes(befly, bucketDate);
|
|
84
|
-
let recent30Count = 0;
|
|
85
|
-
|
|
86
|
-
for (const item of days) {
|
|
87
|
-
recent30Count += item.count;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (todaySummary.count <= 0 && yesterdaySummary.count <= 0 && dayBeforeYesterdaySummary.count <= 0 && weekSummary.count <= 0 && monthSummary.count <= 0 && recent30Count <= 0 && trend.length === 0 && topTypes.length === 0) {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
|
|
71
|
+
function buildErrorStatsResponse(bucketDate, weekStartDate, monthStartDate, recentDateList, todaySummary, yesterdaySummary, dayBeforeYesterdaySummary, weekSummary, monthSummary, recent30Count, trend, days, topTypes) {
|
|
94
72
|
return {
|
|
95
73
|
today: {
|
|
96
74
|
bucketDate: bucketDate,
|
|
97
75
|
count: todaySummary.count
|
|
98
76
|
},
|
|
99
77
|
yesterday: {
|
|
100
|
-
bucketDate:
|
|
78
|
+
bucketDate: recentDateList[recentDateList.length - 2] || bucketDate,
|
|
101
79
|
count: yesterdaySummary.count
|
|
102
80
|
},
|
|
103
81
|
dayBeforeYesterday: {
|
|
104
|
-
bucketDate:
|
|
82
|
+
bucketDate: recentDateList[recentDateList.length - 3] || recentDateList[recentDateList.length - 2] || bucketDate,
|
|
105
83
|
count: dayBeforeYesterdaySummary.count
|
|
106
84
|
},
|
|
107
85
|
week: {
|
|
@@ -125,12 +103,131 @@ async function getErrorStatsFromRedis(befly, bucketDate, weekStartDate, monthSta
|
|
|
125
103
|
};
|
|
126
104
|
}
|
|
127
105
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
106
|
+
function isRedisResultEmpty(todaySummary, yesterdaySummary, dayBeforeYesterdaySummary, weekSummary, monthSummary, recent30Count, trend, topTypes) {
|
|
107
|
+
return todaySummary.count <= 0 && yesterdaySummary.count <= 0 && dayBeforeYesterdaySummary.count <= 0 && weekSummary.count <= 0 && monthSummary.count <= 0 && recent30Count <= 0 && trend.length === 0 && topTypes.length === 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function getErrorStatsFromRedis(befly, bucketDate, weekStartDate, monthStartDate, recentDateList) {
|
|
111
|
+
const [todaySummary, yesterdaySummary, dayBeforeYesterdaySummary, weekSummary, monthSummary, trend, days, topTypes] = await Promise.all([
|
|
112
|
+
getErrorStatsRedisSummary(befly, "day", bucketDate),
|
|
113
|
+
getErrorStatsRedisSummary(befly, "day", recentDateList[recentDateList.length - 2] || bucketDate),
|
|
114
|
+
getErrorStatsRedisSummary(befly, "day", recentDateList[recentDateList.length - 3] || recentDateList[recentDateList.length - 2] || bucketDate),
|
|
115
|
+
getErrorStatsRedisSummary(befly, "week", weekStartDate),
|
|
116
|
+
getErrorStatsRedisSummary(befly, "month", monthStartDate),
|
|
117
|
+
getErrorStatsRedisTrend(befly, bucketDate),
|
|
118
|
+
getErrorStatsRedisDays(befly, recentDateList),
|
|
119
|
+
getErrorStatsRedisTopTypes(befly, bucketDate)
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
const recent30Count = sumCounts(days);
|
|
123
|
+
|
|
124
|
+
if (isRedisResultEmpty(todaySummary, yesterdaySummary, dayBeforeYesterdaySummary, weekSummary, monthSummary, recent30Count, trend, topTypes)) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return buildErrorStatsResponse(bucketDate, weekStartDate, monthStartDate, recentDateList, todaySummary, yesterdaySummary, dayBeforeYesterdaySummary, weekSummary, monthSummary, recent30Count, trend, days, topTypes);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function getErrorStatsDayCountMap(befly, startDate, endDate) {
|
|
132
|
+
const result = await befly.mysql.execute("SELECT bucket_date as bucketDate, SUM(hit_count) as count FROM befly_error_report WHERE state = 1 AND bucket_date BETWEEN ? AND ? GROUP BY bucket_date", [startDate, endDate]);
|
|
133
|
+
const map = new Map();
|
|
134
|
+
|
|
135
|
+
for (const item of result.data || []) {
|
|
136
|
+
map.set(Number(item.bucketDate), getTongJiNumber(item.count));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return map;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function sumDateCounts(map, dateList) {
|
|
143
|
+
return dateList.reduce((sum, date) => sum + (map.get(date) || 0), 0);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function getErrorStatsFromMysql(befly, bucketDate, weekStartDate, monthStartDate, recentDateList) {
|
|
147
|
+
const yesterdayDate = recentDateList[recentDateList.length - 2] || bucketDate;
|
|
148
|
+
const dayBeforeYesterdayDate = recentDateList[recentDateList.length - 3] || yesterdayDate;
|
|
149
|
+
const weekDateList = getTongJiDateRangeList(weekStartDate, bucketDate);
|
|
150
|
+
const monthDateList = getTongJiDateRangeList(monthStartDate, bucketDate);
|
|
151
|
+
|
|
152
|
+
const [dayCountMap, trendRes, topTypesRes] = await Promise.all([
|
|
153
|
+
getErrorStatsDayCountMap(befly, recentDateList[0], bucketDate),
|
|
154
|
+
befly.mysql.execute("SELECT bucket_time as bucketTime, bucket_date as bucketDate, SUM(hit_count) as count FROM befly_error_report WHERE state = 1 AND bucket_date = ? GROUP BY bucket_time, bucket_date ORDER BY bucket_time ASC", [bucketDate]),
|
|
155
|
+
befly.mysql.execute("SELECT error_type as errorType, SUM(hit_count) as count FROM befly_error_report WHERE state = 1 AND bucket_date = ? GROUP BY error_type ORDER BY count DESC LIMIT 5", [bucketDate])
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
const todaySummary = { count: dayCountMap.get(bucketDate) || 0 };
|
|
159
|
+
const yesterdaySummary = { count: dayCountMap.get(yesterdayDate) || 0 };
|
|
160
|
+
const dayBeforeYesterdaySummary = { count: dayCountMap.get(dayBeforeYesterdayDate) || 0 };
|
|
161
|
+
const weekSummary = { count: sumDateCounts(dayCountMap, weekDateList) };
|
|
162
|
+
const monthSummary = { count: sumDateCounts(dayCountMap, monthDateList) };
|
|
163
|
+
const recent30Count = sumDateCounts(dayCountMap, recentDateList);
|
|
164
|
+
|
|
165
|
+
const trend = (trendRes.data || []).map((item) => {
|
|
166
|
+
return {
|
|
167
|
+
bucketTime: getTongJiNumber(item.bucketTime),
|
|
168
|
+
bucketDate: getTongJiNumber(item.bucketDate),
|
|
169
|
+
count: getTongJiNumber(item.count)
|
|
170
|
+
};
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const topTypes = (topTypesRes.data || []).map((item) => {
|
|
174
|
+
return {
|
|
175
|
+
errorType: String(item.errorType || "unknown"),
|
|
176
|
+
count: getTongJiNumber(item.count)
|
|
177
|
+
};
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const days = recentDateList.map((date) => {
|
|
181
|
+
return {
|
|
182
|
+
bucketDate: date,
|
|
183
|
+
count: dayCountMap.get(date) || 0
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return buildErrorStatsResponse(bucketDate, weekStartDate, monthStartDate, recentDateList, todaySummary, yesterdaySummary, dayBeforeYesterdaySummary, weekSummary, monthSummary, recent30Count, trend, days, topTypes);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function buildEmptyDays(recentDateList) {
|
|
191
|
+
return recentDateList.map((date) => {
|
|
192
|
+
return {
|
|
193
|
+
bucketDate: date,
|
|
194
|
+
count: 0
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
}
|
|
131
198
|
|
|
199
|
+
function buildEmptyErrorStats(bucketDate, weekStartDate, monthStartDate, recentDateList) {
|
|
132
200
|
return {
|
|
133
|
-
|
|
201
|
+
today: {
|
|
202
|
+
bucketDate: bucketDate,
|
|
203
|
+
count: 0
|
|
204
|
+
},
|
|
205
|
+
yesterday: {
|
|
206
|
+
bucketDate: recentDateList[recentDateList.length - 2] || bucketDate,
|
|
207
|
+
count: 0
|
|
208
|
+
},
|
|
209
|
+
dayBeforeYesterday: {
|
|
210
|
+
bucketDate: recentDateList[recentDateList.length - 3] || recentDateList[recentDateList.length - 2] || bucketDate,
|
|
211
|
+
count: 0
|
|
212
|
+
},
|
|
213
|
+
week: {
|
|
214
|
+
startDate: weekStartDate,
|
|
215
|
+
endDate: bucketDate,
|
|
216
|
+
count: 0
|
|
217
|
+
},
|
|
218
|
+
month: {
|
|
219
|
+
startDate: monthStartDate,
|
|
220
|
+
endDate: bucketDate,
|
|
221
|
+
count: 0
|
|
222
|
+
},
|
|
223
|
+
recent30: {
|
|
224
|
+
startDate: recentDateList[0],
|
|
225
|
+
endDate: bucketDate,
|
|
226
|
+
count: 0
|
|
227
|
+
},
|
|
228
|
+
trend: [],
|
|
229
|
+
days: buildEmptyDays(recentDateList),
|
|
230
|
+
topTypes: []
|
|
134
231
|
};
|
|
135
232
|
}
|
|
136
233
|
|
|
@@ -149,51 +246,9 @@ export default {
|
|
|
149
246
|
const weekStartDate = getTongJiWeekStartDate(now);
|
|
150
247
|
const monthStartDate = getTongJiMonthStartDate(now);
|
|
151
248
|
const recentDateList = getTongJiRecentDateList(now, ERROR_STATS_DAY_LIMIT);
|
|
152
|
-
const yesterdayDate = recentDateList[recentDateList.length - 2] || bucketDate;
|
|
153
|
-
const dayBeforeYesterdayDate = recentDateList[recentDateList.length - 3] || yesterdayDate;
|
|
154
249
|
|
|
155
250
|
if (!tableReady) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
for (const item of recentDateList) {
|
|
159
|
-
days.push({
|
|
160
|
-
bucketDate: item,
|
|
161
|
-
count: 0
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return befly.tool.Yes("获取成功", {
|
|
166
|
-
today: {
|
|
167
|
-
bucketDate: bucketDate,
|
|
168
|
-
count: 0
|
|
169
|
-
},
|
|
170
|
-
yesterday: {
|
|
171
|
-
bucketDate: yesterdayDate,
|
|
172
|
-
count: 0
|
|
173
|
-
},
|
|
174
|
-
dayBeforeYesterday: {
|
|
175
|
-
bucketDate: dayBeforeYesterdayDate,
|
|
176
|
-
count: 0
|
|
177
|
-
},
|
|
178
|
-
week: {
|
|
179
|
-
startDate: weekStartDate,
|
|
180
|
-
endDate: bucketDate,
|
|
181
|
-
count: 0
|
|
182
|
-
},
|
|
183
|
-
month: {
|
|
184
|
-
startDate: monthStartDate,
|
|
185
|
-
endDate: bucketDate,
|
|
186
|
-
count: 0
|
|
187
|
-
},
|
|
188
|
-
recent30: {
|
|
189
|
-
startDate: recentDateList[0],
|
|
190
|
-
endDate: bucketDate,
|
|
191
|
-
count: 0
|
|
192
|
-
},
|
|
193
|
-
trend: [],
|
|
194
|
-
days: days,
|
|
195
|
-
topTypes: []
|
|
196
|
-
});
|
|
251
|
+
return befly.tool.Yes("获取成功", buildEmptyErrorStats(bucketDate, weekStartDate, monthStartDate, recentDateList));
|
|
197
252
|
}
|
|
198
253
|
|
|
199
254
|
if (befly.redis) {
|
|
@@ -204,88 +259,6 @@ export default {
|
|
|
204
259
|
}
|
|
205
260
|
}
|
|
206
261
|
|
|
207
|
-
|
|
208
|
-
const yesterdaySummary = await getErrorStatsSummary(befly, yesterdayDate, yesterdayDate);
|
|
209
|
-
const dayBeforeYesterdaySummary = await getErrorStatsSummary(befly, dayBeforeYesterdayDate, dayBeforeYesterdayDate);
|
|
210
|
-
const weekSummary = await getErrorStatsSummary(befly, weekStartDate, bucketDate);
|
|
211
|
-
const monthSummary = await getErrorStatsSummary(befly, monthStartDate, bucketDate);
|
|
212
|
-
const recent30Summary = await getErrorStatsSummary(befly, recentDateList[0], bucketDate);
|
|
213
|
-
const trendRes = await befly.mysql.execute("SELECT bucket_time as bucketTime, bucket_date as bucketDate, SUM(hit_count) as count FROM befly_error_report WHERE state = 1 AND bucket_date = ? GROUP BY bucket_time, bucket_date ORDER BY bucket_time ASC", [bucketDate]);
|
|
214
|
-
const daysRes = await befly.mysql.execute("SELECT bucket_date as bucketDate, SUM(hit_count) as count FROM befly_error_report WHERE state = 1 AND bucket_date >= ? GROUP BY bucket_date ORDER BY bucket_date ASC", [recentDateList[0]]);
|
|
215
|
-
const topTypesRes = await befly.mysql.execute("SELECT error_type as errorType, SUM(hit_count) as count FROM befly_error_report WHERE state = 1 AND bucket_date = ? GROUP BY error_type ORDER BY count DESC LIMIT 5", [bucketDate]);
|
|
216
|
-
|
|
217
|
-
const trend = [];
|
|
218
|
-
for (const item of trendRes.data || []) {
|
|
219
|
-
trend.push({
|
|
220
|
-
bucketTime: getTongJiNumber(item.bucketTime),
|
|
221
|
-
bucketDate: getTongJiNumber(item.bucketDate),
|
|
222
|
-
count: getTongJiNumber(item.count)
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const daysMap = new Map();
|
|
227
|
-
|
|
228
|
-
for (const item of recentDateList) {
|
|
229
|
-
daysMap.set(item, {
|
|
230
|
-
bucketDate: item,
|
|
231
|
-
count: 0
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
for (const item of daysRes.data || []) {
|
|
236
|
-
const itemBucketDate = getTongJiNumber(item.bucketDate);
|
|
237
|
-
|
|
238
|
-
if (!daysMap.has(itemBucketDate)) {
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
daysMap.set(itemBucketDate, {
|
|
243
|
-
bucketDate: itemBucketDate,
|
|
244
|
-
count: getTongJiNumber(item.count)
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const days = Array.from(daysMap.values());
|
|
249
|
-
|
|
250
|
-
const topTypes = [];
|
|
251
|
-
for (const item of topTypesRes.data || []) {
|
|
252
|
-
topTypes.push({
|
|
253
|
-
errorType: String(item.errorType || "unknown"),
|
|
254
|
-
count: getTongJiNumber(item.count)
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return befly.tool.Yes("获取成功", {
|
|
259
|
-
today: {
|
|
260
|
-
bucketDate: bucketDate,
|
|
261
|
-
count: todaySummary.count
|
|
262
|
-
},
|
|
263
|
-
yesterday: {
|
|
264
|
-
bucketDate: yesterdayDate,
|
|
265
|
-
count: yesterdaySummary.count
|
|
266
|
-
},
|
|
267
|
-
dayBeforeYesterday: {
|
|
268
|
-
bucketDate: dayBeforeYesterdayDate,
|
|
269
|
-
count: dayBeforeYesterdaySummary.count
|
|
270
|
-
},
|
|
271
|
-
week: {
|
|
272
|
-
startDate: weekStartDate,
|
|
273
|
-
endDate: bucketDate,
|
|
274
|
-
count: weekSummary.count
|
|
275
|
-
},
|
|
276
|
-
month: {
|
|
277
|
-
startDate: monthStartDate,
|
|
278
|
-
endDate: bucketDate,
|
|
279
|
-
count: monthSummary.count
|
|
280
|
-
},
|
|
281
|
-
recent30: {
|
|
282
|
-
startDate: recentDateList[0],
|
|
283
|
-
endDate: bucketDate,
|
|
284
|
-
count: recent30Summary.count
|
|
285
|
-
},
|
|
286
|
-
trend: trend,
|
|
287
|
-
days: days,
|
|
288
|
-
topTypes: topTypes
|
|
289
|
-
});
|
|
262
|
+
return befly.tool.Yes("获取成功", await getErrorStatsFromMysql(befly, bucketDate, weekStartDate, monthStartDate, recentDateList));
|
|
290
263
|
}
|
|
291
264
|
};
|
package/checks/config.js
CHANGED
|
@@ -12,7 +12,7 @@ const noTrimString = z.string().refine(isNoTrimStringAllowEmpty, "不允许首
|
|
|
12
12
|
const beflyModeSchema = z.union([z.literal("manual"), z.literal("auto")]);
|
|
13
13
|
const uploadExtensionListSchema = noTrimString.regex(/^\.[a-z0-9]+(?:,\.[a-z0-9]+)*$/);
|
|
14
14
|
const uploadMimeTypeListSchema = noTrimString.regex(/^[a-z0-9][a-z0-9.+-]*\/[a-z0-9][a-z0-9.+-]*(?:,[a-z0-9][a-z0-9.+-]*\/[a-z0-9][a-z0-9.+-]*)*$/);
|
|
15
|
-
const projectListCodeSchema = z.string().regex(/^[a-
|
|
15
|
+
const projectListCodeSchema = z.string().regex(/^[a-zA-Z][a-zA-Z0-9_-]*$/, "必须以字母开头,只允许字母、数字、短横线、下划线");
|
|
16
16
|
const projectListItemSchema = z
|
|
17
17
|
.object({
|
|
18
18
|
code: projectListCodeSchema,
|
package/package.json
CHANGED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { addDays, getDateYmdNumber, getDayStartTime } from "#befly/utils/datetime.js";
|
|
2
|
-
import { isValidPositiveInt } from "#befly/utils/is.js";
|
|
3
|
-
|
|
4
|
-
import { expireTongJiRedisKeys, getTongJiMonthStartDate, getVisitStatsDayMembersKey, getVisitStatsDayProductMembersKey, getVisitStatsMonthMembersKey, getVisitStatsMonthProductMembersKey, getVisitStatsRecentMembersKey, getVisitStatsRecentProductMembersKey } from "./_tongJi.js";
|
|
5
|
-
|
|
6
|
-
const VISIT_STATS_REDIS_TTL_SECONDS = 45 * 24 * 60 * 60;
|
|
7
|
-
|
|
8
|
-
function getVisitStatsMember(ctx) {
|
|
9
|
-
if (isValidPositiveInt(ctx?.userId)) {
|
|
10
|
-
return `user:${ctx.userId}`;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return `ip:${ctx?.ip || "unknown"}`;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async function addRecentVisitMember(befly, key, member, now) {
|
|
17
|
-
const cutoffTime = getDayStartTime(addDays(now, -29));
|
|
18
|
-
|
|
19
|
-
await befly.redis.zadd(key, [
|
|
20
|
-
{
|
|
21
|
-
score: now,
|
|
22
|
-
member: member
|
|
23
|
-
}
|
|
24
|
-
]);
|
|
25
|
-
await befly.redis.zremrangebyscore(key, "-inf", cutoffTime - 1);
|
|
26
|
-
await befly.redis.expire(key, VISIT_STATS_REDIS_TTL_SECONDS);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function updateVisitStatsRedis(befly, now, reportDate, member, productCode) {
|
|
30
|
-
const monthStartDate = getTongJiMonthStartDate(now);
|
|
31
|
-
const dayKey = getVisitStatsDayMembersKey(reportDate);
|
|
32
|
-
const monthKey = getVisitStatsMonthMembersKey(monthStartDate);
|
|
33
|
-
const recentKey = getVisitStatsRecentMembersKey();
|
|
34
|
-
const dayAdded = await befly.redis.sadd(dayKey, [member]);
|
|
35
|
-
|
|
36
|
-
await befly.redis.sadd(monthKey, [member]);
|
|
37
|
-
await addRecentVisitMember(befly, recentKey, member, now);
|
|
38
|
-
await expireTongJiRedisKeys(befly, [dayKey, monthKey], VISIT_STATS_REDIS_TTL_SECONDS);
|
|
39
|
-
|
|
40
|
-
if (productCode) {
|
|
41
|
-
const dayProductKey = getVisitStatsDayProductMembersKey(reportDate, productCode);
|
|
42
|
-
const monthProductKey = getVisitStatsMonthProductMembersKey(monthStartDate, productCode);
|
|
43
|
-
const recentProductKey = getVisitStatsRecentProductMembersKey(productCode);
|
|
44
|
-
|
|
45
|
-
await befly.redis.sadd(dayProductKey, [member]);
|
|
46
|
-
await befly.redis.sadd(monthProductKey, [member]);
|
|
47
|
-
await addRecentVisitMember(befly, recentProductKey, member, now);
|
|
48
|
-
await expireTongJiRedisKeys(befly, [dayProductKey, monthProductKey], VISIT_STATS_REDIS_TTL_SECONDS);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return dayAdded > 0;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export default {
|
|
55
|
-
name: "上报独立访客统计",
|
|
56
|
-
method: "POST",
|
|
57
|
-
body: "none",
|
|
58
|
-
auth: false,
|
|
59
|
-
fields: {
|
|
60
|
-
pagePath: { name: "页面路径", input: "string", min: 0, max: 200 },
|
|
61
|
-
pageName: { name: "页面名称", input: "string", min: 0, max: 100 },
|
|
62
|
-
source: { name: "来源", input: "string", min: 0, max: 50 },
|
|
63
|
-
productName: { name: "产品名称", input: "string", min: 0, max: 100 },
|
|
64
|
-
productCode: { name: "产品代号", input: "string", min: 0, max: 100 },
|
|
65
|
-
productVersion: { name: "产品版本", input: "string", min: 0, max: 100 },
|
|
66
|
-
detail: { name: "扩展详情", input: "string", min: 0, max: 1000 }
|
|
67
|
-
},
|
|
68
|
-
required: [],
|
|
69
|
-
handler: async (befly, ctx) => {
|
|
70
|
-
const now = Date.now();
|
|
71
|
-
const reportDate = getDateYmdNumber(now);
|
|
72
|
-
|
|
73
|
-
if (!befly.redis) {
|
|
74
|
-
return befly.tool.Yes("上报成功", {
|
|
75
|
-
reportTime: now,
|
|
76
|
-
reportDate: reportDate,
|
|
77
|
-
counted: false,
|
|
78
|
-
stored: false
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const counted = await updateVisitStatsRedis(befly, now, reportDate, getVisitStatsMember(ctx), ctx.body?.productCode || "");
|
|
83
|
-
|
|
84
|
-
return befly.tool.Yes("上报成功", {
|
|
85
|
-
reportTime: now,
|
|
86
|
-
reportDate: reportDate,
|
|
87
|
-
counted: counted,
|
|
88
|
-
stored: true
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
};
|