🎉 first commit
This commit is contained in:
46
app/routes/api.deployments.$action/cache.ts
Normal file
46
app/routes/api.deployments.$action/cache.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
interface CacheItem {
|
||||
data: any;
|
||||
expiry: number;
|
||||
}
|
||||
|
||||
const cache: Record<string, CacheItem> = {};
|
||||
|
||||
// 1 分钟缓存时间
|
||||
const CACHE_TTL = 1 * 60 * 1000;
|
||||
|
||||
export function getFromCache(key: string): any | null {
|
||||
const item = cache[key];
|
||||
if (!item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Date.now() > item.expiry) {
|
||||
delete cache[key];
|
||||
return null;
|
||||
}
|
||||
|
||||
return item.data;
|
||||
}
|
||||
|
||||
export function setCache(key: string, data: any): void {
|
||||
cache[key] = {
|
||||
data,
|
||||
expiry: Date.now() + CACHE_TTL,
|
||||
};
|
||||
}
|
||||
|
||||
export function clearCache(key: string): void {
|
||||
delete cache[key];
|
||||
}
|
||||
|
||||
setInterval(
|
||||
() => {
|
||||
const now = Date.now();
|
||||
for (const key in cache) {
|
||||
if (cache[key].expiry < now) {
|
||||
delete cache[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
60 * 60 * 1000,
|
||||
);
|
||||
23
app/routes/api.deployments.$action/route.tsx
Normal file
23
app/routes/api.deployments.$action/route.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { type LoaderFunctionArgs } from '@remix-run/node';
|
||||
import { requireAuth } from '~/lib/.server/auth';
|
||||
import { errorResponse } from '~/utils/api-response';
|
||||
import { getDeploymentStats } from './stats.server';
|
||||
|
||||
export async function loader({ request, params }: LoaderFunctionArgs) {
|
||||
const authResult = await requireAuth(request, { isApi: true });
|
||||
if (authResult instanceof Response) {
|
||||
return authResult;
|
||||
}
|
||||
|
||||
const userId = authResult.userInfo?.sub;
|
||||
if (!userId) {
|
||||
return errorResponse(401, '用户未登录');
|
||||
}
|
||||
|
||||
switch (params.action) {
|
||||
case 'stats':
|
||||
return getDeploymentStats({ userId });
|
||||
default:
|
||||
return errorResponse(404, `未知的 API 操作: ${params.action}`);
|
||||
}
|
||||
}
|
||||
45
app/routes/api.deployments.$action/stats.server.ts
Normal file
45
app/routes/api.deployments.$action/stats.server.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { prisma } from '~/lib/.server/prisma';
|
||||
import { errorResponse, successResponse } from '~/utils/api-response';
|
||||
import { createScopedLogger } from '~/utils/logger';
|
||||
|
||||
const logger = createScopedLogger('api.deployments.stats');
|
||||
|
||||
export type GetDeploymentStatsArgs = {
|
||||
userId: string;
|
||||
};
|
||||
|
||||
export async function getDeploymentStats({ userId }: GetDeploymentStatsArgs) {
|
||||
try {
|
||||
const totalSites = await prisma.deployment.count({
|
||||
where: { userId },
|
||||
});
|
||||
|
||||
const platformStats = await prisma.deployment.groupBy({
|
||||
by: ['platform'],
|
||||
_count: {
|
||||
id: true,
|
||||
},
|
||||
where: { userId },
|
||||
});
|
||||
|
||||
const sitesByPlatform = platformStats.reduce(
|
||||
(acc, stat) => {
|
||||
acc[stat.platform] = stat._count.id;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, number>,
|
||||
);
|
||||
|
||||
return successResponse(
|
||||
{
|
||||
totalSites,
|
||||
sitesByPlatform,
|
||||
totalDays: 30,
|
||||
},
|
||||
'获取部署统计数据成功',
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error('获取部署统计数据失败:', error);
|
||||
return errorResponse(500, error instanceof Error ? error.message : '获取部署统计数据失败');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user