npm package: @itshixun/qchat
Description: ## 1. 快速集成
Latest version: 2.4.68

# @itshixun/qchat

## 1. 快速集成

<a id="qchat_object"></a>

### 1.1 QChat对象

QChat类的创建参数定义如下：

```ts
/**
 * 创建QChat实例所需的参数类型
 * @template  T - 聊天场景类型SceneType，比如学生做作业、看课件、教师常规对话 等等
 * @template  U - 聊天类型ChatType，对应dify工作流各分支类型，比如StudentQa、TeacherQa、Courseware等
 */
export interface CreateQChatParams<T extends string, U extends string> {
  /** QChat初始选项 */
  initialOption: QChatOption<T, U>;
  /** 选项映射表，每个场景类型对应一个预设的选项对象，方便切换场景时快速变更选项 */
  optionsMap?: QChatSceneOptionMap<T, U>;
}
```

QChat对象通过单例工厂模式确保全局唯一实例。同时QChat具备延迟初始化特性：首次调用 getInstance() 时才创建实例，比如在React或Vue的App入口组件处，在组件mount后执行getInstance()方法创建实例。

### 1.2 创建QChat对象

```ts
// qchatController.ts

import { getToken } from './your/getToken/method';
import { QChat, type QChatOption } from '@itshixun/qchat';

const initialOption: QChatOption<string, string> = {
  defaultChatType: 'standard',
  server: {
    type: 'api',
    api: {
      url: 'https://api.example.com/chat',
      token: getToken,
      tokenKey: 'X-Access-Token',
    },
  },
};

export const qchat = new QChat<string, string>({ initialOption });
```

### 1.3 React 项目集成

```tsx
// App.tsx (React 项目入口文件)

import { qchat } from 'qchatController';

// 获取实例并挂载
useEffect(() => {
  // 首次调用getInstance()时创建qchat组件实例
  const instance = qchat.getInstance();
  // 在应用入口显式挂载
  qchat.mount('qchat_container', 'qchat_btn');
  return () => {
    // 也可用qchat.dispose()，dispose方法也是调用了instance.unmount()
    instance.unmount();
  };
}, []);

return (
  <div>
    <div>{/* 主项目内容 */}</div>
    <div id="qchat-container" className="h-600px w-400px" />
    {/* qchat悬浮按钮需要放置在position-fixed的容器内，同时要注意控制zIndex，保持在所有内容的上层 */}
    <div id="qchat-btn" class="fixed w-0 h-0 z-9999" />
  </div>
);
```

### 1.4 Vue 项目集成

```vue
<!-- App.vue (Vue 项目入口文件) -->

<script setup>
  import { qchat } from 'qchatController';

  onMounted(() => {
    // 首次调用getInstance()时创建qchat组件实例
    qchat.getInstance();
    // 在应用入口显式挂载
    qchat.mount('qchat_container', 'qchat_btn');
  });

  onBeforeUnmount(() => {
    qchat.dispose();
  });
</script>

<template>
  <div><!-- 主项目内容 --></div>
  <div id="qchat-container" class="h-600px w-400px" />
  <!-- qchat悬浮按钮需要放置在position:fixed的容器内，同时要注意控制zIndex，保持在所有内容的上层 -->
  <div id="qchat-btn" class="fixed w-0 h-0 z-9999" />
</template>
```

### 1.5 类型安全体系

