Files
juip-web/src/api/http.ts
2026-08-24 15:23:23 +08:00

147 lines
3.9 KiB
TypeScript

import type { ApiResponse } from "@/lib/api"
import type {
CreateOrderResult,
GameCity,
GameItem,
GameOrderData,
HttpOrderInfo,
} from "@/lib/models/http"
export const PHP_API_BASE_URL =
import.meta.env.VITE_PHP_API_BASE_URL ?? "https://php-api.juip.com"
const DEFAULT_TIMEOUT = 30_000
type RawHttpResponse = Record<string, unknown>
async function postJson<T = RawHttpResponse>(
path: string,
body: unknown,
): Promise<ApiResponse<T>> {
const controller = new AbortController()
const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT)
try {
const response = await fetch(`${PHP_API_BASE_URL}${path}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
body: JSON.stringify(body),
signal: controller.signal,
})
if (!response.ok) {
return {
success: false,
status: response.status,
message: "请求失败",
}
}
const data = (await response.json()) as T
return { success: true, data }
} catch (e) {
if (controller.signal.aborted) {
return {
success: false,
status: 408,
message: "请求超时,请稍后重试",
}
}
return {
success: false,
status: 500,
message: (e as Error).message || "网络错误",
}
} finally {
clearTimeout(timer)
}
}
function unwrapD(raw: RawHttpResponse | undefined): Record<string, unknown> {
const d = raw?.d
if (d && typeof d === "object" && !Array.isArray(d)) {
return d as Record<string, unknown>
}
return {}
}
export async function fetchGameCities(
game: GameOrderData,
): Promise<ApiResponse<GameCity[]>> {
const res = await postJson<RawHttpResponse>("/http/product/city", game)
if (!res.success) return res
const cities = unwrapD(res.data).cities
return {
success: true,
data: Array.isArray(cities) ? (cities as GameCity[]) : [],
}
}
export async function fetchGameList(
game: GameOrderData,
): Promise<ApiResponse<GameItem[]>> {
const res = await postJson<RawHttpResponse>("/http/product/game", game)
if (!res.success) return res
const games = unwrapD(res.data).games
return {
success: true,
data: Array.isArray(games) ? (games as GameItem[]) : [],
}
}
export async function fetchGameLineCount(
game: GameOrderData,
): Promise<ApiResponse<number>> {
const res = await postJson<RawHttpResponse>("/http/product/linecount", game)
if (!res.success) return res
const count = unwrapD(res.data).count
return { success: true, data: Number(count) || 0 }
}
export async function calcGamePrice(
orderInfo: HttpOrderInfo,
): Promise<ApiResponse<number>> {
const res = await postJson<RawHttpResponse>(
"/http/product/calc_price",
orderInfo,
)
if (!res.success) return res
const raw = res.data ?? {}
const priceValue =
typeof raw.price === "number" ? raw.price : unwrapD(raw).price
return {
success: true,
data: typeof priceValue === "number" ? priceValue : 0,
}
}
export async function createHttpOrder(
orderInfo: HttpOrderInfo,
): Promise<ApiResponse<CreateOrderResult>> {
const res = await postJson<RawHttpResponse>("/http/order/create_order", {
cookie: document.cookie,
order_info: orderInfo,
})
if (!res.success) return res
return {
success: true,
data: {
code: Number(res.data?.code) || 0,
msg: typeof res.data?.msg === "string" ? res.data.msg : undefined,
data: typeof res.data?.data === "string" ? res.data.data : undefined,
},
}
}
export async function fetchHttpBalance(): Promise<ApiResponse<number>> {
const res = await postJson<RawHttpResponse | number>(
"/http/user/get_balance",
{
cookie: document.cookie,
},
)
if (!res.success) return res
if (typeof res.data === "number") return { success: true, data: res.data }
const raw = res.data ?? {}
const balance = raw.d ?? raw.data ?? raw.balance
return { success: true, data: Number(balance) || 0 }
}