Files
upage-git/app/lib/hooks/useDeploymentRecords.ts
2025-09-24 17:02:44 +08:00

229 lines
6.4 KiB
TypeScript

import { useRevalidator } from '@remix-run/react';
import { useCallback, useState } from 'react';
import type { DeploymentPlatform } from '~/types/deployment';
import { DeploymentPlatformEnum } from '~/types/deployment';
import { useAuth } from './useAuth';
export interface DeploymentRecord {
id: string;
userId: string;
chatId: string;
platform: string;
deploymentId: string;
url: string;
status: string;
metadata?: Record<string, any>;
createdAt: string;
updatedAt: string;
chat?: {
id: string;
description: string | null;
};
}
export interface DeploymentStats {
totalSites: number;
totalDays: number;
totalVisits: number;
totalBytes?: number;
lastAccess?: string | null;
sitesByPlatform?: Record<string, number>;
}
const platformEndpoints: Record<string, string> = {
[DeploymentPlatformEnum._1PANEL]: '/api/1panel',
[DeploymentPlatformEnum.NETLIFY]: '/api/netlify',
[DeploymentPlatformEnum.VERCEL]: '/api/vercel',
};
function getPlatformEndpoint(platform: string, action: string): string {
const baseEndpoint = platformEndpoints[platform];
if (!baseEndpoint) {
throw new Error(`不支持的平台: ${platform}`);
}
return `${baseEndpoint}/${action}`;
}
export function useDeploymentRecords() {
const { revalidate } = useRevalidator();
const { userInfo, isAuthenticated } = useAuth();
const [deploymentRecords, setDeploymentRecords] = useState<Record<string, DeploymentRecord[]>>({});
const [totals, setTotals] = useState<Record<string, number>>({});
const [isLoading, setIsLoading] = useState<boolean>(false);
const [loadingPlatforms, setLoadingPlatforms] = useState<Record<string, boolean>>({});
const [stats, setStats] = useState<DeploymentStats>({
totalSites: 0,
totalDays: 30,
totalVisits: 0,
sitesByPlatform: {},
});
const loadPlatformRecords = useCallback(
async ({ offset = 0, limit = 10, platform }: { offset?: number; limit?: number; platform: DeploymentPlatform }) => {
if (!isAuthenticated || !userInfo?.sub) {
return;
}
if (platform) {
setLoadingPlatforms((prev) => ({ ...prev, [platform]: true }));
}
try {
const response = await fetch(`/api/deployments?offset=${offset}&limit=${limit}&platform=${platform}`);
if (!response.ok) {
throw new Error('Failed to fetch deployment records');
}
const responseData = await response.json();
if (!responseData.success) {
return;
}
const { deployments } = responseData.data;
setDeploymentRecords((prev) => ({
...prev,
[platform]: offset === 0 ? deployments : [...(prev[platform] || []), ...deployments],
}));
setTotals((prev) => ({
...prev,
[platform]: offset === 0 ? deployments.length : prev[platform] + deployments.length,
}));
} catch (error) {
console.error('Error loading deployment records:', error);
} finally {
if (platform) {
setLoadingPlatforms((prev) => ({ ...prev, [platform]: false }));
}
}
},
[isAuthenticated, userInfo],
);
const loadStats = useCallback(async () => {
if (!isAuthenticated || !userInfo?.sub) {
return;
}
setIsLoading(true);
try {
setStats({
totalSites: 0,
totalDays: 30,
totalVisits: 0,
sitesByPlatform: {},
});
const response = await fetch('/api/deployments/stats');
if (response.ok) {
const responseData = await response.json();
if (!responseData.success) {
return;
}
const data = responseData.data;
setStats((prev) => ({
...prev,
totalSites: data.totalSites || 0,
totalDays: data.totalDays || 30,
totalVisits: data.totalVisits || 0,
totalBytes: data.totalBytes || 0,
lastAccess: data.lastAccess || null,
sitesByPlatform: data.sitesByPlatform || {},
}));
if (data.sitesByPlatform) {
setTotals((prev) => ({
...prev,
...data.sitesByPlatform,
}));
}
}
} catch (error) {
console.error('Error loading deployment stats:', error);
} finally {
setIsLoading(false);
}
}, [isAuthenticated, userInfo]);
const refreshDeploymentRecords = useCallback(() => {
loadStats();
for (const platform of Object.values(DeploymentPlatformEnum)) {
loadPlatformRecords({ platform });
}
}, [loadStats, loadPlatformRecords]);
const toggleAccess = useCallback(
async (id: string, platform: string) => {
try {
const endpoint = getPlatformEndpoint(platform, 'toggle-access');
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ id }),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || '操作失败');
}
const responseData = await response.json();
if (!responseData.success) {
throw new Error(responseData.message || '操作失败');
}
return responseData.data;
} catch (error) {
console.error('切换访问状态失败:', error);
throw error;
}
},
[isAuthenticated, userInfo],
);
const deletePage = useCallback(async (id: string, platform: string) => {
try {
const endpoint = getPlatformEndpoint(platform, 'delete');
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ id }),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || '删除失败');
}
const responseData = await response.json();
if (!responseData.success) {
throw new Error(responseData.message || '删除失败');
}
revalidate();
return responseData.data;
} catch (error) {
console.error('删除部署失败:', error);
throw error;
}
}, []);
return {
deploymentRecords,
totals,
stats,
isLoading,
loadingPlatforms,
loadPlatformRecords,
refreshDeploymentRecords,
isPlatformLoading: (platform: string) => loadingPlatforms[platform] || false,
toggleAccess,
deletePage,
};
}