← 返回 技术博客

技术文章

嵌入式BI PaaS三种集成模式深度解析:从iframe嵌入到Headless API定制

嵌入式BI PaaS三种集成模式深度解析:从iframe嵌入到Headless API定制

2026/05/14技术博客HENGSHI22 分钟阅读
嵌入式BIBI PaaS集成模式衡石科技
嵌入式BI PaaS三种集成模式深度解析:从iframe嵌入到Headless API定制

Article body

正文

前言

在企业数字化转型的浪潮中,商业智能(Business Intelligence,BI)已经从独立的数据分析工具演变为深度嵌入企业业务流程的核心能力。传统的BI系统往往作为一个独立的数据分析平台存在,用户需要专门登录访问。然而,随着企业应用场景的复杂化和精细化,越来越多的组织开始寻求将BI能力无缝集成到现有的业务系统中——无论是CRM、ERP、项目管理系统还是自定义开发的数据应用。

这种需求催生了嵌入式BI(Embedded BI)这一细分领域。嵌入式BI PaaS平台通过提供标准化的集成接口和灵活的嵌入机制,让企业能够将数据分析能力直接嵌入到任何Web应用中,实现“数据随业务走”的目标。本文将以衡石科技的BI PaaS平台为例,深入剖析嵌入式BI的三种集成模式,探讨其技术实现细节,并为开发者提供详尽的集成指南。

一、嵌入式BI PaaS概述

1.1 什么是嵌入式BI PaaS

嵌入式BI PaaS(Platform as a Service)是一种专门用于帮助企业将BI能力嵌入到现有应用中的技术平台。与传统的BI工具不同,嵌入式BI PaaS平台将复杂的报表制作、数据连接、权限管理等功能封装为可调用的服务/API,开发者只需通过简单的集成操作,即可在自己的应用中实现数据可视化功能。

一个成熟的嵌入式BI PaaS平台通常具备以下核心特征:

特征描述
零感知嵌入嵌入后的BI组件与宿主应用风格保持一致,用户无需切换系统
多粒度嵌入支持从单个图表到完整仪表盘的全方位嵌入
灵活的权限体系与宿主应用的用户体系无缝对接
API优先设计所有操作均可通过API驱动
多租户支持满足SaaS服务商的差异化需求

1.2 嵌入式BI的价值

对于企业而言,嵌入式BI带来了显著的商业价值:

  1. 用户体验提升:用户无需离开当前工作上下文即可完成数据分析,降低了使用门槛
  2. 开发成本降低:无需从零构建BI能力,复用成熟平台的功能
  3. 数据一致性:统一的数据底座确保各业务系统使用同一套数据口径
  4. 快速迭代:借助平台能力快速响应业务变化,缩短需求交付周期

1.3 衡石科技BI PaaS平台简介

衡石科技是国内领先的嵌入式BI PaaS平台提供商,其平台具备以下技术优势:

  • 集成友好的开放架构:支持零代码整合嵌入
  • 精细化权限控制:与主流身份认证系统无缝对接
  • 丰富的生态集成:已服务WPP、宝马、广汽本田、阳狮集团、国药集团、亚马逊云科技等200+家SaaS生态伙伴
  • 持续迭代的能力:最新6.2版本增强了门户链接和仪表盘容器控件功能

二、嵌入式BI PaaS的三种集成模式

衡石科技BI PaaS平台提供了三种层次的集成模式,从浅到深分别是:分析成果嵌入分析能力嵌入深度集成定制。这三种模式对应着不同的业务场景和技术复杂度,企业可以根据自身需求选择合适的集成深度。

2.1 三种集成模式概览

┌─────────────────────────────────────────────────────────────────────┐
│                    嵌入式BI PaaS集成层次                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   层次三:深度集成定制(Headless API)                              │
│   ┌─────────────────────────────────────────────────────────┐     │
│   │  ▸ 自定义前端交互                                        │     │
│   │  ▸ 完全控制分析流程                                      │     │
│   │  ▸ 定制化数据处理管道                                    │     │
│   └─────────────────────────────────────────────────────────┘     │
│                              ▲                                      │
│   层次二:分析能力嵌入(模块化嵌入)                                │
│   ┌─────────────────────────────────────────────────────────┐     │
│   │  ▸ 数据集开发模块嵌入                                    │     │
│   │  ▸ 仪表盘创作模块嵌入                                    │     │
│   │  ▸ 多租户隔离创作空间                                    │     │
│   └─────────────────────────────────────────────────────────┘     │
│                              ▲                                      │
│   层次一:分析成果嵌入(组件化嵌入)                                │
│   ┌─────────────────────────────────────────────────────────┐     │
│   │  ▸ 完整仪表盘嵌入                                        │     │
│   │  ▸ 单图表/单控件嵌入                                     │     │
│   │  ▸ 灵活参数传递                                          │     │
│   └─────────────────────────────────────────────────────────┘     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2.2 模式一:分析成果嵌入

