智能助手气泡sdk开发

开发了一个智能助手页面,需要嵌套到系统应用中,为了方便使用,开发了sdk
在这里插入图片描述

/**
 * DeepSeek Bubble SDK
 * 提供一个可拖动的气泡,点击后打开 DeepSeek 聊天界面
 * @param {Object} options 配置选项
 * @param {string} options.aiId 必填,AI的ID
 * @param {string} options.session 必填,会话ID
 * @param {string} [options.position='bottom-right'] 气泡初始位置 (top-left, top-right, bottom-left, bottom-right)
 * @param {string} [options.bubbleColor='#4CAF50'] 气泡颜色
 * @param {string} [options.bubbleIcon='?'] 气泡图标/文字
 * @param {number} [options.bubbleSize=60] 气泡大小(px)
 * @param {string} [options.url=https://localhost:8080/view/aiv1] 接口url
 * @param {string} [options.title=智能助手] 抬头
 */
class DeepSeekBubble {
  constructor(options) {
    if (!options.aiId || !options.session) {
      console.error('DeepSeekBubble: aiId and session are required parameters');
      return;
    }

    this.options = {
      position: 'bottom-right',
      bubbleColor: '#4CAF50',
      bubbleIcon: '?',
      bubbleSize: 60,
      url: "https://deepseek.dev.ihgkj.com/view/aiv1",
      title: "智能助手",
      ...options
    };

    this.isOpen = false;
    this.initPosition = this.calculateInitialPosition();
    this.dragData = { isDragging: false, offsetX: 0, offsetY: 0 };

    this.init();
  }

  init() {
    // 创建气泡元素
    this.createBubble();
    // 创建iframe容器
    this.createIframeContainer();
    // 添加到文档
    document.body.appendChild(this.bubble);
    document.body.appendChild(this.iframeContainer);
    // 设置初始位置
    this.updateBubblePosition(this.initPosition.x, this.initPosition.y);
    // 添加事件监听
    this.addEventListeners();
  }

  createBubble() {
    this.bubble = document.createElement('div');
    this.bubble.style.position = 'fixed';
    this.bubble.style.width = `${this.options.bubbleSize}px`;
    this.bubble.style.height = `${this.options.bubbleSize}px`;
    this.bubble.style.borderRadius = '50%';
    this.bubble.style.backgroundColor = this.options.bubbleColor;
    this.bubble.style.display = 'flex';
    this.bubble.style.alignItems = 'center';
    this.bubble.style.justifyContent = 'center';
    this.bubble.style.color = 'white';
    this.bubble.style.fontSize = '24px';
    this.bubble.style.cursor = 'pointer';
    this.bubble.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
    this.bubble.style.zIndex = '9998';
    this.bubble.style.userSelect = 'none';
    this.bubble.style.transition = 'transform 0.2s';
    this.bubble.textContent = this.options.bubbleIcon;

    // 悬停效果
    this.bubble.addEventListener('mouseenter', () => {
      this.bubble.style.transform = 'scale(1.1)';
    });
    this.bubble.addEventListener('mouseleave', () => {
      this.bubble.style.transform = 'scale(1)';
    });
  }

  createIframeContainer() {
    this.iframeContainer = document.createElement('div');
    this.iframeContainer.style.position = 'fixed';
    this.iframeContainer.style.width = '400px';
    this.iframeContainer.style.height = '700px';
    this.iframeContainer.style.borderRadius = '12px';
    this.iframeContainer.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.2)';
    this.iframeContainer.style.backgroundColor = 'white';
    this.iframeContainer.style.display = 'none';
    this.iframeContainer.style.flexDirection = 'column';
    this.iframeContainer.style.zIndex = '9999';
    this.iframeContainer.style.overflow = 'hidden';

    // 创建头部
    const header = document.createElement('div');
    header.style.padding = '12px 16px';
    header.style.backgroundColor = '#f5f5f5';
    header.style.display = 'flex';
    header.style.justifyContent = 'space-between';
    header.style.alignItems = 'center';
    header.style.borderBottom = '1px solid #e0e0e0';
    header.style.cursor = 'move';

    const title = document.createElement('div');
    title.textContent = `${this.options.title}`;
    title.style.fontWeight = 'bold';

    const closeBtn = document.createElement('div');
    closeBtn.textContent = '×';
    closeBtn.style.fontSize = '24px';
    closeBtn.style.cursor = 'pointer';
    closeBtn.addEventListener('click', () => this.toggleChat(false));

    header.appendChild(title);
    header.appendChild(closeBtn);

    // 创建iframe
    this.iframe = document.createElement('iframe');
    this.iframe.style.flex = '1';
    this.iframe.style.border = 'none';


    this.iframe.src = `${this.options.url}?aiId=${this.options.aiId}&session=${this.options.session}`;
    this.iframeContainer.appendChild(header);
    this.iframeContainer.appendChild(this.iframe);

    // 头部拖动功能
    let isDragging = false;
    let offsetX, offsetY;

