157 lines
5.1 KiB
TypeScript
157 lines
5.1 KiB
TypeScript
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
|
|
import type {
|
|
CreateProjectRequest,
|
|
Project,
|
|
ProjectListResponse,
|
|
ProjectResponse,
|
|
ProjectStatus,
|
|
UpdateProjectRequest,
|
|
} from "../../../shared/api";
|
|
|
|
import { handleResponse, handleVoidResponse } from "../utils/api";
|
|
import { createConsoleLogger } from "../utils/logger";
|
|
|
|
const PROJECTS_KEY = ["projects"] as const;
|
|
const logger = createConsoleLogger();
|
|
|
|
export async function archiveProject(id: string): Promise<Project> {
|
|
const response = await fetch(`/api/projects/${id}/archive`, { method: "POST" });
|
|
return handleResponse(response, (data) => (data as ProjectResponse).project);
|
|
}
|
|
|
|
export async function createProject(data: CreateProjectRequest): Promise<Project> {
|
|
const response = await fetch("/api/projects", {
|
|
body: JSON.stringify(data),
|
|
headers: { "Content-Type": "application/json" },
|
|
method: "POST",
|
|
});
|
|
return handleResponse(response, (data) => (data as ProjectResponse).project);
|
|
}
|
|
|
|
export async function deleteProject(id: string): Promise<void> {
|
|
const response = await fetch(`/api/projects/${id}`, { method: "DELETE" });
|
|
return handleVoidResponse(response);
|
|
}
|
|
|
|
export async function fetchProject(id: string): Promise<Project> {
|
|
const response = await fetch(`/api/projects/${id}`);
|
|
return handleResponse(response, (data) => (data as ProjectResponse).project);
|
|
}
|
|
|
|
export async function fetchProjectList(params: {
|
|
keyword?: string;
|
|
page?: number;
|
|
pageSize?: number;
|
|
sortBy?: string;
|
|
sortOrder?: string;
|
|
status?: ProjectStatus;
|
|
}): Promise<ProjectListResponse> {
|
|
const searchParams = new URLSearchParams();
|
|
if (params.page) searchParams.set("page", String(params.page));
|
|
if (params.pageSize) searchParams.set("pageSize", String(params.pageSize));
|
|
if (params.keyword) searchParams.set("keyword", params.keyword);
|
|
if (params.sortBy) searchParams.set("sortBy", params.sortBy);
|
|
if (params.sortOrder) searchParams.set("sortOrder", params.sortOrder);
|
|
if (params.status) searchParams.set("status", params.status);
|
|
const qs = searchParams.toString();
|
|
const url = `/api/projects${qs ? `?${qs}` : ""}`;
|
|
const response = await fetch(url);
|
|
if (!response.ok) {
|
|
const body = (await response.json().catch(() => null)) as null | { error?: string };
|
|
throw new Error(body?.error ?? `HTTP ${response.status}`);
|
|
}
|
|
return response.json() as Promise<ProjectListResponse>;
|
|
}
|
|
|
|
export async function restoreProject(id: string): Promise<Project> {
|
|
const response = await fetch(`/api/projects/${id}/restore`, { method: "POST" });
|
|
return handleResponse(response, (data) => (data as ProjectResponse).project);
|
|
}
|
|
|
|
export async function updateProject(id: string, data: UpdateProjectRequest): Promise<Project> {
|
|
const response = await fetch(`/api/projects/${id}`, {
|
|
body: JSON.stringify(data),
|
|
headers: { "Content-Type": "application/json" },
|
|
method: "PATCH",
|
|
});
|
|
return handleResponse(response, (data) => (data as ProjectResponse).project);
|
|
}
|
|
|
|
export function useArchiveProject() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: archiveProject,
|
|
onSuccess: (data) => {
|
|
logger.info("项目归档成功", { name: data.name, projectId: data.id });
|
|
void queryClient.invalidateQueries({ queryKey: PROJECTS_KEY });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useCreateProject() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: createProject,
|
|
onSuccess: (data) => {
|
|
logger.info("项目创建成功", { name: data.name, projectId: data.id });
|
|
void queryClient.invalidateQueries({ queryKey: PROJECTS_KEY });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useDeleteProject() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: deleteProject,
|
|
onSuccess: (_data, variables) => {
|
|
logger.info("项目删除成功", { projectId: variables });
|
|
void queryClient.invalidateQueries({ queryKey: PROJECTS_KEY });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useProject(id: string) {
|
|
return useQuery({
|
|
enabled: !!id,
|
|
queryFn: () => fetchProject(id),
|
|
queryKey: [...PROJECTS_KEY, "detail", id],
|
|
});
|
|
}
|
|
|
|
export function useProjectList(params: {
|
|
keyword?: string;
|
|
page?: number;
|
|
pageSize?: number;
|
|
sortBy?: string;
|
|
sortOrder?: string;
|
|
status?: ProjectStatus;
|
|
}) {
|
|
return useQuery({
|
|
queryFn: () => fetchProjectList(params),
|
|
queryKey: [...PROJECTS_KEY, "list", params],
|
|
});
|
|
}
|
|
|
|
export function useRestoreProject() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: restoreProject,
|
|
onSuccess: (data) => {
|
|
logger.info("项目恢复成功", { name: data.name, projectId: data.id });
|
|
void queryClient.invalidateQueries({ queryKey: PROJECTS_KEY });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useUpdateProject() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: (args: { data: UpdateProjectRequest; id: string }) => updateProject(args.id, args.data),
|
|
onSuccess: (data) => {
|
|
logger.info("项目更新成功", { name: data.name, projectId: data.id });
|
|
void queryClient.invalidateQueries({ queryKey: PROJECTS_KEY });
|
|
},
|
|
});
|
|
}
|