2.2.1 模式概述

分析成果嵌入是最基础的集成模式,适用于将已经开发好的仪表盘、报表或图表嵌入到目标应用中。这种模式下,BI平台侧的开发和配置工作已经完成,宿主应用只需负责展示和数据范围控制。

典型特征

  • 多粒度嵌入:支持数据应用、完整仪表盘、单图表等多个层级
  • 灵活的参数传递:支持数据参数(过滤条件)和UI参数(样式配置)
  • 外层系统控制:宿主应用完全控制数据范围和展示样式
  • 零前端开发:无需前端开发即可完成集成

2.2.2 技术实现

分析成果嵌入主要通过iframe嵌入SDK嵌入两种方式实现。

方式一:iframe嵌入

iframe嵌入是最简单直接的方式,适用于对交互要求不高的场景:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>嵌入式BI仪表盘示例</title>
    <style>
        body {
            margin: 0;
            padding: 20px;
            font-family: -apple-system, BlinkMacSystemFont, sans-serif;
        }
        .dashboard-container {
            width: 100%;
            height: 800px;
            border: 1px solid #e0e0e0;
            border-radius: 8px;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <h1>销售数据仪表盘</h1>

    <!-- 方式一:基础iframe嵌入 -->
    <div class="dashboard-container">
        <iframe
            src="https://bi-platform.example.com/dashboard/view/abc123"
            width="100%"
            height="100%"
            frameborder="0"
            allowfullscreen>
        </iframe>
    </div>
</body>
</html>

方式二:JavaScript SDK嵌入

JavaScript SDK提供了更丰富的交互能力,支持参数传递和事件监听:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>嵌入式BI SDK示例</title>
    <!-- 引入BI SDK -->
    <script src="https://bi-platform.example.com/sdk/hengshi-sdk.min.js"></script>
    <style>
        #dashboard-container {
            width: 100%;
            height: 800px;
        }
    </style>
</head>
<body>
    <h1>销售数据仪表盘</h1>
    <div id="dashboard-container"></div>

    <script>
        // 初始化BI SDK
        const bi = new HengshiSDK({
            baseUrl: 'https://bi-platform.example.com',
            token: 'YOUR_AUTH_TOKEN',  // 通过后端接口获取
            org: 'your-org-id'
        });

        // 渲染仪表盘
        const dashboard = bi.dashboard({
            container: '#dashboard-container',
            id: 'dashboard-abc123',
            // 数据参数传递 - 控制数据范围
            params: {
                region: '华东',           // 地区过滤
                dateRange: ['2024-01-01', '2024-03-31'],  // 日期范围
                productCategory: ['电子产品', '服装']     // 产品分类
            },
            // UI参数传递 - 控制展示样式
            ui: {
                theme: 'light',           // 主题配置
                showToolbar: false,       // 是否显示工具栏
                showFilters: true,        // 是否显示筛选器
                chartColors: ['#1890ff', '#52c41a', '#faad14']
            }
        });

        // 监听事件
        dashboard.on('chart:click', (event) => {
            console.log('图表点击事件:', event);
            // 处理钻取逻辑
            handleDrillDown(event.data);
        });

        // 动态更新参数
        function updateFilters(newRegion) {
            dashboard.setParams({
                region: newRegion
            });
        }

        // 导出数据
        async function exportData() {
            const data = await dashboard.exportData({
                format: 'excel',
                filename: 'sales-report'
            });
            downloadFile(data);
        }
    </script>
</body>
</html>

2.2.3 后端Token获取

为了安全起见,前端嵌入时需要通过后端获取访问令牌:

# Python后端示例:获取BI平台访问令牌
import requests
import json
from datetime import datetime, timedelta

class BIIntegrationService:
    def __init__(self, bi_base_url, api_key, api_secret):
        self.base_url = bi_base_url
        self.api_key = api_key
        self.api_secret = api_secret

    def get_embed_token(self, user_id, user_name, permissions):
        """
        获取嵌入式访问令牌

        Args:
            user_id: 用户在宿主系统的ID
            user_name: 用户名
            permissions: 用户权限列表,如 ['dashboard:view', 'data:export']

        Returns:
            dict: 包含token和过期时间
        """
        auth_url = f"{self.base_url}/api/v1/auth/embed-token"

        payload = {
            "user": {
                "id": str(user_id),
                "name": user_name,
                "type": "external"  # 外部系统用户
            },
            "permissions": permissions,
            "expire_in": 3600  # 1小时过期
        }

        response = requests.post(
            auth_url,
            json=payload,
            headers={
                "Authorization": f"Bearer {self.api_key}:{self.api_secret}",
                "Content-Type": "application/json"
            }
        )

        if response.status_code == 200:
            return response.json()
        else:
            raise Exception(f"获取token失败: {response.text}")

    def get_dashboard_embed_url(self, dashboard_id, token):
        """
        生成带token的仪表盘嵌入URL

        Args:
            dashboard_id: 仪表盘ID
            token: 访问令牌

        Returns:
            str: 完整的嵌入URL
        """
        return f"{self.base_url}/embed/dashboard/{dashboard_id}?token={token}"