    header.addEventListener('mousedown', (e) => {
      isDragging = true;
      offsetX = e.clientX - this.iframeContainer.getBoundingClientRect().left;
      offsetY = e.clientY - this.iframeContainer.getBoundingClientRect().top;
      this.iframeContainer.style.cursor = 'grabbing';
    });

    document.addEventListener('mousemove', (e) => {
      if (!isDragging) return;
      const x = e.clientX - offsetX;
      const y = e.clientY - offsetY;
      this.iframeContainer.style.left = `${x}px`;
      this.iframeContainer.style.top = `${y}px`;
    });

    document.addEventListener('mouseup', () => {
      isDragging = false;
      this.iframeContainer.style.cursor = '';
    });
  }

  addEventListeners() {
    // 气泡点击事件
    this.bubble.addEventListener('click', () => this.toggleChat());

    // 气泡拖动功能
    this.bubble.addEventListener('mousedown', (e) => {
      this.dragData.isDragging = true;
      this.dragData.offsetX = e.clientX - this.bubble.getBoundingClientRect().left;
      this.dragData.offsetY = e.clientY - this.bubble.getBoundingClientRect().top;
      this.bubble.style.cursor = 'grabbing';
    });

    document.addEventListener('mousemove', (e) => {
      if (!this.dragData.isDragging) return;
      const x = e.clientX - this.dragData.offsetX;
      const y = e.clientY - this.dragData.offsetY;
      this.updateBubblePosition(x, y);
    });

    document.addEventListener('mouseup', () => {
      this.dragData.isDragging = false;
      this.bubble.style.cursor = '';
    });
  }

  toggleChat(show) {
    this.isOpen = show !== undefined ? show : !this.isOpen;

    if (this.isOpen) {
      // 显示聊天窗口并定位在气泡附近
      const bubbleRect = this.bubble.getBoundingClientRect();
      let left = bubbleRect.left;
      let top = bubbleRect.top - 600 - 10; // 放在气泡上方

      // 如果上方空间不足,放在下方
      if (top < 10) {
        top = bubbleRect.top + bubbleRect.height + 10;
      }

      // 确保不超出屏幕右侧
      if (left + 400 > window.innerWidth) {
        left = window.innerWidth - 400 - 10;
      }

      this.iframeContainer.style.left = `${left}px`;
      this.iframeContainer.style.top = `${top}px`;
      this.iframeContainer.style.display = 'flex';
    } else {
      this.iframeContainer.style.display = 'none';
    }
  }

  updateBubblePosition(x, y) {
    // 确保气泡不会移出视口
    const maxX = window.innerWidth - this.options.bubbleSize;
    const maxY = window.innerHeight - this.options.bubbleSize;

    const clampedX = Math.max(0, Math.min(x, maxX));
    const clampedY = Math.max(0, Math.min(y, maxY));

    this.bubble.style.left = `${clampedX}px`;
    this.bubble.style.top = `${clampedY}px`;
  }

  calculateInitialPosition() {
    const size = this.options.bubbleSize;
    const margin = 20;

    switch (this.options.position) {
      case 'top-left':
        return { x: margin, y: margin };
      case 'top-right':
        return { x: window.innerWidth - size - margin, y: margin };
      case 'bottom-left':
        return { x: margin, y: window.innerHeight - size - margin };
      case 'bottom-right':
      default:
        return { x: window.innerWidth - size - margin, y: window.innerHeight - size - margin };
    }
  }

  destroy() {
    if (this.bubble && this.bubble.parentNode) {
      this.bubble.parentNode.removeChild(this.bubble);
    }
    if (this.iframeContainer && this.iframeContainer.parentNode) {
      this.iframeContainer.parentNode.removeChild(this.iframeContainer);
    }
    document.removeEventListener('mousemove', this.handleDragMove);
    document.removeEventListener('mouseup', this.handleDragEnd);
  }
}

// 全局访问
window.DeepSeekBubble = DeepSeekBubble;

使用sdk的方法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script src="./sdk-ai.js"></script>
    <script>
        // 初始化气泡
        const deepseekBubble = new DeepSeekBubble({
            aiId: 'gjkg',      // 必填参数
            session: 'YOUR_SESSION',  // 必填参数
            position: 'bottom-right', // 可选,默认'bottom-right'
            bubbleColor: '#4CAF50',   // 可选,气泡颜色
            bubbleIcon: '?',          // 可选,气泡图标/文字
            bubbleSize: 35,            // 可选,气泡大小(px)
            url:"http://localhost:8080/view/aiv1"
        });
    </script>
</body>

</html>

引用示例

    <script src="./sdk-ai.min.js"></script>
    <script>
        // 初始化气泡
        const deepseekBubble = new DeepSeekBubble({
            aiId: 'gjkg',      // 必填参数
            session: 'YOUR_SESSION',  // 必填参数
            position: 'bottom-right', // 可选,默认'bottom-right'
            bubbleColor: '#4CAF50',   // 可选,气泡颜色
            bubbleIcon: '?',          // 可选,气泡图标/文字
            bubbleSize: 35,            // 可选,气泡大小(px)
            url:"http://localhost:8080/view/aiv1"
        });
    </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值