267 lines
6.3 KiB
JavaScript
267 lines
6.3 KiB
JavaScript
/**
|
|||
|
|
* API 封装模块
|
||
|
|
* 提供与后端API的交互功能
|
||
|
|
*/
|
||
|
|
|
||
|
|
class BIAPIClient {
|
||
|
|
constructor(baseURL = '') {
|
||
|
|
this.baseURL = baseURL || window.location.origin;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 通用请求方法
|
||
|
|
async request(endpoint, options = {}) {
|
||
|
|
const url = `${this.baseURL}${endpoint}`;
|
||
|
|
const defaultOptions = {
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
},
|
||
|
|
...options,
|
||
|
|
};
|
||
|
|
|
||
|
|
try {
|
||
|
|
const response = await fetch(url, defaultOptions);
|
||
|
|
|
||
|
|
if (!response.ok) {
|
||
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
return await response.json();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('API请求失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// GET请求
|
||
|
|
async get(endpoint, params = {}) {
|
||
|
|
const url = new URL(`${this.baseURL}${endpoint}`, window.location.origin);
|
||
|
|
|
||
|
|
Object.keys(params).forEach(key => {
|
||
|
|
if (params[key] !== undefined && params[key] !== null) {
|
||
|
|
url.searchParams.append(key, params[key]);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
return this.request(url.pathname + url.search);
|
||
|
|
}
|
||
|
|
|
||
|
|
// POST请求
|
||
|
|
async post(endpoint, data = {}) {
|
||
|
|
return this.request(endpoint, {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// PUT请求
|
||
|
|
async put(endpoint, data = {}) {
|
||
|
|
return this.request(endpoint, {
|
||
|
|
method: 'PUT',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// DELETE请求
|
||
|
|
async delete(endpoint) {
|
||
|
|
return this.request(endpoint, {
|
||
|
|
method: 'DELETE',
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// BI相关API
|
||
|
|
async getOverviewDashboards() {
|
||
|
|
return this.get('/bi-api/dashboards/overview');
|
||
|
|
}
|
||
|
|
|
||
|
|
async getDashboardData(dashboardId) {
|
||
|
|
return this.get(`/bi-api/dashboards/${dashboardId}/data`);
|
||
|
|
}
|
||
|
|
|
||
|
|
async getChartData(chartId) {
|
||
|
|
return this.get(`/bi-api/charts/${chartId}/data`);
|
||
|
|
}
|
||
|
|
|
||
|
|
async searchBIObjects(keyword) {
|
||
|
|
return this.get('/bi-api/search', { keyword });
|
||
|
|
}
|
||
|
|
|
||
|
|
async getChartTypes() {
|
||
|
|
return this.get('/bi-api/charts/types');
|
||
|
|
}
|
||
|
|
|
||
|
|
async getDataSourceTypes() {
|
||
|
|
return this.get('/bi-api/data-sources/types');
|
||
|
|
}
|
||
|
|
|
||
|
|
async getPopularTags() {
|
||
|
|
return this.get('/bi-api/popular-tags');
|
||
|
|
}
|
||
|
|
|
||
|
|
async getQuickStats() {
|
||
|
|
return this.get('/bi-api/quick-stats');
|
||
|
|
}
|
||
|
|
|
||
|
|
async getChartSuggestions() {
|
||
|
|
return this.get('/bi-api/chart-suggestions');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建全局API客户端实例
|
||
|
|
const apiClient = new BIAPIClient();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 数据获取函数
|
||
|
|
*/
|
||
|
|
|
||
|
|
// 获取概览看板列表
|
||
|
|
export async function getDashboards() {
|
||
|
|
try {
|
||
|
|
return await apiClient.getOverviewDashboards();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取看板列表失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取看板详细数据
|
||
|
|
export async function getDashboardDetail(dashboardId) {
|
||
|
|
try {
|
||
|
|
return await apiClient.getDashboardData(dashboardId);
|
||
|
|
} catch (error) {
|
||
|
|
console.error(`获取看板 ${dashboardId} 数据失败:`, error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取图表数据
|
||
|
|
export async function getChartData(chartId) {
|
||
|
|
try {
|
||
|
|
return await apiClient.getChartData(chartId);
|
||
|
|
} catch (error) {
|
||
|
|
console.error(`获取图表 ${chartId} 数据失败:`, error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 搜索BI对象
|
||
|
|
export async function searchBIObjects(keyword) {
|
||
|
|
try {
|
||
|
|
return await apiClient.searchBIObjects(keyword);
|
||
|
|
} catch (error) {
|
||
|
|
console.error(`搜索 ${keyword} 失败:`, error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取支持的图表类型
|
||
|
|
export async function getChartTypes() {
|
||
|
|
try {
|
||
|
|
return await apiClient.getChartTypes();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取图表类型失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取支持的数据源类型
|
||
|
|
export async function getDataSourceTypes() {
|
||
|
|
try {
|
||
|
|
return await apiClient.getDataSourceTypes();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取数据源类型失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取热门标签
|
||
|
|
export async function getPopularTags() {
|
||
|
|
try {
|
||
|
|
return await apiClient.getPopularTags();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取热门标签失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取快速统计信息
|
||
|
|
export async function getQuickStats() {
|
||
|
|
try {
|
||
|
|
return await apiClient.getQuickStats();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取快速统计失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 获取图表建议
|
||
|
|
export async function getChartSuggestions() {
|
||
|
|
try {
|
||
|
|
return await apiClient.getChartSuggestions();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('获取图表建议失败:', error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 工具函数
|
||
|
|
*/
|
||
|
|
|
||
|
|
// 格式化日期
|
||
|
|
export function formatDate(dateString) {
|
||
|
|
const date = new Date(dateString);
|
||
|
|
return date.toLocaleString('zh-CN', {
|
||
|
|
year: 'numeric',
|
||
|
|
month: '2-digit',
|
||
|
|
day: '2-digit',
|
||
|
|
hour: '2-digit',
|
||
|
|
minute: '2-digit'
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 格式化数字
|
||
|
|
export function formatNumber(num, decimals = 2) {
|
||
|
|
return parseFloat(num).toFixed(decimals);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 显示加载状态
|
||
|
|
export function showLoading(element) {
|
||
|
|
element.innerHTML = '<div class="loading">加载中...</div>';
|
||
|
|
}
|
||
|
|
|
||
|
|
// 显示错误状态
|
||
|
|
export function showError(element, message) {
|
||
|
|
element.innerHTML = `<div class="error">${message}</div>`;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 显示空状态
|
||
|
|
export function showEmpty(element, message = '暂无数据') {
|
||
|
|
element.innerHTML = `<div class="empty">${message}</div>`;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 防抖函数
|
||
|
|
export function debounce(func, wait) {
|
||
|
|
let timeout;
|
||
|
|
return function executedFunction(...args) {
|
||
|
|
const later = () => {
|
||
|
|
clearTimeout(timeout);
|
||
|
|
func(...args);
|
||
|
|
};
|
||
|
|
clearTimeout(timeout);
|
||
|
|
timeout = setTimeout(later, wait);
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// 节流函数
|
||
|
|
export function throttle(func, limit) {
|
||
|
|
let inThrottle;
|
||
|
|
return function() {
|
||
|
|
const args = arguments;
|
||
|
|
const context = this;
|
||
|
|
if (!inThrottle) {
|
||
|
|
func.apply(context, args);
|
||
|
|
inThrottle = true;
|
||
|
|
setTimeout(() => inThrottle = false, limit);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|