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.
@@ -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
- for (const bucketTime of bucketSet) {
18
- const itemBucketTime = getTongJiNumber(bucketTime);
19
+ const trend = await Promise.all(
20
+ bucketSet.map(async (bucketTime) => {
21
+ const itemBucketTime = getTongJiNumber(bucketTime);
19
22
 
20
- trend.push({
21
- bucketTime: itemBucketTime,
22
- bucketDate: bucketDate,
23
- count: getTongJiNumber(await befly.redis.getString(getErrorStatsDayBucketCountKey(bucketDate, itemBucketTime)))
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
- const days = [];
33
-
34
- for (const item of recentDateList) {
35
- days.push({
36
- bucketDate: item,
37
- count: getTongJiNumber(await befly.redis.getString(getErrorStatsPeriodCountKey("day", item)))
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
- for (const errorType of typeSet) {
49
- const name = String(errorType || "unknown");
50
- const count = getTongJiNumber(await befly.redis.getString(getErrorStatsDayTypeCountKey(bucketDate, name)));
51
-
52
- if (count <= 0) {
53
- continue;
54
- }
55
-
56
- topTypes.push({
57
- errorType: name,
58
- count: count
59
- });
60
- }
61
-
62
- topTypes.sort((a, b) => {
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
- return topTypes.slice(0, 5);
66
+ return String(a.errorType).localeCompare(String(b.errorType), "zh-CN");
67
+ })
68
+ .slice(0, 5);
71
69
  }
72
70
 
73
- async function getErrorStatsFromRedis(befly, bucketDate, weekStartDate, monthStartDate, recentDateList) {
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: yesterdayDate,
78
+ bucketDate: recentDateList[recentDateList.length - 2] || bucketDate,
101
79
  count: yesterdaySummary.count
102
80
  },
103
81
  dayBeforeYesterday: {
104
- bucketDate: dayBeforeYesterdayDate,
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
- async function getErrorStatsSummary(befly, startDate, endDate) {
129
- const result = await befly.mysql.execute("SELECT SUM(hit_count) as count FROM befly_error_report WHERE state = 1 AND bucket_date BETWEEN ? AND ?", [startDate, endDate]);
130
- const detail = result.data?.[0] || {};
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
- count: getTongJiNumber(detail.count)
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
- const days = [];
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
- const todaySummary = await getErrorStatsSummary(befly, bucketDate, bucketDate);
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-z][a-zA-Z0-9]*$/, "必须是小驼峰命名");
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,6 +1,6 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "3.56.0",
3
+ "version": "3.58.0",
4
4
  "gitHead": "49c39d36695036e85fc64083cc43c1652fff96cb",
5
5
  "private": false,
6
6
  "description": "Befly - 为 Bun 专属打造的 JavaScript API 接口框架核心引擎",
@@ -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
- };