# 使用示例
if __name__ == "__main__":
    service = BIIntegrationService(
        bi_base_url="https://bi-platform.example.com",
        api_key="your_api_key",
        api_secret="your_api_secret"
    )

    # 获取token
    result = service.get_embed_token(
        user_id=12345,
        user_name="张三",
        permissions=["dashboard:view:dashboard-abc123"]
    )

    print(f"Token: {result['token']}")
    print(f"过期时间: {result['expires_at']}")

2.2.4 适用场景

分析成果嵌入模式非常适合以下业务场景:

场景描述优势
个性化报表发布为不同角色用户批量生成定制化报表快速交付,降低开发成本
企业门户集成将BI仪表盘嵌入企业OA或门户系统统一入口,提升用户体验
客户自助服务为客户提供专属的数据分析页面增强客户粘性
数据汇报展示在汇报材料中嵌入实时数据图表数据实时,演示便捷

2.3 模式二:分析能力嵌入

2.3.1 模式概述

当企业需要为终端用户提供完整的数据分析工具时,分析成果嵌入就显得不够灵活了。此时,分析能力嵌入模式能够将BI平台的数据集开发、仪表盘创作等功能模块直接嵌入到宿主应用中,让用户拥有完整的自助分析能力。

核心特点

  • 模块化嵌入:按需选择功能模块(数据集、仪表盘、分析等)
  • 完整的创作体验:用户可以在宿主应用中完成从数据准备到可视化展示的全流程
  • 多租户隔离:为不同用户/租户提供独立的创作空间
  • 深度定制UI:可调整功能模块的展示样式以匹配宿主应用

2.3.2 技术架构

分析能力嵌入的架构设计如下:

┌─────────────────────────────────────────────────────────────────────┐
│                    分析能力嵌入架构                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   ┌─────────────────────────────────────────────────────────────┐  │
│   │                      宿主应用                                │  │
│   │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │  │
│   │  │ 数据集模块  │  │ 仪表盘模块  │  │ 分析工具模块│         │  │
│   │  │ (Dataset)   │  │(Dashboard)  │  │ (Analytics) │         │  │
│   │  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘         │  │
│   │         │                │                │                 │  │
│   │  ┌──────┴────────────────┴────────────────┴──────┐        │  │
│   │  │              统一BI SDK层                       │        │  │
│   │  │   - 认证鉴权  - 事件通信  - 状态同步  - 主题配置 │        │  │
│   │  └──────────────────────┬──────────────────────────┘        │  │
│   └─────────────────────────┼───────────────────────────────────┘  │
│                             │                                       │
│   ┌─────────────────────────┼───────────────────────────────────┐  │
│   │                         ▼                                    │  │
│   │  ┌─────────────────────────────────────────────────────┐   │  │
│   │  │              衡石BI PaaS平台                          │   │  │
│   │  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐    │   │  │
│   │  │  │数据连接 │ │ 数据处理│ │ 可视化  │ │ 权限管理│    │   │  │
│   │  │  │ Manager │ │ Engine  │ │ Engine  │ │ Module  │    │   │  │
│   │  │  └─────────┘ └─────────┘ └─────────┘ └─────────┘    │   │  │
│   │  └─────────────────────────────────────────────────────┘   │  │
│   └─────────────────────────────────────────────────────────────┘  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2.3.3 模块化嵌入实现

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>分析能力嵌入示例</title>
    <script src="https://bi-platform.example.com/sdk/hengshi-sdk.min.js"></script>
    <style>
        /* 定义CSS变量以匹配宿主应用主题 */
        :root {
            --primary-color: #1890ff;
            --secondary-color: #52c41a;
            --border-radius: 8px;
        }

        /* 仪表盘创作模块容器 */
        #dashboard-editor {
            width: 100%;
            height: calc(100vh - 60px);
            border: 1px solid #e8e8e8;
            border-radius: var(--border-radius);
        }

        /* 数据集开发模块容器 */
        #dataset-editor {
            width: 100%;
            height: 600px;
            border: 1px solid #e8e8e8;
            border-radius: var(--border-radius);
        }

        /* 自定义工具栏样式 */
        .custom-toolbar {
            display: flex;
            gap: 10px;
            padding: 10px;
            background: #fafafa;
            border-bottom: 1px solid #e8e8e8;
        }
    </style>
