Files
database_render/web/static/js/api-client.js
2025-08-07 20:03:53 +08:00

180 lines
5.4 KiB
JavaScript

/**
* API客户端 - 处理所有AJAX请求
*/
class APIClient {
constructor(baseURL = '/api') {
this.baseURL = baseURL;
this.defaultHeaders = {
'Content-Type': 'application/json',
'Accept': 'application/json'
};
this.cache = new Map();
this.cacheTimeout = 5 * 60 * 1000; // 5分钟缓存
}
/**
* 获取所有数据表列表
*/
async getTables() {
const cacheKey = 'tables';
// 检查缓存
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
}
const response = await fetch(`${this.baseURL}/tables`);
if (!response.ok) throw new Error('Failed to fetch tables');
const data = await response.json();
this.cache.set(cacheKey, { data, timestamp: Date.now() });
return data;
}
/**
* 获取数据表数据
* @param {string} tableAlias - 表别名
* @param {Object} params - 查询参数
*/
async getTableData(tableAlias, params = {}) {
const url = new URL(`${this.baseURL}/data/${tableAlias}`, window.location.origin);
// 添加查询参数
Object.keys(params).forEach(key => {
if (params[key] !== undefined && params[key] !== '') {
url.searchParams.append(key, params[key]);
}
});
const cacheKey = url.toString();
// 检查缓存(搜索参数相关的缓存)
if (this.cache.has(cacheKey) && !params.search) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
}
// 使用 AbortController 支持请求取消
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
try {
const response = await fetch(url, {
signal: controller.signal,
headers: this.defaultHeaders
});
clearTimeout(timeoutId);
if (!response.ok) throw new Error('Failed to fetch table data');
const data = await response.json();
// 缓存非搜索请求的结果
if (!params.search) {
this.cache.set(cacheKey, { data, timestamp: Date.now() });
}
return data;
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}
/**
* 获取数据详情
* @param {string} tableAlias - 表别名
* @param {string|number} id - 记录ID
*/
async getRecordDetail(tableAlias, id) {
const cacheKey = `detail:${tableAlias}:${id}`;
// 检查缓存
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch(`${this.baseURL}/data/${tableAlias}/detail/${id}`, {
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) throw new Error('Failed to fetch record detail');
const data = await response.json();
this.cache.set(cacheKey, { data, timestamp: Date.now() });
return data;
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}
/**
* 获取可用模板列表
* @param {string} tableName - 表名
*/
async getAvailableTemplates(tableName) {
const cacheKey = `templates:${tableName}`;
// 检查缓存
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
}
const response = await fetch(`/api/templates/${tableName}/available`);
if (!response.ok) throw new Error('Failed to fetch templates');
const data = await response.json();
this.cache.set(cacheKey, { data, timestamp: Date.now() });
return data;
}
/**
* 验证模板
* @param {string} tableName - 表名
* @param {string} templateType - 模板类型
*/
async validateTemplate(tableName, templateType) {
const response = await fetch(`/api/templates/${tableName}/validate?type=${templateType}`);
return response.json();
}
/**
* 获取模板预览
* @param {string} tableName - 表名
* @param {string} templateType - 模板类型
*/
async getTemplatePreview(tableName, templateType) {
const response = await fetch(`/api/templates/${tableName}/preview?type=${templateType}`);
if (!response.ok) throw new Error('Failed to fetch template preview');
return response.text();
}
/**
* 清空缓存
*/
clearCache() {
this.cache.clear();
}
}
// 全局API客户端实例
window.apiClient = new APIClient();