Files
dukang/apps/mini-user/src/lib/api.ts
T
2026-07-12 15:17:54 +08:00

125 lines
3.1 KiB
TypeScript

import Taro from '@tarojs/taro';
import { ClientApp } from '@dukang/shared-types';
import { goLogin } from './auth-nav';
function resolveApiBase(): string {
const origin =
typeof TARO_APP_API_ORIGIN !== 'undefined' && TARO_APP_API_ORIGIN
? TARO_APP_API_ORIGIN
: process.env.TARO_ENV === 'h5'
? 'http://localhost:3000'
: '';
if (origin) {
return `${origin.replace(/\/$/, '')}/api/v1`;
}
return '/api/v1';
}
export const API_BASE = resolveApiBase();
const TOKEN_KEY = 'user_access_token';
const REFRESH_KEY = 'user_refresh_token';
export const CLIENT_APP = ClientApp.USER_MINI;
export function getToken(): string {
try {
return Taro.getStorageSync(TOKEN_KEY) || '';
} catch {
return '';
}
}
export function getRefreshToken(): string {
try {
return Taro.getStorageSync(REFRESH_KEY) || '';
} catch {
return '';
}
}
export function saveAuth(data: { accessToken: string; refreshToken?: string }) {
Taro.setStorageSync(TOKEN_KEY, data.accessToken);
if (data.refreshToken) {
Taro.setStorageSync(REFRESH_KEY, data.refreshToken);
}
}
export function clearAuth() {
Taro.removeStorageSync(TOKEN_KEY);
Taro.removeStorageSync(REFRESH_KEY);
}
export function isLoggedIn(): boolean {
return !!getToken();
}
export function redirectToLogin() {
goLogin();
}
export function logout() {
clearAuth();
Taro.reLaunch({ url: '/pages/home/index' });
}
type ReqOptions = {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
data?: Record<string, unknown> | unknown;
auth?: boolean;
};
function parseBody(data: unknown): { code?: number; message?: string } {
if (data && typeof data === 'object') {
return data as { code?: number; message?: string };
}
return {};
}
/** 统一请求:注入 USER_MINI + Bearer,解包 { code, message, data } */
export async function request<T = unknown>(path: string, options: ReqOptions = {}): Promise<T> {
const header: Record<string, string> = {
'Content-Type': 'application/json',
'X-Client-App': CLIENT_APP,
};
const token = getToken();
if (token) header.Authorization = `Bearer ${token}`;
const res = await Taro.request({
url: `${API_BASE}${path}`,
method: options.method ?? 'GET',
data: options.data as Record<string, unknown>,
header,
});
const status = res.statusCode;
const body = parseBody(res.data);
if (status === 401 || body?.code === 401) {
clearAuth();
redirectToLogin();
throw new Error(body?.message || '登录已过期,请重新登录');
}
if (status === 404 && body.code === undefined) {
throw new Error('接口不可达,请确认 API 服务已启动');
}
if (status >= 400 || body.code !== 0) {
throw new Error(body?.message || `请求失败(${status})`);
}
return (res.data as { data: T }).data;
}
export function toast(title: string, icon: 'success' | 'error' | 'none' = 'none') {
Taro.showToast({ title, icon, duration: 1800 });
}
export type SessionPayload = {
accessToken: string;
refreshToken?: string;
};
export type UserProfile = {
id: string;
phone?: string | null;
nickname?: string | null;
avatarUrl?: string | null;
};