</head>
<body>
    <h1>企业级自助分析平台</h1>

    <!-- 自定义导航 -->
    <div class="custom-toolbar">
        <button onclick="switchModule('dashboard')">仪表盘创作</button>
        <button onclick="switchModule('dataset')">数据集开发</button>
        <button onclick="switchModule('analytics')">高级分析</button>
    </div>

    <!-- 仪表盘创作模块 -->
    <div id="dashboard-editor" style="display: none;"></div>

    <!-- 数据集开发模块 -->
    <div id="dataset-editor" style="display: none;"></div>

    <script>
        const bi = new HengshiSDK({
            baseUrl: 'https://bi-platform.example.com',
            token: 'YOUR_TOKEN',
            org: 'enterprise-org-id'
        });

        // 初始化仪表盘创作模块
        function initDashboardEditor() {
            const editor = bi.module('dashboard-editor', {
                mode: 'edit',  // edit 或 view
                showChartTypes: ['bar', 'line', 'pie', 'table', 'scatter'],
                showDataSources: true,
                allowPublish: true,
                // 主题配置
                theme: {
                    primaryColor: '#1890ff',
                    fontFamily: 'PingFang SC, Microsoft YaHei',
                    compactMode: false
                },
                // 多租户隔离配置
                workspace: {
                    id: 'tenant-workspace-001',
                    name: '华东区域租户'
                }
            });

            // 保存事件
            editor.on('save', (data) => {
                console.log('仪表盘已保存:', data);
                notifyBackend(data);
            });

            // 发布事件
            editor.on('publish', (data) => {
                console.log('仪表盘已发布:', data);
                // 触发后续业务流程
            });

            return editor;
        }

        // 初始化数据集开发模块
        function initDatasetEditor() {
            const editor = bi.module('dataset-editor', {
                mode: 'edit',
                // 数据源配置
                allowedDataSources: ['mysql', 'postgresql', 'api'],
                // SQL编辑权限
                sqlEditorEnabled: true,
                // 数据预览行数
                previewRows: 100
            });

            editor.on('save', (data) => {
                console.log('数据集已保存:', data);
            });

            return editor;
        }

        // 模块切换
        let currentModule = null;

        function switchModule(moduleName) {
            // 隐藏所有模块
            document.getElementById('dashboard-editor').style.display = 'none';
            document.getElementById('dataset-editor').style.display = 'none';

            // 显示目标模块
            if (moduleName === 'dashboard') {
                document.getElementById('dashboard-editor').style.display = 'block';
                if (!currentModule) {
                    currentModule = initDashboardEditor();
                }
            } else if (moduleName === 'dataset') {
                document.getElementById('dataset-editor').style.display = 'block';
                if (!currentModule) {
                    currentModule = initDatasetEditor();
                }
            }
        }

        // 后端通知
        async function notifyBackend(data) {
            await fetch('/api/bi/notifications', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    event: 'dashboard_saved',
                    data: data,
                    timestamp: new Date().toISOString()
                })
            });
        }

        // 初始化
        switchModule('dashboard');
    </script>
</body>
</html>

2.3.4 多租户隔离实现

对于SaaS服务商或大型企业,多租户隔离是核心需求:

// 多租户隔离配置示例
class MultiTenantIntegration {
    constructor(biPlatformUrl) {
        this.bi = new HengshiSDK({
            baseUrl: biPlatformUrl
        });
    }

    // 创建租户工作空间
    async createTenantWorkspace(tenantInfo) {
        return await this.bi.admin('workspace').create({
            name: tenantInfo.name,
            slug: tenantInfo.slug,  // URL友好标识
            settings: {
                // 数据隔离策略
                dataIsolation: 'strict',
                // 资源配额
                quotas: {
                    dashboards: 50,
                    datasets: 20,
                    users: 100,
                    storage: '10GB'
                },
                // 功能开关
                features: {
                    sqlEditor: true,
                    aiAssistant: tenantInfo.plan === 'pro',
                    customThemes: true
                }
            }
        });
    }

    // 为租户用户分配权限
    async assignTenantPermissions(tenantId, userId, role) {
        const rolePermissions = {
            admin: ['*'],
            analyst: [
                'dashboard:create',
                'dashboard:edit',
                'dashboard:view',
                'dataset:create',
                'dataset:edit',
                'dataset:view',
                'data:export'
            ],
            viewer: [
                'dashboard:view',
                'data:export:limited'
            ]
        };

        return await this.bi.admin('permission').assign({
            tenantId,
            userId,
            permissions: rolePermissions[role] || rolePermissions.viewer
        });
    }