QChat 接受两个范型参数，详见[1.1](#qchat_object) 中QChat 参数类型的定义。使用方式见下方代码示例：

```typescript
import { QChat, QChatSceneOptionMap } from '@itshixun/qchat';

// 使用示例：定义教学场景类型和对话类型
type SceneType = 'lecture' | 'homework';
type ChatType = 'student' | 'teacher';

const optionsMap: QChatSceneOptionMap<SceneType, ChatType> = new Map<SceneType, Partial<QChatOption<ChatType>>>([
  [
    'lecture',
    {
      ui: {
        title: '教学助手',
      },
      /* ... */
    },
  ],
  [
    'homework',
    {
      ui: {
        title: '作业助手',
      },
      /* ... */
    },
  ],
]);

const eduChat = new QChat<SceneType, ChatType>({
  initialOption: {
    /* 初始基础配置项 */
  },
  optionsMap,
  containerId: 'qchat_container',
  btnId: 'qchat_btn',
});

// 在业务端，通过setOptionsFromKey方法，快速切换为对应场景的配置项
eduChat.getInstance().setOptionsFromKey('lecture', {
  /* 这里可附加额外配置项 */
});
```

## 2. 核心配置项

### 2.1 基础配置

#### 2.1.1 配置项类型定义

```typescript
/**
 * QChat组件配置项
 * QChat功能的核心类型，用于组件的配置项，包括外观配置、服务连接配置、相关状态等
 */
export interface QChatOption<SceneType extends string, ChatType extends string> {
  /** 外观配置 */
  ui?: {
    /** AI助手面板标题 */
    title?: string;
    /** AI助手面板logo */
    logo?: string;
    /** AI助手面板logo大小，默认34 */
    logoSize?: number;
    /** 显示关闭按钮 */
    showClose?: boolean;
    /** 欢迎界面配置 */
    welcome?: {
      title?: string;
      /** 欢迎页描述 */
      description?: string;
      /** 常用工具FUT(Frequently Used Tools)板块配置  */
      futConfig?: FUTConfig;
      /** 高频问题FAQ(Frequently Asked Questions)板块配置 */
      faqConfig?: FAQConfig;
    };
    /** 对话界面配置 */
    chat?: {
      /** 对话时显示双方名称 */
      showName?: boolean;
      /** 对话时显示双方头像 */
      showAvatar?: boolean;
      /** 底部是否显示类似“所有内容均由Ai生成仅供参考”的信息*/
      showBottomInfo?: boolean;
      /** 底部文字信息，默认“所有内容均由AI生成” */
      bottomInfo?: string;
      /** ai助手头像 */
      aiAvatar?: string;
      /** ai助手名称 */
      aiName?: string;
      /** 用户头像 */
      userAvatar?: string;
      /** 用户名 */
      userName?: string;
      /** 头像大小 */
      avatarSize?: number;
      /** 输入框占位文字 */
      placeholderText?: string;
      /** 限制输入框和对话气泡列表的最大宽度，默认980px，传0则不限制 */
      maxChatWidth?: number;
      /** 输入框最大输入内容，不传则默认5000 */
      maxInputLength?: number;
      /** 可给对话容器附加样式 */
      chatWrapperStyle?: React.CSSProperties;
      /** 可给Header附加额外样式 */
      headerStyle?: React.CSSProperties;
      /** 抽屉样式 */
      drawerStyle?: React.CSSProperties;
    };
    /** ai按钮配置*/
    aiButton?: {
      /** 按钮可拖拽的区域，默认整个屏幕区域：top: 0, right: 0, bottom: 0, left: 0 */
      top?: number;
      right?: number;
      bottom?: number;
      left?: number;
      zIndex?: number;
      /** ai按钮的tooltip */
      tip?: string[];
    };
  };
  /**
   * 默认聊天类型，随着教师/学生等角色切换可随时改变
   */
  defaultChatType: ChatType;
  /**
   * 是否开启对话中的智能提示功能，默认为true，开启后，AI回复完内容后，会加载建议问题列表
   */
  enableChatSuggestions?: boolean;
  /**
   * 是否显示历史记录，默认为true，开启后，点击历史记录按钮，会加载历史记录列表
   */
  enableHistory?: boolean;
  /**
   * qst-ui-system 配置选项
   *
   *- `initQstTheme`决定是否在组件挂载时初始化 qst-ui-system 的样式（注入CSS 变量）。
   *- 如果容器项目已经初始化了 qst-ui-system：
   *   - 如果希望使用容器项目的qst-ui-system配置，`initQstTheme`设置为 `false`，并确保 `themeOption.namespace` 与容器项目一致，组件将使用容器项目的 UI 主题配置。
   *   - 如果需要与容器项目使用不同的 qst-ui-system 配置：`initQstTheme`设置为`true`，且必须设置 `themeOption.namespace` 和 `themeOption.styleTagId`，以与容器项目的配置区分开。
   *- 如果容器项目未使用 qst-ui-system：
   *   - `initQstTheme`必须设置为 `true`，组件将在挂载时根据 `themeOption` 初始化 qst-ui-system 并注入样式。
   */
  theme?: {
    namespace: string;
    initQstTheme?: boolean;
    themeOption?: ThemeOption;
  };
  /**
   * qchat相关状态，跟随页面使用场景的变化而更新
   */
  state?: QChatState<SceneType, ChatType>;
  /** 服务连接配置 */
  server: ServerOptions;
}

/**
 * qchat组件状态配置
 */
export interface QChatState<SceneType extends string, ChatType extends string> {
  /** 当前所在课程id */
  courseId?: string;
  /**
   * 场景，比如“答疑、课件学习、作业辅助、练习辅助、实践学习”，每次提问带场景参数，用于统计
   * - CourseQA(1, "课程答疑"),
   * - PreviewCourseware(2, "课件预览"),
   * - HomeworkAnswer(3, "作业答题"),
   * - ExerciseAnswer(4, "练习答题"),
   * - DoExperiment(5, "做实验"),
   * - DoPractice(6, "做实训"),
   */
  scene?: SceneType;
  /**
   * 在active状态如果为true，则显示对话面板，否则隐藏对话面板，显示悬浮按钮。
   */
  active?: boolean;
  /**
   * 建议问题列表，点击建议问题时，会发送该问题
   */
  prompts?: Array<PromptData<ChatType>>;
}

/**
 * 服务连接配置
 */
export interface ServerOptions {
  /**
   * 服务类型，目前仅支持api类型
   * - model 直接连接模型的api
   * - api 连接后端服务的api
   */
  type: 'model' | 'api';
  /**
   * api配置
   */
  api?: {
    /** api基础url */
    url: string;
    /** 动态获取token的方法 */
    token?: () => string;
    /** type为api时，tokenKey为请求头中token的key */
    tokenKey?: string;
  };
}
```

## 3. 核心 API 方法

```typescript
import { qchat } from 'qchatController';

/**
 * 显式挂载
 * 组件初始化与DOM挂载完全解耦，提升组件使用灵活性，符合渐进式挂载的最佳实践
 */
qchant.mount(containerId, btnId);

// 设置智能指令
qchat.getInstance().setDirective({
  chatType: 'expRecommend',
  elements: [
    {
      type: 'text',
      value: `请帮我推荐一些符合教学要求的实践案例\n实践主题：`,
    },
    {
      type: 'input',
      placeholder: '请输入需要推荐的要求',
    },
  ],
});

// 提交用户输入
qchat.getInstance().submitInput({
  type: 'homeworkQa',
  query: '如何计算矩阵特征值？',
});

// 开启新对话
qchat.getInstance().startNewConversation();

// 更新配置
qchat.getInstance().updateOption({
  ui: { title: '数学助手' },
  enableHistory: false,
});

// 快速切换为对应场景的配置项
qchat.getInstance().setOptionsFromKey('lecture', {
  /* 这里可附加额外配置项 */
});
```

## 4. 事件交互系统

### 4.1 事件监听示例

```typescript
import { qchat } from 'qchatController';
// 监听容器尺寸变化
qchat.eventBus.on('resize', ({ width, height }) => {
  console.log(`容器尺寸更新：${width}x${height}`);
});

// 监听配置选项变更
qchat.eventBus.on('optionChanged', (data) => {
  console.log('qchat选项有变更');
});
```

### 4.2 事件类型表

| 事件名称        | 触发时机                                                                                                         | 数据格式                                      |
| --------------- | ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| toggleActive    | 展开/收起qchat对话面板                                                                                           | { active: boolean }                           |
| updateOption    | 触发更新配置项                                                                                                   | Partial<QChatOption<SceneType, ChatType>>     |
| optionChanged   | 配置项变更后触发                                                                                                 | QChatOption<SceneType, ChatType>              |
| showToast       | 触发toast提示                                                                                                    | { message: string; type: 'success'\|'error' } |
| newConversation | 开启新对话                                                                                                       | void                                          |
| setDirective    | 指令设置完成                                                                                                     | DirectiveData<ChatType>                       |
| submitInput     | 用户提交输入                                                                                                     | InputSubmitType<ChatType>                     |
| resize          | 容器尺寸变化                                                                                                     | { width: number, height: number }             |
| onExpImport     | 业务端在实验案例采纳成功后触发，qchat监听到该事件后更新状态                                                      | void                                          |
| clickExpApply   | 点击“申请试用”按钮触发，业务端监听该事件处理后续逻辑                                                             | ExpRecommendItem                              |
| clickExpImport  | 点击“采纳”按钮触发，业务端监听该事件处理后续逻辑                                                                 | ExpRecommendItem                              |
| clickFUT        | 点击欢迎页的常用工具项目触发该事件，业务端监听到该事件后进行后续处理                                             | FUTItem                                       |
| clickPromptLink | 点击输入框上方的快捷按钮，当快捷按钮的`PromptData.isLink === true`时，触发该事件，业务端监听该事件后进行后续处理 | PromptData<ChatType>                          |