@plasosdk/client-sdk
Version:
Plaso教育平台的客户端SDK
195 lines (173 loc) • 4.98 kB
text/typescript
import React from 'react';
import { createRoot, Root } from 'react-dom/client';
import { PlasoViewer } from './components/PlasoViewer';
import { Environment } from './config/environment';
import { PlasoContentType,getUrlConfigMap } from './config/url';
export interface PlasoClientOptions {
token: string;
container: HTMLElement;
env?: Environment;
onError?: (error: Error) => void;
onLoading?: (isLoading: boolean) => void;
// 是否打开开发者工具
devTools?: boolean
platform?: string;
}
// 定义URL映射配置
interface UrlConfig {
baseUrl: string;
}
export class PlasoClient {
private platform: string;
private token: string;
private container: HTMLElement;
private onError?: (error: Error) => void;
private onLoading?: (isLoading: boolean) => void;
private root: Root | null = null;
private env: Environment;
private URL_CONFIG_MAP: Record<PlasoContentType, UrlConfig> | null = null;
private devTools: boolean;
constructor(options: PlasoClientOptions) {
this.platform = options.platform || 'plaso';
this.token = options.token;
this.container = options.container;
this.onError = options.onError;
this.onLoading = options.onLoading;
this.root = createRoot(this.container);
this.env = options.env || Environment.PROD;
this.URL_CONFIG_MAP = getUrlConfigMap(this.env, this.platform);
this.devTools = options.devTools || false;
this.checkParams();
}
private checkParams = () => {
if(!(this.token && this.container)){
this.onError?.(new Error('传入参数有误'));
}
}
private handleError(error: Error): void {
console.error('Plaso客户端错误:', error);
if (this.onError) {
this.onError(error);
}
}
/**
* 构建完整URL
* @param type 内容类型
* @returns 完整的URL
*/
private buildUrl(type: PlasoContentType): string {
const config = this.URL_CONFIG_MAP?.[type];
if (!config) {
throw new Error(`不支持的内容类型: ${type}`);
}
const { baseUrl } = config;
// 检查baseUrl是否已包含参数
const hasParams = baseUrl.includes('?');
const separator = hasParams ? '&' : '?';
return `${baseUrl}${separator}token=${encodeURIComponent(this.token)}`;
}
/**
* 渲染内容
* @param type 内容类型
*/
private async renderContent(type: PlasoContentType): Promise<void> {
if (!this.root) {
throw new Error('Plaso客户端未正确初始化');
}
if (this.onLoading) {
this.onLoading(true);
}
try {
const url = this.buildUrl(type);
this.root.render(
React.createElement(PlasoViewer, {
url,
token: this.token,
type,
devTools: this.devTools,
onError: this.handleError.bind(this)
})
);
} catch (error) {
this.handleError(error as Error);
throw error;
} finally {
if (this.onLoading) {
this.onLoading(false);
}
}
}
/**
* 创建指定类型的模块
* @param module 模块类型
*/
public async createModule(module: PlasoContentType): Promise<void> {
try {
await this.renderContent(module);
} catch (error) {
this.handleError(error as Error);
throw error;
}
}
/**
* 创建作业
*/
public async createAssignment(): Promise<void> {
try {
await this.createModule(PlasoContentType.NHOMEWORK);
} catch (error) {
this.handleError(error as Error);
throw error;
}
}
/**
* 创建课堂
*/
public async createClassroom(): Promise<void> {
try {
await this.createModule(PlasoContentType.LIVECLASS);
} catch (error) {
this.handleError(error as Error);
throw error;
}
}
/**
* 创建资源
*/
public async createResource(): Promise<void> {
try {
await this.createModule(PlasoContentType.RESOURCES);
} catch (error) {
this.handleError(error as Error);
throw error;
}
}
/**
* 渲染自定义内容
* @param type 内容类型
*/
public async renderCustomContent(type: PlasoContentType): Promise<void> {
try {
await this.createModule(type);
} catch (error) {
this.handleError(error as Error);
throw error;
}
}
/**
* 销毁客户端实例
*/
public destroy(): HTMLElement | void {
console.log('销毁客户端实例');
if (this.root) {
this.root.unmount();
this.root = null;
}
if (this.container.parentNode) {
const newContainer = this.container.cloneNode(false) as HTMLElement;
this.container.parentNode.replaceChild(newContainer, this.container);
this.container = newContainer;
return newContainer; // 返回新节点
}
}
}