/** * 租户管理 API */ import { getAccessToken } from '../../../../framework/auth/api'; const API_BASE = '/api/admin/tenants'; const MODULES_API = '/api/admin/modules'; function getAuthHeaders(): HeadersInit { const headers: Record = { 'Content-Type': 'application/json', }; const token = getAccessToken(); if (token) { headers['Authorization'] = `Bearer ${token}`; } return headers; } // ==================== 类型定义 ==================== export type TenantType = 'HOSPITAL' | 'PHARMA' | 'JOURNAL' | 'INTERNAL' | 'PUBLIC'; export type TenantStatus = 'ACTIVE' | 'SUSPENDED' | 'EXPIRED'; export type JournalLanguage = 'ZH' | 'EN' | 'OTHER'; export interface TenantInfo { id: string; code: string; name: string; type: TenantType; journalLanguage?: JournalLanguage | null; journalFullName?: string | null; logoUrl?: string | null; brandColor?: string | null; loginBackgroundUrl?: string | null; status: TenantStatus; contactName?: string | null; contactPhone?: string | null; contactEmail?: string | null; expiresAt?: string | null; createdAt: string; updatedAt: string; } export interface TenantModuleConfig { code: string; name: string; enabled: boolean; expiresAt?: string | null; } export interface TenantDetail extends TenantInfo { modules: TenantModuleConfig[]; userCount: number; } export interface ModuleInfo { code: string; name: string; description?: string | null; icon?: string | null; } export interface CreateTenantRequest { code: string; name: string; type: TenantType; journalLanguage?: JournalLanguage; journalFullName?: string; logoUrl?: string; brandColor?: string; loginBackgroundUrl?: string; contactName?: string; contactPhone?: string; contactEmail?: string; expiresAt?: string; modules?: string[]; } export interface UpdateTenantRequest { name?: string; type?: TenantType; journalLanguage?: JournalLanguage | null; journalFullName?: string | null; logoUrl?: string | null; brandColor?: string | null; loginBackgroundUrl?: string | null; contactName?: string; contactPhone?: string; contactEmail?: string; expiresAt?: string | null; } export interface TenantListResponse { success: boolean; data: TenantInfo[]; total: number; page: number; limit: number; totalPages: number; } // ==================== API 函数 ==================== /** * 获取租户列表 */ export async function fetchTenantList(params?: { type?: TenantType; status?: TenantStatus; search?: string; page?: number; limit?: number; }): Promise { const searchParams = new URLSearchParams(); if (params?.type) searchParams.set('type', params.type); if (params?.status) searchParams.set('status', params.status); if (params?.search) searchParams.set('search', params.search); if (params?.page) searchParams.set('page', String(params.page)); if (params?.limit) searchParams.set('limit', String(params.limit)); const url = `${API_BASE}?${searchParams.toString()}`; const response = await fetch(url, { method: 'GET', headers: getAuthHeaders(), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '获取租户列表失败'); } return response.json(); } /** * 获取租户详情 */ export async function fetchTenantDetail(id: string): Promise { const response = await fetch(`${API_BASE}/${id}`, { method: 'GET', headers: getAuthHeaders(), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '获取租户详情失败'); } const result = await response.json(); return result.data; } /** * 创建租户 */ export async function createTenant(data: CreateTenantRequest): Promise { const response = await fetch(API_BASE, { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify(data), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '创建租户失败'); } const result = await response.json(); return result.data; } /** * 更新租户信息 */ export async function updateTenant(id: string, data: UpdateTenantRequest): Promise { const response = await fetch(`${API_BASE}/${id}`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '更新租户失败'); } const result = await response.json(); return result.data; } /** * 更新租户状态 */ export async function updateTenantStatus(id: string, status: TenantStatus): Promise { const response = await fetch(`${API_BASE}/${id}/status`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify({ status }), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '更新租户状态失败'); } } /** * 删除租户 */ export async function deleteTenant(id: string): Promise { const response = await fetch(`${API_BASE}/${id}`, { method: 'DELETE', headers: getAuthHeaders(), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '删除租户失败'); } } /** * 配置租户模块 */ export async function configureModules( tenantId: string, modules: { code: string; enabled: boolean; expiresAt?: string | null }[] ): Promise { const response = await fetch(`${API_BASE}/${tenantId}/modules`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify({ modules }), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '配置租户模块失败'); } const result = await response.json(); return result.data; } /** * 获取所有可用模块列表 */ export async function fetchModuleList(): Promise { const response = await fetch(MODULES_API, { method: 'GET', headers: getAuthHeaders(), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '获取模块列表失败'); } const result = await response.json(); return result.data; } // ==================== RVW Config API ==================== /** 租户审稿配置 */ export interface TenantRvwConfig { id: string; tenantId: string; editorialBaseStandard: 'zh' | 'en'; editorialExpertPrompt: string | null; editorialHandlebarsTemplate: string | null; methodologyExpertPrompt: string | null; methodologyHandlebarsTemplate: string | null; dataForensicsExpertPrompt: string | null; dataForensicsHandlebarsTemplate: string | null; clinicalExpertPrompt: string | null; clinicalHandlebarsTemplate: string | null; createdAt: string; updatedAt: string; } /** 更新审稿配置请求 */ export interface UpdateRvwConfigRequest { editorialBaseStandard?: 'zh' | 'en'; editorialExpertPrompt?: string | null; editorialHandlebarsTemplate?: string | null; methodologyExpertPrompt?: string | null; methodologyHandlebarsTemplate?: string | null; dataForensicsExpertPrompt?: string | null; dataForensicsHandlebarsTemplate?: string | null; clinicalExpertPrompt?: string | null; clinicalHandlebarsTemplate?: string | null; } /** * 获取租户智能审稿配置 */ export async function fetchRvwConfig(tenantId: string): Promise { const response = await fetch(`${API_BASE}/${tenantId}/rvw-config`, { headers: getAuthHeaders(), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '获取审稿配置失败'); } const result = await response.json(); return result.data; } /** * 保存(UPSERT)租户智能审稿配置 */ export async function saveRvwConfig(tenantId: string, data: UpdateRvwConfigRequest): Promise { const response = await fetch(`${API_BASE}/${tenantId}/rvw-config`, { method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify(data), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || '保存审稿配置失败'); } const result = await response.json(); return result.data; }