2026-03-11 14:38:43 +08:00
|
|
|
|
import { readingApi } from "./client";
|
|
|
|
|
|
import type { ResultPageResultTenant, Tenant as ApiTenant } from "./generated/model";
|
2026-02-28 17:51:15 +08:00
|
|
|
|
|
|
|
|
|
|
// ==================== 类型定义 ====================
|
|
|
|
|
|
|
|
|
|
|
|
export interface TenantQueryParams {
|
|
|
|
|
|
page?: number;
|
|
|
|
|
|
pageSize?: number;
|
|
|
|
|
|
keyword?: string;
|
|
|
|
|
|
status?: string;
|
|
|
|
|
|
packageType?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface Tenant {
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
loginAccount: string;
|
|
|
|
|
|
address?: string;
|
|
|
|
|
|
contactPerson?: string;
|
|
|
|
|
|
contactPhone?: string;
|
|
|
|
|
|
logoUrl?: string;
|
|
|
|
|
|
packageType: string;
|
|
|
|
|
|
teacherQuota: number;
|
|
|
|
|
|
studentQuota: number;
|
|
|
|
|
|
storageQuota?: number;
|
|
|
|
|
|
teacherCount: number;
|
|
|
|
|
|
studentCount: number;
|
|
|
|
|
|
storageUsed?: number;
|
|
|
|
|
|
startDate: string;
|
|
|
|
|
|
expireDate: string;
|
|
|
|
|
|
status: string;
|
|
|
|
|
|
createdAt: string;
|
|
|
|
|
|
updatedAt?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface TenantDetail extends Tenant {
|
|
|
|
|
|
teachers?: Array<{
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
phone: string;
|
|
|
|
|
|
email?: string;
|
|
|
|
|
|
status: string;
|
|
|
|
|
|
lessonCount: number;
|
|
|
|
|
|
}>;
|
|
|
|
|
|
students?: Array<{
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
classId: number;
|
|
|
|
|
|
gender?: string;
|
|
|
|
|
|
readingCount: number;
|
|
|
|
|
|
}>;
|
|
|
|
|
|
classes?: Array<{
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
grade: string;
|
|
|
|
|
|
studentCount: number;
|
|
|
|
|
|
}>;
|
|
|
|
|
|
_count?: {
|
|
|
|
|
|
teachers: number;
|
|
|
|
|
|
students: number;
|
|
|
|
|
|
classes: number;
|
|
|
|
|
|
lessons: number;
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface CreateTenantDto {
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
loginAccount: string;
|
|
|
|
|
|
password?: string;
|
|
|
|
|
|
address?: string;
|
|
|
|
|
|
contactPerson?: string;
|
|
|
|
|
|
contactPhone?: string;
|
|
|
|
|
|
packageType?: string;
|
|
|
|
|
|
teacherQuota?: number;
|
|
|
|
|
|
studentQuota?: number;
|
|
|
|
|
|
startDate?: string;
|
|
|
|
|
|
expireDate?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface UpdateTenantDto {
|
|
|
|
|
|
name?: string;
|
|
|
|
|
|
address?: string;
|
|
|
|
|
|
contactPerson?: string;
|
|
|
|
|
|
contactPhone?: string;
|
|
|
|
|
|
packageType?: string;
|
|
|
|
|
|
teacherQuota?: number;
|
|
|
|
|
|
studentQuota?: number;
|
|
|
|
|
|
startDate?: string;
|
|
|
|
|
|
expireDate?: string;
|
|
|
|
|
|
status?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface UpdateTenantQuotaDto {
|
|
|
|
|
|
packageType?: string;
|
|
|
|
|
|
teacherQuota?: number;
|
|
|
|
|
|
studentQuota?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface AdminStats {
|
|
|
|
|
|
tenantCount: number;
|
|
|
|
|
|
activeTenantCount: number;
|
|
|
|
|
|
courseCount: number;
|
|
|
|
|
|
publishedCourseCount: number;
|
|
|
|
|
|
studentCount: number;
|
|
|
|
|
|
teacherCount: number;
|
|
|
|
|
|
lessonCount: number;
|
|
|
|
|
|
monthlyLessons: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface TrendData {
|
|
|
|
|
|
month: string;
|
|
|
|
|
|
tenantCount: number;
|
|
|
|
|
|
lessonCount: number;
|
|
|
|
|
|
studentCount: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ActiveTenant {
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
lessonCount: number;
|
|
|
|
|
|
teacherCount: number;
|
|
|
|
|
|
studentCount: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface PopularCourse {
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
usageCount: number;
|
|
|
|
|
|
teacherCount: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface AdminSettings {
|
|
|
|
|
|
// Basic settings
|
|
|
|
|
|
systemName?: string;
|
|
|
|
|
|
systemDesc?: string;
|
|
|
|
|
|
contactPhone?: string;
|
|
|
|
|
|
contactEmail?: string;
|
|
|
|
|
|
systemLogo?: string;
|
|
|
|
|
|
|
|
|
|
|
|
// Security settings
|
|
|
|
|
|
passwordStrength?: string;
|
|
|
|
|
|
maxLoginAttempts?: number;
|
|
|
|
|
|
tokenExpire?: string;
|
|
|
|
|
|
forceHttps?: boolean;
|
|
|
|
|
|
|
|
|
|
|
|
// Notification settings
|
|
|
|
|
|
emailEnabled?: boolean;
|
|
|
|
|
|
smtpHost?: string;
|
|
|
|
|
|
smtpPort?: number;
|
|
|
|
|
|
smtpUser?: string;
|
|
|
|
|
|
smtpPassword?: string;
|
|
|
|
|
|
fromEmail?: string;
|
|
|
|
|
|
smsEnabled?: boolean;
|
|
|
|
|
|
|
|
|
|
|
|
// Storage settings
|
|
|
|
|
|
storageType?: string;
|
|
|
|
|
|
maxFileSize?: number;
|
|
|
|
|
|
allowedTypes?: string;
|
|
|
|
|
|
|
|
|
|
|
|
// Tenant defaults
|
|
|
|
|
|
defaultTeacherQuota?: number;
|
|
|
|
|
|
defaultStudentQuota?: number;
|
|
|
|
|
|
enableAutoExpire?: boolean;
|
|
|
|
|
|
notifyBeforeDays?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-10 23:50:53 +08:00
|
|
|
|
export interface AdminSettingsUpdateRequest {
|
|
|
|
|
|
systemName?: string;
|
|
|
|
|
|
systemDesc?: string;
|
|
|
|
|
|
contactPhone?: string;
|
|
|
|
|
|
contactEmail?: string;
|
|
|
|
|
|
systemLogo?: string;
|
|
|
|
|
|
passwordStrength?: string;
|
|
|
|
|
|
maxLoginAttempts?: number;
|
|
|
|
|
|
tokenExpire?: string;
|
|
|
|
|
|
forceHttps?: boolean;
|
|
|
|
|
|
emailEnabled?: boolean;
|
|
|
|
|
|
smtpHost?: string;
|
|
|
|
|
|
smtpPort?: number;
|
|
|
|
|
|
smtpUser?: string;
|
|
|
|
|
|
smtpPassword?: string;
|
|
|
|
|
|
fromEmail?: string;
|
|
|
|
|
|
smsEnabled?: boolean;
|
|
|
|
|
|
storageType?: string;
|
|
|
|
|
|
maxFileSize?: number;
|
|
|
|
|
|
allowedTypes?: string;
|
|
|
|
|
|
defaultTeacherQuota?: number;
|
|
|
|
|
|
defaultStudentQuota?: number;
|
|
|
|
|
|
enableAutoExpire?: boolean;
|
|
|
|
|
|
notifyBeforeDays?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface TenantStatusUpdateRequest {
|
|
|
|
|
|
status: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface TenantQuotaUpdateRequest {
|
|
|
|
|
|
packageType?: string;
|
|
|
|
|
|
teacherQuota?: number;
|
|
|
|
|
|
studentQuota?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-28 17:51:15 +08:00
|
|
|
|
// ==================== 租户管理 ====================
|
|
|
|
|
|
|
2026-03-11 14:38:43 +08:00
|
|
|
|
export const getTenants = (
|
|
|
|
|
|
params: TenantQueryParams,
|
|
|
|
|
|
): Promise<{
|
|
|
|
|
|
items: Tenant[];
|
|
|
|
|
|
total: number;
|
|
|
|
|
|
page: number;
|
|
|
|
|
|
pageSize: number;
|
|
|
|
|
|
}> =>
|
|
|
|
|
|
readingApi.getTenantPage(params as any).then((res) => {
|
|
|
|
|
|
const wrapped = res as ResultPageResultTenant;
|
|
|
|
|
|
const pageData = wrapped.data;
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
items: (pageData?.items as unknown as ApiTenant[] as Tenant[]) ?? [],
|
|
|
|
|
|
total: pageData?.total ?? 0,
|
|
|
|
|
|
page: pageData?.page ?? params.page ?? 1,
|
|
|
|
|
|
pageSize: pageData?.pageSize ?? params.pageSize ?? 10,
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
2026-03-10 17:28:31 +08:00
|
|
|
|
|
|
|
|
|
|
export const getTenant = (id: number): Promise<TenantDetail> =>
|
|
|
|
|
|
readingApi.getTenant(id).then((res) => res.data as any);
|
|
|
|
|
|
|
|
|
|
|
|
export const createTenant = (
|
|
|
|
|
|
data: CreateTenantDto,
|
|
|
|
|
|
): Promise<Tenant & { tempPassword: string }> =>
|
|
|
|
|
|
readingApi.createTenant(data as any).then((res) => {
|
|
|
|
|
|
const map = res.data as any;
|
|
|
|
|
|
// Orval 将返回值定义为 ResultTenant / ResultMapStringString,这里按现有前端期望结构进行兼容转换
|
|
|
|
|
|
return {
|
|
|
|
|
|
...(map as Tenant),
|
2026-03-11 13:53:48 +08:00
|
|
|
|
tempPassword: (map as any).tempPassword ?? "",
|
2026-03-10 17:28:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
export const updateTenant = (
|
|
|
|
|
|
id: number,
|
|
|
|
|
|
data: UpdateTenantDto,
|
|
|
|
|
|
): Promise<Tenant> =>
|
|
|
|
|
|
readingApi.updateTenant(id, data as any).then((res) => res.data as any);
|
|
|
|
|
|
|
|
|
|
|
|
export const updateTenantQuota = (
|
|
|
|
|
|
id: number,
|
|
|
|
|
|
data: UpdateTenantQuotaDto,
|
|
|
|
|
|
): Promise<Tenant> =>
|
2026-03-11 13:53:48 +08:00
|
|
|
|
readingApi.updateTenantQuota(id, data as any).then((res) => res.data as any);
|
2026-03-10 17:28:31 +08:00
|
|
|
|
|
|
|
|
|
|
export const updateTenantStatus = (
|
|
|
|
|
|
id: number,
|
|
|
|
|
|
status: string,
|
|
|
|
|
|
): Promise<{ id: number; name: string; status: string }> =>
|
|
|
|
|
|
readingApi
|
|
|
|
|
|
.updateTenantStatus(id, { status } as any)
|
|
|
|
|
|
.then((res) => res.data as any);
|
|
|
|
|
|
|
|
|
|
|
|
export const resetTenantPassword = (
|
|
|
|
|
|
id: number,
|
|
|
|
|
|
): Promise<{ tempPassword: string }> =>
|
|
|
|
|
|
readingApi.resetTenantPassword(id).then((res) => res.data as any);
|
|
|
|
|
|
|
|
|
|
|
|
export const deleteTenant = (id: number): Promise<{ success: boolean }> =>
|
|
|
|
|
|
readingApi.deleteTenant(id).then(() => ({ success: true }));
|
2026-02-28 17:51:15 +08:00
|
|
|
|
|
|
|
|
|
|
// ==================== 统计数据 ====================
|
|
|
|
|
|
|
2026-03-10 17:28:31 +08:00
|
|
|
|
export const getAdminStats = (): Promise<AdminStats> =>
|
|
|
|
|
|
readingApi.getStats3().then((res) => res.data as any);
|
2026-02-28 17:51:15 +08:00
|
|
|
|
|
2026-03-10 17:28:31 +08:00
|
|
|
|
export const getTrendData = (): Promise<TrendData[]> =>
|
|
|
|
|
|
readingApi.getTrendData().then((res) => res.data as any);
|
2026-02-28 17:51:15 +08:00
|
|
|
|
|
2026-03-11 13:53:48 +08:00
|
|
|
|
export const getActiveTenants = (limit?: number): Promise<ActiveTenant[]> =>
|
|
|
|
|
|
readingApi.getActiveTenants({ limit } as any).then((res) => res.data as any);
|
2026-02-28 17:51:15 +08:00
|
|
|
|
|
2026-03-11 13:53:48 +08:00
|
|
|
|
export const getPopularCourses = (limit?: number): Promise<PopularCourse[]> =>
|
|
|
|
|
|
readingApi.getPopularCourses({ limit } as any).then((res) => res.data as any);
|
2026-02-28 17:51:15 +08:00
|
|
|
|
|
|
|
|
|
|
// ==================== 系统设置 ====================
|
|
|
|
|
|
|
2026-03-10 17:28:31 +08:00
|
|
|
|
export const getAdminSettings = (): Promise<AdminSettings> =>
|
|
|
|
|
|
readingApi.getSettings1().then((res) => res.data as any);
|
2026-02-28 17:51:15 +08:00
|
|
|
|
|
2026-03-10 17:28:31 +08:00
|
|
|
|
export const updateAdminSettings = (
|
|
|
|
|
|
data: Record<string, any>,
|
|
|
|
|
|
): Promise<AdminSettings> =>
|
2026-03-11 13:53:48 +08:00
|
|
|
|
readingApi.updateSettings1(data as any).then(() => getAdminSettings());
|