import type { App } from "@capp/eden"; import type { WatchSource } from "vue"; import { treaty } from "@elysiajs/eden"; import { i18n } from "@/locales"; const baseURL = import.meta.env.DEV ? window.location.origin : import.meta.env.VITE_API_URL; export const client = treaty(baseURL, { fetch: { credentials: "include", }, headers() { const token = localStorage.getItem("user-token") || ""; const headers = new Headers(); headers.append("Content-Type", "application/json"); headers.append("Authorization", token ? `Bearer ${token}` : ""); return headers; }, }); export interface SafeClientOptions { silent?: boolean; immediate?: boolean; watchSource?: WatchSource; // 用于监听的响应式数据源 } export interface SafeClientReturn { data: Ref; error: Ref; isPending: Ref; execute: () => Promise; onFetchResponse: (callback: (data: T, error: E) => void) => void; stopWatching?: () => void; } export type RequestPromise = Promise<{ data: T; error: E; status?: number; response?: Response }>; export function safeClient( requestPromise: (() => RequestPromise) | RequestPromise, options: SafeClientOptions = {}, ): SafeClientReturn & Promise> { const { immediate = true, watchSource } = options; const data = ref(null); const error = ref(null); const isPending = ref(false); let responseCallback: ((data: T, error: E) => void) | null = null; let stopWatcher: (() => void) | undefined; const execute = async () => { isPending.value = true; let request: () => RequestPromise; if (typeof requestPromise !== "function") { request = () => Promise.resolve(requestPromise); } else { request = requestPromise; } const res = await request().finally(() => { isPending.value = false; }); if (res.error) { if (!options.silent && res.status === 418) { showToast(i18n.global.t((res.error as any).value.code, { ...(res.error as any).value.context, })); } else if (res.status === 401) { setTimeout(() => { showToast("登录状态已过期,2秒后将跳转到登录页面,请重新登录!"); localStorage.removeItem("user-token"); window.location.reload(); }, 2000); } else if (!options.silent) { showToast((res.error as any).message || i18n.global.t("network_error")); } throw res.error; } data.value = res.data; error.value = res.error; // 调用注册的回调函数 if (responseCallback) { responseCallback(res.data, res.error); } }; function onFetchResponse(callback: (data: T, error: E) => void) { responseCallback = callback; } function stopWatching() { if (stopWatcher) { stopWatcher(); stopWatcher = undefined; } } // 如果提供了 watchSource,则监听其变化 if (watchSource) { stopWatcher = watch( watchSource, () => { execute(); }, { immediate: false }, // 不立即执行,避免与 immediate 选项冲突 ); } const result: SafeClientReturn = { data: data as Ref, error: error as Ref, isPending, execute, onFetchResponse, stopWatching, }; const promise = immediate ? execute().then(() => result) : Promise.resolve(result); Object.assign(promise, result); return promise as SafeClientReturn & Promise>; }