's'
This commit is contained in:
29
services/api-client.ts
Normal file
29
services/api-client.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { z, ZodSchema } from "zod";
|
||||
|
||||
interface ApiClientOptions<TSchema extends ZodSchema> {
|
||||
endpoint: string;
|
||||
schema: TSchema;
|
||||
init?: RequestInit;
|
||||
}
|
||||
|
||||
export async function requestWithSchema<TSchema extends ZodSchema>({
|
||||
endpoint,
|
||||
schema,
|
||||
init,
|
||||
}: ApiClientOptions<TSchema>): Promise<z.infer<TSchema>> {
|
||||
const res = await fetch(endpoint, {
|
||||
...init,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(init?.headers ?? {}),
|
||||
},
|
||||
next: { revalidate: 60 },
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`API 请求失败: ${res.status} ${res.statusText}`);
|
||||
}
|
||||
|
||||
const json = await res.json();
|
||||
return schema.parse(json);
|
||||
}
|
||||
25
services/apps.service.ts
Normal file
25
services/apps.service.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { appResources } from "@/lib/mock-data";
|
||||
import { AppResource } from "@/lib/types";
|
||||
import { appListSchema, appResourceSchema } from "@/dto/app.dto";
|
||||
import { requestWithSchema } from "@/services/api-client";
|
||||
|
||||
const USE_REMOTE_API = false;
|
||||
|
||||
export async function getApps(): Promise<AppResource[]> {
|
||||
if (!USE_REMOTE_API) {
|
||||
return appListSchema.parse(appResources) as AppResource[];
|
||||
}
|
||||
return requestWithSchema({
|
||||
endpoint: "/api/apps",
|
||||
schema: appListSchema,
|
||||
}) as Promise<AppResource[]>;
|
||||
}
|
||||
|
||||
export async function getAppBySlug(slug: string): Promise<AppResource | null> {
|
||||
if (!USE_REMOTE_API) {
|
||||
const matched = appResources.find((app) => app.slug === slug);
|
||||
return matched ? (appResourceSchema.parse(matched) as AppResource) : null;
|
||||
}
|
||||
const all = await getApps();
|
||||
return all.find((app) => app.slug === slug) ?? null;
|
||||
}
|
||||
53
services/order.service.ts
Normal file
53
services/order.service.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { orderSchema } from "@/dto/order.dto";
|
||||
import { requestWithSchema } from "@/services/api-client";
|
||||
|
||||
const USE_REMOTE_API = false;
|
||||
|
||||
function amountByPlan(plan: "free" | "pro" | "ultra") {
|
||||
if (plan === "ultra") return 99;
|
||||
if (plan === "pro") return 29;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export async function createCheckoutOrder(plan: "free" | "pro" | "ultra", slug: string) {
|
||||
if (!USE_REMOTE_API) {
|
||||
const orderSeed = `${plan}-${slug}`.replace(/[^a-zA-Z0-9]/g, "").slice(0, 14).toUpperCase();
|
||||
return orderSchema.parse({
|
||||
id: `NOVA-${orderSeed || "DEMO0001"}`,
|
||||
plan,
|
||||
slug,
|
||||
amount: amountByPlan(plan),
|
||||
status: "pending",
|
||||
createdAt: "2026-04-02T00:00:00.000Z",
|
||||
});
|
||||
}
|
||||
|
||||
return requestWithSchema({
|
||||
endpoint: `/api/orders/create?plan=${plan}&slug=${encodeURIComponent(slug)}`,
|
||||
schema: orderSchema,
|
||||
init: { method: "POST" },
|
||||
});
|
||||
}
|
||||
|
||||
export async function getOrderById(input: {
|
||||
id: string;
|
||||
plan: "free" | "pro" | "ultra";
|
||||
slug: string;
|
||||
status: "pending" | "success" | "failed";
|
||||
}) {
|
||||
if (!USE_REMOTE_API) {
|
||||
return orderSchema.parse({
|
||||
id: input.id,
|
||||
plan: input.plan,
|
||||
slug: input.slug,
|
||||
amount: amountByPlan(input.plan),
|
||||
status: input.status,
|
||||
createdAt: "2026-04-02T00:00:00.000Z",
|
||||
});
|
||||
}
|
||||
|
||||
return requestWithSchema({
|
||||
endpoint: `/api/orders/${input.id}?status=${input.status}&plan=${input.plan}&slug=${encodeURIComponent(input.slug)}`,
|
||||
schema: orderSchema,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user