npm package: @sensedealai/cue-widget-sdk
Description: Cue 助手挂件 SDK - 支持 CDN 和 ESM 引入，开箱即用
Author: Cue Team
Latest version: 1.0.12

# Cue Widget SDK

<p align="center">
  <img src="https://img.shields.io/npm/v/@sensedealai/cue-widget-sdk.svg" alt="npm version">
  <img src="https://img.shields.io/npm/l/@sensedealai/cue-widget-sdk.svg" alt="MIT License">
  <img src="https://img.shields.io/npm/types/@sensedealai/cue-widget-sdk.svg" alt="TypeScript">
</p>

<p align="center">✨ 轻量级 AI 助手挂件 SDK - 开箱即用，支持 CDN 和 ESM 引入 ✨</p>

## 特性

- 🚀 **开箱即用** - 简单配置即可集成到任何项目
- 📦 **多格式支持** - 支持 ESM、CJS、UMD (CDN) 三种引入方式
- 🎨 **框架无关** - 可在 React、Vue、Angular 或纯 HTML 中使用
- 🎯 **自动挂载** - 无需手动渲染组件
- ⚡ **按需加载** - 动态导入，减小包体积
- 🔧 **高度可配置** - 支持自定义主题、位置、回调等

## 快速开始

> **前置要求**
>
> 在使用 SDK 前，请先访问 [Cue 官网](https://cuecue.cn/) 注册账号并创建应用，获取 `code` 授权码。

### 方式一：CDN 引入（推荐）

最简单的方式，无需构建工具，直接在 HTML 中引入：

```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>我的网站</title>

  <!-- 1. 引入 Cue Widget SDK (已内置 React 和样式) -->
  <script src="https://unpkg.com/@sensedealai/cue-widget-sdk@latest/dist/umd/index.min.js"></script>
</head>
<body>
  <div id="app"></div>

  <script>
    // 2. 初始化 SDK
    const widget = CueWidgetSDK.init({
      code: 'your-auth-code',  // 必填：你的授权码
      position: 'bottom-right',               // 按钮位置
      buttonLabel: '助手',                    // 按钮文字
      modalTitle: 'AI 助手',                  // 弹窗标题
    });

    // 可选：监听事件
    widget.onOpen(() => console.log('助手已打开'));
    widget.onClose(() => console.log('助手已关闭'));
  </script>
</body>
</html>
```

### 方式二：NPM 安装（React 项目）

```bash
npm install @sensedealai/cue-widget-sdk
# 或
pnpm add @sensedealai/cue-widget-sdk
# 或
yarn add @sensedealai/cue-widget-sdk
```

#### ESM 引入（推荐）

```tsx
import { init, create } from '@sensedealai/cue-widget-sdk';

// 方式一：使用 init (推荐)
const widget = init({
  code: 'your-app-key',
  position: 'bottom-right',
  buttonLabel: '助手',
  modalTitle: 'AI 助手',
});

// 方式二：使用 create (更简洁)
const widget = create({
  code: 'your-app-key',
});

// 控制助手
widget.open();   // 打开助手
widget.close();  // 关闭助手

// 更新配置 (不支持更新 code)
widget.updateConfig({
  position: 'top-left',
  theme: 'dark',
});

// 销毁实例
widget.destroy();
```

#### 直接使用 React 组件

如果你在 React 项目中，也可以直接使用组件：

```tsx
import { CueWidget } from '@sensedealai/cue-widget-sdk';

function App() {
  return (
    <CueWidget
      code="your-app-key"
      position="bottom-right"
      buttonLabel="助手"
      modalTitle="AI 助手"
    />
  );
}
```

## API 参考

### `init(config)` - 初始化 SDK

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| `code` | `string` | ✅ | - | 授权码 |
| `env` | `'development' \| 'test' \| 'production'` | ❌ | `'production'` | API 环境配置 |
| `container` | `string` | ❌ | `body` | 容器元素 ID |
| `position` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | ❌ | `'bottom-right'` | 按钮位置 |
| `buttonLabel` | `string` | ❌ | `'Cue'` | 按钮文字 |
| `modalTitle` | `string` | ❌ | `'AI 助手'` | 弹窗标题 |
| `closeOnClickOutside` | `boolean` | ❌ | `false` | 点击外部是否关闭 |
| `zIndex` | `number` | ❌ | `2000` | 弹窗层级 |
| `primaryColor` | `string` | ❌ | `'#6366f1'` | 主题色 (十六进制) |
| `theme` | `'light' \| 'dark'` | ❌ | `'light'` | 主题模式 |
| `showWidget` | `boolean` | ❌ | `true` | 是否显示挂件 |
| `showWidgetBtn` | `boolean` | ❌ | `true` | 是否显示触发按钮 |
| `showImportReport` | `boolean` | ❌ | `true` | 是否显示报告导入按钮 |
| `onOpen` | `() => void` | ❌ | - | 打开回调 |
| `onClose` | `() => void` | ❌ | - | 关闭回调 |
| `onAuthSuccess` | `(data: AuthTokenResult) => void` | ❌ | - | [认证成功回调](./DEVELOPMENT.md#authtokenresult) |
| `onAuthError` | `(error: Error) => void` | ❌ | - | 认证失败回调 |
| `onImportReport` | `(data: ImportReportData) => void` | ❌ | - | [导入报告回调类型说明](./DEVELOPMENT.md#importreportdata) |
| `window` | `{ url?: string }` | ❌ | - | window 模式配置，配置即启用，详见 [Window 模式](#window-模式---第三方应用集成) |
| `iframe` | `{ name?: string }` | ❌ | - | iframe 模式配置，详见 [iframe 模式](#iframe-模式---嵌入式场景) |

**返回值：** `CueWidgetInstance`

> **提示：** 完整配置类型定义见 [开发文档 - CueWidgetConfig](./DEVELOPMENT.md#cuewidgetconfig)，授权码 `code` 请前往 [Cue 官网](https://cuecue.cn/) 注册获取。

### `CueWidgetInstance` - SDK 实例方法

| 方法 | 参数 | 说明 |
|------|------|------|
| `open()` | - | 打开助手 |
| `close()` | - | 关闭助手 |
| `updateConfig(config)` | [`Partial<CueWidgetConfig>`](./DEVELOPMENT.md#cuewidgetconfig) | 更新配置 (不支持更新 code) |
| `destroy()` | - | 销毁实例 |

## 高级用法

### 多种初始化方式

```tsx
import { init, create } from '@sensedealai/cue-widget-sdk';

// 完整配置
const widget1 = init({
  code: 'your-app-key',
  position: 'bottom-right',
  buttonLabel: 'AI 助手',
  modalTitle: '智能问答',
  theme: 'dark',
  primaryColor: '#4F46E5',
  showImportReport: true,
  onOpen: () => console.log('打开'),
  onClose: () => console.log('关闭'),
  onImportReport: (data) => {
    console.log('报告内容:', data.content);
    console.log('选中来源:', data.sources);
  },
  // ... 其他配置项
});

// 简洁配置 (使用默认值)
const widget2 = create({
  code: 'your-app-key',
});
```

### 动态更新配置

```tsx
const widget = create({
  code: 'your-app-key',
  position: 'bottom-right',
});

// 切换位置
widget.updateConfig({ position: 'top-left' });

// 切换主题
widget.updateConfig({ theme: 'dark', primaryColor: '#10B981' });

// 注意：updateConfig 不支持更新 code
// 如果传入不同的 code，会抛出错误
```

### 事件监听

```tsx
const widget = init({
  code: 'your-app-key',
  onOpen: () => {
    // 助手打开时执行
    console.log('助手已打开');
  },
  onClose: () => {
    // 助手关闭时执行
    console.log('助手已关闭');
  },
  onImportReport: (data) => {
    // 导入报告时执行
    console.log('报告内容:', data.content);
    console.log('选中来源:', data.sources);
  },
});

// 也可以通过实例方法监听
widget.onOpen(() => console.log('打开'));
widget.onClose(() => console.log('关闭'));
```

### Window 模式 - 第三方应用集成

Window 模式用于第三方应用集成场景。认证成功后将 Token 通过 `postMessage` 发送到新窗口。

```html
<script>
  // 方式一：指定跳转 URL（必须是 Cue 租户站点）
  const widget = CueWidgetSDK.init({
    code: 'your-auth-code',
    window: {
      url: 'https://your-tenant.cuecue.cn',
    },
  });

  // 方式二：使用后端返回的 domain_prefix
  const widget2 = CueWidgetSDK.init({
    code: 'your-auth-code',
    window: {},  // 配置即启用
  });
</script>
```

### iframe 模式 - 嵌入式场景

iframe 模式用于嵌入式场景。认证成功后将 Token 通过 `postMessage` 发送到子 iframe（嵌入页面必须是 Cue 租户站点）。

```html
<iframe name="chat-iframe" src="https://your-tenant.cuecue.cn" style="display: none;"></iframe>

<script>
  const widget = CueWidgetSDK.init({
    code: 'your-auth-code',
    iframe: {
      name: 'chat-iframe',
    },
  });
  // 认证成功后再显示 iframe
  if (widget) {
    document.querySelector('iframe[name="chat-iframe"]').style.display = 'block';
  }
</script>
```

> **注意：** iframe 元素应在 `CueWidgetSDK` 初始化完成后才显示在页面上，确保 SDK 认证成功后再展示 iframe。

### 在 Vue 中使用

```html
<template>
  <div id="app"></div>
</template>

<script>
import { create } from '@sensedealai/cue-widget-sdk';

export default {
  mounted() {
    this.widget = create({
      code: 'your-app-key',
    });

    // 3秒后自动打开助手
    setTimeout(() => {
      this.widget.open();
    }, 3000);
  },
  beforeDestroy() {
    if (this.widget) {
      this.widget.destroy();
    }
  },
};
</script>
```

### 在 Angular 中使用

```typescript
import { Component, OnInit, OnDestroy } from '@angular/core';
import { init } from '@sensedealai/cue-widget-sdk';

@Component({
  selector: 'app-root',
  template: `<div id="app"></div>`,
})
export class AppComponent implements OnInit, OnDestroy {
  private widget: any;

  ngOnInit() {
    this.widget = init({
      code: 'your-app-key',
    });
  }

  ngOnDestroy() {
    if (this.widget) {
      this.widget.destroy();
    }
  }
}
```

## 构建命令

```bash
# 开发模式
pnpm dev

# 构建所有格式 (ESM, CJS, UMD)
pnpm build

# 代码检查
pnpm lint

# 代码格式化
pnpm format

# 类型检查
pnpm type-check

# 发布新版本 (需要先配置 standard-version)
pnpm release
```

> **开发指南**: 更多开发流程、发布注意事项等，请参考 [DEVELOPMENT.md](./DEVELOPMENT.md)

## 项目结构

```
cue-widget-sdk/
├── src/
│   ├── index.tsx              # ESM/CJS 入口
│   ├── cue-widget-sdk.tsx     # UMD 入口 + SDK 主逻辑
│   ├── components/            # React 组件
│   │   ├── CueWidget/         # 主组件
│   │   │   ├── index.tsx      # 组件导出
│   │   │   └── TriggerButton.tsx  # 悬浮按钮
│   │   ├── Chat/              # 聊天组件
│   │   │   ├── ChatMain.tsx   # 聊天主界面
│   │   │   ├── TaskHub.tsx    # 任务中心
│   │   │   ├── PartnerSelector.tsx    # 伙伴选择器
│   │   │   ├── PartnerTypeBadge.tsx   # 伙伴类型徽章
│   │   │   ├── PartnerIcon.tsx        # 伙伴图标
│   │   │   ├── OptimizeModal.tsx      # 优化弹窗
│   │   │   └── RunningModal.tsx       # 运行中弹窗
│   │   ├── Report/            # 报告组件
│   │   │   ├── ReportViewer.tsx
│   │   │   ├── SourcesPanel.tsx
│   │   │   ├── ReporterMarkdown.tsx
│   │   │   └── LinkPreview.tsx
│   │   ├── Icons.tsx          # 图标组件
│   │   ├── MarkdownRenderer.tsx  # Markdown 渲染
│   │   └── ui/                # 通用 UI 组件
│   │       ├── Modal.tsx
│   │       ├── SplitPanel.tsx
│   │       ├── InfiniteScroll.tsx
│   │       └── Badge.tsx
│   ├── api/                   # API 请求封装
│   ├── contexts/              # React Context
│   │   ├── AuthContext.tsx    # 认证上下文
│   │   └── CueWidgetContext.tsx
│   ├── hooks/                 # 自定义 Hooks
│   ├── styles/                # 全局样式
│   │   └── globals.css       # Tailwind 样式
│   ├── types/                 # TypeScript 类型
│   ├── utils/                 # 工具函数
│   │   ├── WorkflowEngine.ts  # 工作流引擎
│   │   └── logger.ts          # 日志工具
│   └── config/                # 配置
├── dist/                      # 构建输出
├── rollup.config.js           # 统一构建配置 (ESM/CJS/UMD)
├── package.json
└── tsconfig.json
```

## 浏览器支持

- Chrome >= 90
- Firefox >= 88
- Safari >= 14
- Edge >= 90

## 许可证

MIT License - 详见 [LICENSE](LICENSE) 文件

## 贡献

欢迎提交 Issue 和 Pull Request！