    // 获取租户隔离的SDK实例
    getTenantSDK(tenantId, token) {
        return new HengshiSDK({
            baseUrl: this.bi.config.baseUrl,
            token,
            org: tenantId,  // 关键:使用租户ID作为组织标识
            // 强制数据隔离
            isolation: {
                type: 'tenant',
                tenantId
            }
        });
    }
}

2.3.5 适用场景

分析能力嵌入模式适合以下业务场景:

场景描述典型用户
自助BI工具为业务人员提供数据分析工具业务分析师、数据专员
SaaS产品增强在SaaS产品中嵌入BI模块SaaS平台运营商
行业解决方案垂直行业的定制化分析能力行业软件开发商
企业内部平台构建统一的企业数据分析平台企业IT部门

2.4 模式三:深度集成定制

2.4.1 模式概述

当企业需要完全掌控分析前端的交互体验和业务流程时,前两种模式就无法满足需求了。此时,深度集成定制模式通过提供完整的API接口,让开发者能够以衡石BI PaaS为分析底座,从零构建完全定制化的前端应用。

核心能力

  • Headless API:无头API,支持任意前端框架
  • 完整的数据管道控制:自定义数据处理流程
  • 灵活的交互定制:打造独特的用户体验
  • 流程编排:根据业务需求调整分析流程

2.4.2 API架构设计

┌─────────────────────────────────────────────────────────────────────┐
│                      Headless BI API架构                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   ┌─────────────────────────────────────────────────────────────┐  │
│   │                    定制前端应用                             │  │
│   │   React / Vue / Angular / Solid / Svelte / 任意框架         │  │
│   └──────────────────────────┬──────────────────────────────────┘  │
│                              │                                       │
│   ┌──────────────────────────▼──────────────────────────────────┐  │
│   │                   BI API Gateway                             │  │
│   │   ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐           │  │
│   │   │ Auth    │ │ Query   │ │ Dataset │ │Dashboard│           │  │
│   │   │ API     │ │ API     │ │ API     │ │ API     │           │  │
│   │   └─────────┘ └─────────┘ └─────────┘ └─────────┘           │  │
│   └──────────────────────────┬──────────────────────────────────┘  │
│                              │                                       │
│   ┌──────────────────────────▼──────────────────────────────────┐  │
│   │                   衡石BI PaaS Core                           │  │
│   │   ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐           │  │
│   │   │ 数据    │ │ 语义    │ │ 计算    │ │ 缓存    │           │  │
│   │   │ 连接器  │ │ 模型    │ │ 引擎    │ │ 引擎    │           │  │
│   │   └─────────┘ └─────────┘ └─────────┘ └─────────┘           │  │
│   └───────────────────────────────────────────────────────────────┘  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2.4.3 核心API接口

认证API

// 认证相关API
class BIAuthClient {
    constructor(baseUrl) {
        this.baseUrl = baseUrl;
    }

