31 lines
1.5 KiB
TypeScript
31 lines
1.5 KiB
TypeScript
import { accessToken } from './auth';
|
|
|
|
const baseUrl = import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:8080/api/v1';
|
|
const deviceId = localStorage.getItem('aioa.admin.device') ?? crypto.randomUUID();
|
|
localStorage.setItem('aioa.admin.device', deviceId);
|
|
let registeredToken = '';
|
|
|
|
async function ensureDevice(token: string) {
|
|
if (registeredToken === token) return;
|
|
const response = await fetch(`${baseUrl}/devices/register`, {
|
|
method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ id: deviceId, name: navigator.userAgent.slice(0, 200), platform: 'OTHER', appVersion: 'admin-web' }),
|
|
});
|
|
if (!response.ok) throw new Error(`设备注册失败 (${response.status})`);
|
|
registeredToken = token;
|
|
}
|
|
|
|
export async function api<T>(path: string, init: RequestInit = {}): Promise<T> {
|
|
const token = await accessToken();
|
|
if (!token) throw new Error('登录已失效');
|
|
await ensureDevice(token);
|
|
const response = await fetch(`${baseUrl}${path}`, {
|
|
...init,
|
|
headers: { Authorization: `Bearer ${token}`, 'X-AIOA-Device-Id': deviceId, 'Content-Type': 'application/json', ...init.headers },
|
|
});
|
|
if (!response.ok) throw new Error((await response.json().catch(() => null))?.detail ?? `请求失败 (${response.status})`);
|
|
if (response.status === 204 || response.headers.get('content-length') === '0') return undefined as T;
|
|
const text = await response.text();
|
|
return (text ? JSON.parse(text) : undefined) as T;
|
|
}
|