it0/it0-web-admin/src/infrastructure/repositories/api-app-version.repository.ts

108 lines
3.8 KiB
TypeScript

import { apiClient } from '../api/api-client';
import {
AppVersion,
AppVersionFilter,
UpdateAppVersionInput,
UploadAppVersionInput,
ParsedPackageInfo,
} from '@/domain/entities/app-version';
/** Normalize version-service response: platform comes back as ANDROID/IOS, fileSize as bigint string */
function normalize(raw: Record<string, unknown>): AppVersion {
return {
...(raw as AppVersion),
platform: (raw.platform as string).toLowerCase() as 'android' | 'ios',
fileSize: raw.fileSize != null ? Number(raw.fileSize) : undefined,
};
}
export async function listVersions(filter?: AppVersionFilter): Promise<AppVersion[]> {
const params = new URLSearchParams();
if (filter?.platform) params.append('platform', filter.platform.toUpperCase());
if (filter?.includeDisabled) params.append('includeDisabled', 'true');
const qs = params.toString();
const result = await apiClient<unknown[]>(`/api/v1/versions${qs ? '?' + qs : ''}`);
return result.map((v) => normalize(v as Record<string, unknown>));
}
export async function getVersionById(id: string): Promise<AppVersion> {
const result = await apiClient<unknown>(`/api/v1/versions/${id}`);
return normalize(result as Record<string, unknown>);
}
export async function updateVersion(id: string, input: UpdateAppVersionInput): Promise<AppVersion> {
const result = await apiClient<unknown>(`/api/v1/versions/${id}`, { method: 'PUT', body: input });
return normalize(result as Record<string, unknown>);
}
export async function deleteVersion(id: string): Promise<void> {
await apiClient<unknown>(`/api/v1/versions/${id}`, { method: 'DELETE' });
}
export async function toggleVersion(id: string, isEnabled: boolean): Promise<void> {
await apiClient<unknown>(`/api/v1/versions/${id}/toggle`, {
method: 'PATCH',
body: { isEnabled },
});
}
function getClientAuthHeaders(): Record<string, string> {
const headers: Record<string, string> = {};
if (typeof window === 'undefined') return headers;
const token = localStorage.getItem('access_token');
if (token) headers['Authorization'] = `Bearer ${token}`;
const tenantData = localStorage.getItem('current_tenant');
if (tenantData) {
try {
const tenant = JSON.parse(tenantData) as { id: string };
headers['X-Tenant-Id'] = tenant.id;
} catch {
// ignore parse errors
}
}
return headers;
}
export async function uploadVersion(input: UploadAppVersionInput): Promise<AppVersion> {
const formData = new FormData();
formData.append('file', input.file);
formData.append('platform', input.platform.toUpperCase());
formData.append('versionName', input.versionName);
formData.append('buildNumber', input.buildNumber);
formData.append('isForceUpdate', String(input.isForceUpdate ?? false));
if (input.changelog) formData.append('changelog', input.changelog);
if (input.minOsVersion) formData.append('minOsVersion', input.minOsVersion);
const response = await fetch('/api/app-versions/upload', {
method: 'POST',
headers: getClientAuthHeaders(),
body: formData,
});
if (!response.ok) {
const err = await response.json().catch(() => null) as { message?: string } | null;
throw new Error(err?.message || `上传失败: ${response.status}`);
}
const result = await response.json() as Record<string, unknown>;
return normalize(result);
}
export async function parsePackage(file: File, platform: 'android' | 'ios'): Promise<ParsedPackageInfo> {
const formData = new FormData();
formData.append('file', file);
formData.append('platform', platform.toUpperCase());
const response = await fetch('/api/app-versions/parse', {
method: 'POST',
headers: getClientAuthHeaders(),
body: formData,
});
if (!response.ok) {
throw new Error(`解析失败: ${response.status}`);
}
return response.json() as Promise<ParsedPackageInfo>;
}