    // SSO登录 (SAML2示例)
    async samlLogin(redirectUrl) {
        const response = await fetch(`${this.baseUrl}/api/v1/auth/saml/init`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                idp: 'authing',  // 支持: teams, authing, okta等
                redirectUrl
            })
        });

        const { samlUrl } = await response.json();
        window.location.href = samlUrl;
    }

    // JWT Token验证
    async validateJWT(token) {
        const response = await fetch(`${this.baseUrl}/api/v1/auth/jwt/validate`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${token}`,
                'Content-Type': 'application/json'
            }
        });

        return await response.json();
    }

    // 外部系统Token交换
    async exchangeToken(externalToken) {
        const response = await fetch(`${this.baseUrl}/api/v1/auth/token/exchange`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                provider: 'external',
                token: externalToken,
                scope: ['dashboard:read', 'data:query']
            })
        });

        return await response.json();
    }
}

数据查询API

// 数据查询API
class BIQueryClient {
    constructor(baseUrl, accessToken) {
        this.baseUrl = baseUrl;
        this.accessToken = accessToken;
    }

    // 执行SQL查询
    async executeQuery(sql, options = {}) {
        const response = await fetch(`${this.baseUrl}/api/v1/query/sql`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${this.accessToken}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                sql,
                timeout: options.timeout || 30000,
                // 查询参数
                params: options.params || {},
                // 缓存策略
                cache: {
                    enabled: options.cache !== false,
                    ttl: options.cacheTTL || 300
                }
            })
        });

        if (!response.ok) {
            const error = await response.json();
            throw new Error(error.message);
        }

        return await response.json();
    }

    // 通过语义模型查询
    async queryFromModel(modelId, query) {
        const response = await fetch(`${this.baseUrl}/api/v1/query/model/${modelId}`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${this.accessToken}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                measures: query.measures || [],
                dimensions: query.dimensions || [],
                filters: query.filters || [],
                orders: query.orders || [],
                limit: query.limit || 1000
            })
        });

        return await response.json();
    }

    // 图表数据查询
    async queryChartData(chartId, params = {}) {
        const response = await fetch(
            `${this.baseUrl}/api/v1/chart/${chartId}/data?${new URLSearchParams(params)}`,
            {
                headers: {
                    'Authorization': `Bearer ${this.accessToken}`
                }
            }
        );

        return await response.json();
    }
}

仪表盘管理API

// 仪表盘管理API
class BIDashboardClient {
    constructor(baseUrl, accessToken) {
        this.baseUrl = baseUrl;
        this.accessToken = accessToken;
    }

    // 获取仪表盘列表
    async listDashboards(options = {}) {
        const params = new URLSearchParams({
            page: options.page || 1,
            pageSize: options.pageSize || 20,
            folderId: options.folderId || '',
            tag: options.tag || ''
        });

        const response = await fetch(
            `${this.baseUrl}/api/v1/dashboards?${params}`,
            {
                headers: {
                    'Authorization': `Bearer ${this.accessToken}`
                }
            }
        );

        return await response.json();
    }

    // 获取仪表盘详情
    async getDashboard(dashboardId) {
        const response = await fetch(
            `${this.baseUrl}/api/v1/dashboard/${dashboardId}`,
            {
                headers: {
                    'Authorization': `Bearer ${this.accessToken}`
                }
            }
        );

        return await response.json();
    }

    // 创建仪表盘
    async createDashboard(dashboard) {
        const response = await fetch(`${this.baseUrl}/api/v1/dashboard`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${this.accessToken}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                name: dashboard.name,
                description: dashboard.description,
                folderId: dashboard.folderId,
                layout: dashboard.layout,
                theme: dashboard.theme
            })
        });

        return await response.json();
    }

    // 更新仪表盘
    async updateDashboard(dashboardId, updates) {
        const response = await fetch(`${this.baseUrl}/api/v1/dashboard/${dashboardId}`, {
            method: 'PATCH',
            headers: {
                'Authorization': `Bearer ${this.accessToken}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(updates)
        });

        return await response.json();
    }

    // 发布仪表盘
    async publishDashboard(dashboardId) {
        const response = await fetch(
            `${this.baseUrl}/api/v1/dashboard/${dashboardId}/publish`,
            {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${this.accessToken}`
                }
            }
        );

        return await response.json();
    }

    // 导出仪表盘
    async exportDashboard(dashboardId) {
        const response = await fetch(
            `${this.baseUrl}/api/v1/dashboard/${dashboardId}/export`,
            {
                headers: {
                    'Authorization': `Bearer ${this.accessToken}`
                }
            }
        );

        return await response.blob();
    }
}

2.4.4 React集成示例

以下是一个使用React和Headless API构建完全定制化BI前端的完整示例:

// React BI组件示例
import React, { useState, useEffect, useCallback } from 'react';

// API客户端
import { BIAuthClient, BIQueryClient, BIDashboardClient } from './bi-clients';

// 自定义图表组件
import { CustomBarChart, CustomLineChart, CustomTable } from './charts';

// 主题配置
const theme = {
    colors: ['#1890ff', '#52c41a', '#faad14', '#f5222d', '#722ed1'],
    fontFamily: 'PingFang SC, Microsoft YaHei',
    backgroundColor: '#ffffff'
};

export const EmbeddedBI: React.FC = {
    orgId: string;
    userToken: string;
}> = ({ orgId, userToken }) => {
    const [dashboards, setDashboards] = useState([]);
    const [currentDashboard, setCurrentDashboard] = useState(null);
    const [chartData, setChartData] = useState({});
    const [filters, setFilters] = useState({});

    // 初始化API客户端
    const authClient = new BIAuthClient('https://bi-platform.example.com');
    const queryClient = new BIQueryClient('https://bi-platform.example.com', userToken);
    const dashboardClient = new BIDashboardClient('https://bi-platform.example.com', userToken);

    // 加载仪表盘列表
    useEffect(() => {
        const loadDashboards = async () => {
            try {
                const result = await dashboardClient.listDashboards({
                    folderId: orgId
                });
                setDashboards(result.data);
            } catch (error) {
                console.error('加载仪表盘失败:', error);
            }
        };

        loadDashboards();
    }, [orgId]);

    // 加载仪表盘数据
    const loadDashboardData = useCallback(async (dashboardId: string) => {
        try {
            const dashboard = await dashboardClient.getDashboard(dashboardId);
            setCurrentDashboard(dashboard);

            // 为每个图表加载数据
            const dataPromises = dashboard.charts.map(async (chart) => {
                const data = await queryClient.queryChartData(chart.id, filters);
                return { [chart.id]: data };
            });

            const dataResults = await Promise.all(dataPromises);
            const newChartData = Object.assign({}, ...dataResults);
            setChartData(newChartData);
        } catch (error) {
            console.error('加载仪表盘数据失败:', error);
        }
    }, [filters]);

    // 处理筛选器变化
    const handleFilterChange = useCallback((filterName: string, value: any) => {
        setFilters(prev => ({
            ...prev,
            [filterName]: value
        }));
    }, []);

    // 渲染图表
    const renderChart = (chart: any) => {
        const data = chartData[chart.id];
        if (!data) return <div>Loading...</div>;

        const props = {
            data: data.result,
            theme,
            ...chart.config
        };

        switch (chart.type) {
            case 'bar':
                return <CustomBarChart {...props} />;
            case 'line':
                return <CustomLineChart {...props} />;
            case 'table':
                return <CustomTable {...props} />;
            default:
                return <div>不支持的图表类型</div>;
        }
    };

    return (
        <div className="embedded-bi-container">
            {/* 仪表盘选择器 */}
            <div className="dashboard-selector">
                <select
                    onChange={(e) => loadDashboardData(e.target.value)}
                    value={currentDashboard?.id || ''}
                >
                    <option value="">选择仪表盘</option>
                    {dashboards.map(d => (
                        <option key={d.id} value={d.id}>{d.name}</option>
                    ))}
                </select>
            </div>

            {/* 筛选器区域 */}
            {currentDashboard?.filters && (
                <div className="filters-panel">
                    {currentDashboard.filters.map(filter => (
                        <FilterComponent
                            key={filter.id}
                            filter={filter}
                            value={filters[filter.paramName]}
                            onChange={(value) => handleFilterChange(filter.paramName, value)}
                        />
                    ))}
                </div>
            )}

            {/* 图表网格 */}
            {currentDashboard && (
                <div className="chart-grid">
                    {currentDashboard.charts.map(chart => (
                        <div
                            key={chart.id}
                            className="chart-item"
                            style={{
                                gridColumn: `span ${chart.layout.cols || 1}`,
                                gridRow: `span ${chart.layout.rows || 1}`
                            }}
                        >
                            <div className="chart-header">
                                <h3>{chart.title}</h3>
                            </div>
                            <div className="chart-body">
                                {renderChart(chart)}
                            </div>
                        </div>
                    ))}
                </div>
            )}
        </div>
    );
};

2.4.5 适用场景

深度集成定制模式适合以下业务场景:

场景描述技术要求
定制化BI应用从零构建独特的BI产品前端开发能力强
嵌入式分析SDK封装为可分发的SDK架构设计能力
流程驱动分析将分析嵌入业务流程业务理解能力强
AI增强分析集成AI助手能力AI集成能力

三、集成开放层技术要点

无论选择哪种集成模式,衡石BI PaaS平台都提供了完善的技术支持,确保集成的稳定性和安全性。

3.1 认证与权限体系

3.1.1 SSO登录支持

衡石BI PaaS支持多种SSO登录方式,确保与宿主系统的身份体系无缝对接:

// SSO配置示例
const ssoConfig = {
    // Microsoft Teams集成
    teams: {
        enabled: true,
        tenantId: 'your-teams-tenant-id',
        clientId: 'your-app-client-id'
    },

    // Authing SAML2集成
    authing: {
        enabled: true,
        domain: 'your-company.authing.cn',
        appId: 'your-app-id'
    },

    // JWT令牌验证
    jwt: {
        enabled: true,
        issuer: 'your-auth-service',
        secretKey: 'your-secret-key',
        algorithms: ['RS256']
    }
};

3.1.2 精细化权限控制

┌─────────────────────────────────────────────────────────────────────┐
│                    权限控制层次                                     │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   组织层 (Organization)                                             │
│   ├── 组织管理员                                                    │
│   └── 组织成员                                                      │
│           │                                                         │
│           ▼                                                         │
│   工作空间层 (Workspace)                                             │
│   ├── 工作空间管理员                                                │
│   ├── 分析师                                                        │
│   └── 查看者                                                        │
│           │                                                         │
│           ▼                                                         │
│   资源层 (Resource)                                                  │
│   ├── 仪表盘: 创建/编辑/查看/删除/导出                              │
│   ├── 数据集: 创建/编辑/查看/删除                                   │
│   └── 数据源: 创建/编辑/查看/删除                                    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

3.2 CORS配置

跨域资源共享(CORS)是前端集成中的常见问题。衡石BI PaaS支持动态配置CORS:

// CORS配置
const corsConfig = {
    allowedOrigins: [
        'https://app.example.com',
        'https://portal.example.com',
        'http://localhost:3000'  // 开发环境
    ],
    allowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
    allowedHeaders: [
        'Content-Type',
        'Authorization',
        'X-Requested-With'
    ],
    credentials: true,
    maxAge: 86400  // 预检请求缓存时间
};

3.3 AI助手SDK

衡石6.x版本提供了AI助手SDK,支持在React应用中快速集成智能分析能力:

// AI助手集成示例
import { AIAssistant } from '@hengshi/ai-sdk-react';

const App = () => {
    return (
        <BIProvider
            baseUrl="https://bi-platform.example.com"
            token={userToken}
        >
            <AIAssistant
                // AI助手配置
                theme="dark"
                position="bottom-right"
                placeholder="输入问题,我来帮你分析..."

                // 功能配置
                capabilities={[
                    'natural_language_query',  // 自然语言查询
                    'chart_recommendation',     // 图表推荐
                    'insight_generation',      // 洞察生成
                    'sql_assistant'            // SQL助手
                ]}

                // 数据范围限制
                dataScope={{
                    datasets: ['sales_data', 'customer_data'],
                    restrictions: ['region:华东']  // 数据权限
                }}

                // 回调函数
                onQuery={handleQuery}
                onError={handleError}
            />
        </BIProvider>
    );
};

四、版本更新:6.2版本集成增强

衡石BI PaaS平台的6.2版本带来了重要的集成增强功能:

功能描述集成价值
门户链接快速定位支持通过URL直接定位到发布目录简化导航,提升用户体验
仪表盘容器控件仪表盘可作为整体导入导出支持整体方案迁移和部署

4.1 门户链接增强

// 6.2版本门户链接支持
const portalUrl = `${biBaseUrl}/portal/${orgId}/${folderId}`;
const dashboardUrl = `${portalUrl}/dashboard/${dashboardId}`;

// 直接定位到特定目录
const folderUrl = `${portalUrl}/folder/${folderId}?view=list`;

4.2 仪表盘容器导入导出

// 导出仪表盘包(含容器)
const exportPackage = await dashboardClient.exportDashboard('dashboard-123', {
    includeContainer: true,  // 包含容器样式
    includeData: false,      // 不包含数据
    format: 'json'
});

// 导入仪表盘包
await dashboardClient.importDashboard({
    package: exportPackage,
    targetFolder: 'new-folder-id',
    overwrite: false
});

五、总结与最佳实践

5.1 三种集成模式对比

维度分析成果嵌入分析能力嵌入深度集成定制
集成复杂度
前端开发量大量
定制灵活性
交付周期
适合场景快速上线产品增强独立产品
技术要求基础Web技能前端开发能力全栈能力

5.2 集成最佳实践

  1. 从简单开始:优先考虑分析成果嵌入,根据业务需求逐步深入
  2. 注重安全性:始终通过后端获取访问令牌,避免前端暴露敏感信息
  3. 关注用户体验:确保嵌入后的组件与宿主应用风格一致
  4. 做好监控:集成完成后监控API调用和性能指标
  5. 版本管理:关注BI平台的版本更新,及时适配新特性

5.3 生态伙伴案例

衡石BI PaaS已经成功服务了众多行业领军企业,包括:

  • 汽车行业:宝马、广汽本田
  • 广告传媒:WPP、阳狮集团、蓝色光标
  • 医药健康:国药集团
  • 科技企业:亚马逊云科技
  • 消费品牌:太太乐、元气森林

同时,平台已与200+家SaaS生态伙伴建立合作,包括菲尼克斯电气、中国航信、深信服、浪潮云、金蝶云、致远互联等知名企业。


结语

嵌入式BI PaaS正在成为企业数字化转型的重要基础设施。通过本文介绍的三种集成模式,企业可以根据自身的技术能力和业务需求,选择最适合的集成深度。衡石科技作为国内领先的嵌入式BI PaaS平台,凭借其完善的API体系、灵活的嵌入机制和丰富的行业经验,正在帮助越来越多的企业实现数据能力的敏捷交付。

无论是需要快速嵌入现成仪表盘的初创企业,还是希望打造完全定制化BI产品的大型组织,衡石BI PaaS都能提供针对性的解决方案,值得深入探索和实践。

HENGSHI SENSE

丰富的资源 完整的生态

邀您成为衡石伙伴

立即加入

企业级部署、产品集成与试用咨询均可快速响应