# aPaaS Native Chart Components with Bitable Connector
Complete guide for setting up Feishu/Lark aPaaS chart components with Bitable data source integration.
## Table of Contents
1. [Overview](#overview)
2. [Prerequisites](#prerequisites)
3. [Data Request Setup](#data-request-setup)
4. [Chart Component Configurations](#chart-component-configurations)
5. [Event Binding](#event-binding)
6. [Integration Steps](#integration-steps)
7. [Troubleshooting](#troubleshooting)
## Overview
This guide demonstrates how to connect Bitable tables to aPaaS native chart components for real-time data visualization. The approach uses aPaaS's built-in data connectors and chart components to create interactive dashboards without custom code.
### Key Components
- **Bitable**: Feishu's database/spreadsheet hybrid for structured data storage
- **aPaaS**: Feishu's low-code application platform for building custom apps
- **Data Request**: aPaaS's built-in API connector for fetching data
- **Chart Components**: Native visualization components (metric cards, line/bar/pie charts)
### Project Context
- **aPaaS App ID**: `Dffwb10dwaz6UZs6c4HlWyV3g7c`
- **aPaaS Page ID**: `pgeEOroex4nCBQxc`
- **Bitable app_token**: `C8kmbTsqoa6rBesTKRpl8nV8gHd`
- **Table ID**: `tblG4uuUvbwfvI9Z`
## Prerequisites
### Required Access
1. **Feishu/Lark Account** with access to:
- Bitable workspace
- aPaaS platform
- Developer console
2. **API Credentials**:
- App ID and App Secret (for tenant access token)
- Personal Base Token (optional, for user-specific access)
3. **Permissions**:
- Read access to the Bitable table
- Edit access to the aPaaS application
### Bitable API Endpoint
The Bitable API for listing records is available at:
```
POST https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/search
```
## Data Request Setup
### Step 1: Create Data Request in aPaaS
1. **Navigate to Data Sources**:
- Open your aPaaS application
- Go to "Data Sources" or "数据源" section
- Click "Add Data Request" or "添加数据请求"
2. **Configure API Connection**:
```json
{
"name": "getTikTokData",
"method": "POST",
"url": "https://open.feishu.cn/open-apis/bitable/v1/apps/C8kmbTsqoa6rBesTKRpl8nV8gHd/tables/tblG4uuUvbwfvI9Z/records/search",
"headers": {
"Authorization": "Bearer {{tenant_access_token}}",
"Content-Type": "application/json"
},
"body": {
"field_names": [
"Date",
"Views",
"Likes",
"Comments",
"Shares",
"Followers",
"Engagement_Rate"
],
"page_size": 500,
"sort": [
{
"field_name": "Date",
"desc": false
}
]
}
}
```
### Step 2: Authentication Configuration
**Option A: Tenant Access Token (Recommended)**
```json
{
"auth": {
"type": "custom",
"tokenEndpoint": "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
"tokenMethod": "POST",
"tokenBody": {
"app_id": "{{APP_ID}}",
"app_secret": "{{APP_SECRET}}"
},
"tokenPath": "tenant_access_token"
}
}
```
**Option B: Personal Base Token**
```json
{
"headers": {
"Authorization": "Bearer {{PERSONAL_BASE_TOKEN}}",
"Content-Type": "application/json"
}
}
```
### Step 3: Field Mapping Configuration
Define how Bitable fields map to chart data:
```json
{
"fieldMapping": {
"dateField": "Date",
"metrics": {
"views": "Views",
"likes": "Likes",
"comments": "Comments",
"shares": "Shares",
"followers": "Followers",
"engagementRate": "Engagement_Rate"
}
},
"transformations": {
"dateFormat": "YYYY-MM-DD",
"numberFormat": {
"decimals": 2,
"useGrouping": true
}
}
}
```
### Step 4: Response Data Structure
Expected response from Bitable API:
```json
{
"code": 0,
"msg": "success",
"data": {
"has_more": false,
"page_token": "",
"total": 30,
"items": [
{
"record_id": "recXXXXXX",
"fields": {
"Date": 1698768000000,
"Views": 15234,
"Likes": 1823,
"Comments": 342,
"Shares": 189,
"Followers": 25678,
"Engagement_Rate": 15.2
}
}
]
}
}
```
### Step 5: Data Processing
Configure data processing in aPaaS:
```javascript
// Data transformation expression
function processData(response) {
return response.data.items.map(item => ({
date: new Date(item.fields.Date).toISOString().split('T')[0],
views: item.fields.Views,
likes: item.fields.Likes,
comments: item.fields.Comments,
shares: item.fields.Shares,
followers: item.fields.Followers,
engagementRate: item.fields.Engagement_Rate
}));
}
```
## Chart Component Configurations
### 1. Metric Card Component
**Use Case**: Display single KPI values with optional comparison
```json
{
"component": "MetricCard",
"config": {
"title": "Total Views",
"dataSource": "getTikTokData",
"valueExpression": "{{sum(data.views)}}",
"format": {
"type": "number",
"notation": "compact",
"maximumFractionDigits": 1
},
"comparison": {
"enabled": true,
"previousPeriod": "last_30_days",
"showPercentage": true
},
"style": {
"backgroundColor": "#FFFFFF",
"borderRadius": "8px",
"padding": "16px",
"icon": "👁️",
"iconColor": "#3370FF"
}
},
"binding": {
"value": "{{sum(getTikTokData.items.map(i => i.fields.Views))}}"
}
}
```
**Multiple Metric Cards Example**:
```json
[
{
"title": "Total Likes",
"value": "{{sum(data.likes)}}",
"icon": "❤️",
"change": "+12.5%"
},
{
"title": "Avg Engagement Rate",
"value": "{{avg(data.engagementRate)}}%",
"icon": "📊",
"change": "+3.2%"
},
{
"title": "Total Followers",
"value": "{{max(data.followers)}}",
"icon": "👥",
"change": "+8.7%"
}
]
```
### 2. Line Chart Component
**Use Case**: Display trends over time
```json
{
"component": "LineChart",
"config": {
"title": "Views & Engagement Trend",
"dataSource": "getTikTokData",
"xAxis": {
"field": "Date",
"type": "time",
"label": "Date",
"format": "MMM DD"
},
"yAxis": [
{
"field": "Views",
"label": "Views",
"position": "left",
"format": "0,0"
},
{
"field": "Engagement_Rate",
"label": "Engagement Rate (%)",
"position": "right",
"format": "0.0"
}
],
"series": [
{
"field": "Views",
"name": "Daily Views",
"type": "line",
"color": "#3370FF",
"smooth": true,
"yAxisIndex": 0,
"showSymbol": true,
"symbolSize": 6
},
{
"field": "Engagement_Rate",
"name": "Engagement Rate",
"type": "line",
"color": "#00C48C",
"smooth": true,
"yAxisIndex": 1,
"lineStyle": {
"type": "dashed"
}
}
],
"legend": {
"show": true,
"position": "top"
},
"tooltip": {
"trigger": "axis",
"shared": true
},
"grid": {
"left": "10%",
"right": "10%",
"bottom": "10%",
"top": "15%"
}
},
"binding": {
"data": "{{processData(getTikTokData)}}"
}
}
```
### 3. Bar Chart Component
**Use Case**: Compare metrics across categories or time periods
```json
{
"component": "BarChart",
"config": {
"title": "Social Engagement Breakdown",
"dataSource": "getTikTokData",
"orientation": "vertical",
"xAxis": {
"field": "Date",
"type": "category",
"label": "Date"
},
"yAxis": {
"label": "Count",
"format": "0,0"
},
"series": [
{
"field": "Likes",
"name": "Likes",
"color": "#FF3B69",
"stack": "engagement"
},
{
"field": "Comments",
"name": "Comments",
"color": "#3370FF",
"stack": "engagement"
},
{
"field": "Shares",
"name": "Shares",
"color": "#00C48C",
"stack": "engagement"
}
],
"barWidth": "60%",
"legend": {
"show": true,
"position": "bottom"
},
"tooltip": {
"trigger": "axis",
"axisPointer": {
"type": "shadow"
}
}
},
"binding": {
"data": "{{getTikTokData.items.slice(0, 10)}}"
}
}
```
**Horizontal Bar Chart (Top 10)**:
```json
{
"component": "BarChart",
"config": {
"title": "Top 10 Posts by Views",
"orientation": "horizontal",
"dataSource": "getTikTokData",
"xAxis": {
"field": "Views",
"type": "value"
},
"yAxis": {
"field": "Date",
"type": "category"
},
"series": [
{
"field": "Views",
"name": "Views",
"color": "#3370FF"
}
],
"sort": {
"field": "Views",
"order": "desc"
},
"limit": 10
}
}
```
### 4. Pie Chart Component
**Use Case**: Show distribution or composition
```json
{
"component": "PieChart",
"config": {
"title": "Engagement Distribution",
"dataSource": "getTikTokData",
"series": [
{
"type": "pie",
"radius": ["40%", "70%"],
"data": [
{
"name": "Likes",
"value": "{{sum(data.likes)}}",
"color": "#FF3B69"
},
{
"name": "Comments",
"value": "{{sum(data.comments)}}",
"color": "#3370FF"
},
{
"name": "Shares",
"value": "{{sum(data.shares)}}",
"color": "#00C48C"
}
],
"label": {
"show": true,
"formatter": "{b}: {d}%"
},
"emphasis": {
"itemStyle": {
"shadowBlur": 10,
"shadowOffsetX": 0,
"shadowColor": "rgba(0, 0, 0, 0.5)"
}
}
}
],
"legend": {
"show": true,
"position": "right",
"orient": "vertical"
}
},
"binding": {
"data": "{{aggregateEngagement(getTikTokData)}}"
}
}
```
**Donut Chart Variant**:
```json
{
"component": "PieChart",
"config": {
"title": "Content Performance",
"series": [
{
"type": "pie",
"radius": ["50%", "70%"],
"center": ["50%", "50%"],
"avoidLabelOverlap": true,
"itemStyle": {
"borderRadius": 8,
"borderColor": "#fff",
"borderWidth": 2
}
}
]
}
}
```
## Event Binding
### Click Interactions
**1. Chart Click Event**
```json
{
"events": {
"onClick": {
"action": "filter",
"target": "otherChart",
"expression": "{{item.date}}"
}
}
}
```
**2. Metric Card Click**
```json
{
"events": {
"onClick": {
"action": "navigate",
"target": "detailPage",
"params": {
"metric": "{{component.title}}",
"value": "{{component.value}}"
}
}
}
}
```
### Data Filtering
**Set up filter connections between components**:
```json
{
"filters": [
{
"id": "dateRangeFilter",
"type": "dateRange",
"defaultValue": {
"start": "{{today(-30)}}",
"end": "{{today()}}"
},
"affects": ["lineChart1", "barChart1", "metricCards"]
},
{
"id": "metricFilter",
"type": "dropdown",
"options": ["Views", "Likes", "Comments", "Shares"],
"defaultValue": "Views",
"affects": ["lineChart1"]
}
]
}
```
### Cross-Component Communication
**Example: Dashboard with linked charts**
```json
{
"dashboard": {
"components": [
{
"id": "dateSelector",
"type": "DateRangePicker",
"events": {
"onChange": {
"broadcast": "dateChanged",
"payload": "{{selectedRange}}"
}
}
},
{
"id": "mainChart",
"type": "LineChart",
"listeners": {
"dateChanged": {
"action": "updateData",
"params": {
"dateRange": "{{event.payload}}"
}
}
}
},
{
"id": "summaryCards",
"type": "MetricCardGroup",
"listeners": {
"dateChanged": {
"action": "refresh"
}
}
}
]
}
}
```
### Event Types
| Event Type | Trigger | Use Case |
|------------|---------|----------|
| `onClick` | User clicks on chart element | Filter, navigate, show details |
| `onHover` | User hovers over element | Show tooltip, highlight related data |
| `onChange` | Data or selection changes | Update dependent components |
| `onLoad` | Component loads | Initialize data, set defaults |
| `onRefresh` | Data refreshes | Update UI, show loading state |
## Integration Steps
### Step-by-Step Setup Guide
#### Phase 1: Prepare Bitable Data Source
1. **Open your Bitable**:
- Navigate to: `https://bytedance.feishu.cn/base/C8kmbTsqoa6rBesTKRpl8nV8gHd`
- Verify table ID: `tblG4uuUvbwfvI9Z`
2. **Verify Data Structure**:
- Confirm required fields exist: Date, Views, Likes, Comments, Shares, Followers, Engagement_Rate
- Check data types are correct (Number, Date, Percentage)
- Ensure data is populated
3. **Set Permissions**:
- Go to Bitable settings → Sharing
- Add your aPaaS app to authorized applications
- Grant "Read" permission
#### Phase 2: Configure aPaaS Application
1. **Access aPaaS Platform**:
- Login to: `https://apaas.feishu.cn`
- Navigate to your app: `Dffwb10dwaz6UZs6c4HlWyV3g7c`
- Open page: `pgeEOroex4nCBQxc`
2. **Create Data Request**:
- Go to "Data Sources" panel
- Click "+ Add Data Request"
- Name: `getTikTokData`
- Copy configuration from `config/apaas-data-request.json`
- Test the connection
3. **Add Authentication**:
- In Data Request settings, go to "Authentication" tab
- Select "Custom Token"
- Configure tenant access token endpoint
- Or use Personal Base Token in headers
#### Phase 3: Add Chart Components
1. **Add Metric Cards**:
- Drag "Metric Card" component to canvas
- Repeat 4 times for: Views, Likes, Engagement Rate, Followers
- Configure each card with appropriate data binding
2. **Add Line Chart**:
- Drag "Line Chart" component to canvas
- Set data source: `getTikTokData`
- Configure X-axis: Date field
- Configure Y-axis: Views, Engagement_Rate
- Set up dual-axis if needed
3. **Add Bar Chart**:
- Drag "Bar Chart" component to canvas
- Configure for stacked engagement metrics
- Set data binding for Likes, Comments, Shares
4. **Add Pie Chart**:
- Drag "Pie Chart" component to canvas
- Configure donut chart style
- Bind to aggregated engagement data
#### Phase 4: Configure Data Binding
For each component, set data binding expressions:
**Metric Card Example**:
```
Title: Total Views
Value: {{sum(getTikTokData.data.items.map(i => i.fields.Views))}}
Format: number, compact
```
**Line Chart Example**:
```
X-Axis Data: {{getTikTokData.data.items.map(i => i.fields.Date)}}
Y-Axis Data (Views): {{getTikTokData.data.items.map(i => i.fields.Views)}}
Y-Axis Data (Engagement): {{getTikTokData.data.items.map(i => i.fields.Engagement_Rate)}}
```
#### Phase 5: Set Up Interactions
1. **Add Date Range Filter**:
- Drag "Date Range Picker" to top of page
- Name: `dateRangeFilter`
- Default: Last 30 days
2. **Connect Filter to Charts**:
- For each chart component:
- Go to "Events" tab
- Add listener for `dateRangeFilter.onChange`
- Update data request with filter parameters
3. **Add Click Events**:
- On bar chart: Click to show detail modal
- On metric cards: Click to filter line chart
- On pie chart: Click to highlight related data
#### Phase 6: Testing and Validation
1. **Test Data Loading**:
- Preview page
- Verify all components load data
- Check for errors in console
2. **Test Interactions**:
- Click on chart elements
- Change date range filter
- Verify cross-component updates work
3. **Test Different Scenarios**:
- Empty data state
- Large datasets
- Different date ranges
- Mobile/desktop views
#### Phase 7: Optimization
1. **Performance Tuning**:
- Implement data caching (cache TTL: 5 minutes)
- Use pagination for large datasets
- Lazy load charts below the fold
2. **Error Handling**:
- Add loading states
- Add error messages for API failures
- Add empty states for no data
3. **Polish UI**:
- Adjust chart colors to match brand
- Set proper spacing and layout
- Add chart descriptions/tooltips
## Data Request Best Practices
### 1. Pagination for Large Datasets
```json
{
"body": {
"page_size": 100,
"page_token": "{{nextPageToken}}"
},
"pagination": {
"enabled": true,
"tokenField": "page_token",
"hasMoreField": "has_more"
}
}
```
### 2. Filtering at API Level
```json
{
"body": {
"filter": {
"conjunction": "and",
"conditions": [
{
"field_name": "Date",
"operator": "is",
"value": ["{{startDate}}", "{{endDate}}"]
}
]
}
}
}
```
### 3. Sorting
```json
{
"body": {
"sort": [
{
"field_name": "Date",
"desc": false
},
{
"field_name": "Views",
"desc": true
}
]
}
}
```
### 4. Caching Strategy
```json
{
"cache": {
"enabled": true,
"ttl": 300,
"key": "tiktok_data_{{dateRange}}"
}
}
```
## Troubleshooting
### Common Issues
#### 1. Authentication Errors
**Problem**: 401 Unauthorized or 403 Forbidden
**Solutions**:
- Verify tenant access token is valid
- Check app has permission to access Bitable
- Ensure token is refreshed before expiration
- Confirm app_id and app_secret are correct
#### 2. No Data Displayed
**Problem**: Charts are empty or show "No Data"
**Solutions**:
- Check data request returns data in preview
- Verify field names match exactly (case-sensitive)
- Check data binding expressions are correct
- Confirm Bitable table has data
#### 3. Chart Not Updating
**Problem**: Data doesn't refresh when filter changes
**Solutions**:
- Verify event bindings are set up correctly
- Check data request has dynamic parameters
- Confirm component listeners are configured
- Test filter independently
#### 4. Performance Issues
**Problem**: Page loads slowly or charts lag
**Solutions**:
- Implement pagination for large datasets
- Add caching to data requests
- Reduce chart refresh frequency
- Optimize data transformations
#### 5. Field Mapping Errors
**Problem**: Wrong data or null values in charts
**Solutions**:
- Verify field names in Bitable match config
- Check data types are compatible
- Add null checks in expressions: `{{data?.views ?? 0}}`
- Test with sample data first
### Debug Checklist
- [ ] Bitable API returns data successfully
- [ ] Authentication token is valid
- [ ] Field names match exactly
- [ ] Data binding expressions are correct
- [ ] Components are linked to data source
- [ ] Event bindings are configured
- [ ] No console errors
- [ ] Data formats are compatible
## Advanced Features
### 1. Real-time Data Updates
Set up auto-refresh for charts:
```json
{
"refresh": {
"enabled": true,
"interval": 60000,
"onlyWhenVisible": true
}
}
```
### 2. Custom Calculations
Add calculated fields:
```javascript
{
"calculated_fields": [
{
"name": "total_engagement",
"expression": "{{likes + comments + shares}}"
},
{
"name": "engagement_per_follower",
"expression": "{{(likes + comments + shares) / followers * 100}}"
}
]
}
```
### 3. Conditional Formatting
Apply styles based on data:
```json
{
"conditionalFormatting": [
{
"field": "engagement_rate",
"rules": [
{
"condition": "{{value > 10}}",
"style": { "color": "#00C48C", "icon": "⬆️" }
},
{
"condition": "{{value < 5}}",
"style": { "color": "#F54A45", "icon": "⬇️" }
}
]
}
]
}
```
### 4. Export Functionality
Add export buttons:
```json
{
"export": {
"enabled": true,
"formats": ["CSV", "Excel", "PDF"],
"includeCharts": true
}
}
```
## Resources
### Official Documentation
- [Feishu Open Platform](https://open.feishu.cn/)
- [Bitable API Documentation](https://open.feishu.cn/document/server-docs/docs/bitable-v1/app-table-record/list)
- [aPaaS Platform](https://apaas.feishu.cn/)
- [Feishu Cards Chart Component](https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/feishu-cards/card-components/content-components/chart)
### Related Tools
- [VChart Documentation](https://visactor.io/vchart/) - Chart library for Feishu
- [Lark Developer Portal](https://open.larksuite.com/)
### Support
- Feishu Community: https://open.feishu.cn/community/
- Developer Forum: https://open.larksuite.com/
- API Support: Check official documentation for contact options
## Conclusion
This configuration enables you to build powerful, interactive dashboards in aPaaS using Bitable as the data source. The native chart components provide:
- **No-code setup**: Visual configuration without programming
- **Real-time data**: Direct connection to Bitable tables
- **Interactive features**: Click events, filters, cross-component communication
- **Professional visualizations**: Enterprise-grade charts and metrics
- **Scalability**: Handles large datasets with pagination and caching
Follow the integration steps carefully, test thoroughly, and refer to the troubleshooting section if you encounter issues.