@devflow-cc/react
Version:
一个功能强大的React库,用于构建数据驱动的应用程序,支持实时通信、身份验证和数据库操作
1,836 lines (1,817 loc) • 55.3 kB
JavaScript
import axios from 'axios';
import React from 'react';
/**
* 标准表字段(所有表都必须包含)
*/
const STANDARD_FIELDS = [
'id',
'created_by',
'created_at',
'updated_by',
'updated_at',
'deleted_by',
'deleted_at'
];
/**
* 默认配置
*/
const DEFAULT_CONFIG$1 = {
baseURL: 'http://localhost:8000',
apiVersion: 'v1',
timeout: 10000,
language: 'zh',
headers: {
'Content-Type': 'application/json'
},
errorHandler: {
onError: undefined,
retry: 0
}
};
/**
* 国际化消息
*/
const I18N_MESSAGES = {
zh: {
'error.network': '网络连接错误',
'error.timeout': '请求超时',
'error.unauthorized': '未授权访问',
'error.forbidden': '权限不足',
'error.not_found': '资源不存在',
'error.validation': '数据验证失败',
'error.server': '服务器内部错误',
'error.unknown': '未知错误',
'warning.standard_field': '警告:{field} 是标准字段,将由系统自动管理',
'success.operation': '操作成功',
'info.loading': '加载中...',
'info.no_data': '暂无数据',
'info.pagination': '第 {page} 页,共 {total} 条记录'
},
en: {
'error.network': 'Network connection error',
'error.timeout': 'Request timeout',
'error.unauthorized': 'Unauthorized access',
'error.forbidden': 'Insufficient permissions',
'error.not_found': 'Resource not found',
'error.validation': 'Data validation failed',
'error.server': 'Internal server error',
'error.unknown': 'Unknown error',
'warning.standard_field': 'Warning: {field} is a standard field and will be managed automatically by the system',
'success.operation': 'Operation successful',
'info.loading': 'Loading...',
'info.no_data': 'No data available',
'info.pagination': 'Page {page} of {total} records'
}
};
/**
* 配置管理器
*/
class ConfigManager {
constructor(config) {
this.config = { ...DEFAULT_CONFIG$1, ...config };
this.messages = I18N_MESSAGES;
}
/**
* 获取配置
*/
getConfig() {
return { ...this.config };
}
/**
* 更新配置
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
}
/**
* 获取当前语言
*/
getCurrentLanguage() {
return this.config.language || 'zh';
}
/**
* 设置语言
*/
setLanguage(language) {
this.config.language = language;
}
/**
* 获取国际化消息
*/
getMessage(key, params = {}) {
const lang = this.getCurrentLanguage();
const messages = this.messages[lang] || this.messages['zh'];
let message = messages[key] || key;
// 替换参数
Object.keys(params).forEach(param => {
message = message.replace(new RegExp(`{${param}}`, 'g'), params[param]);
});
return message;
}
/**
* 扩展国际化消息
*/
extendMessages(language, messages) {
if (!this.messages[language]) {
this.messages[language] = {};
}
this.messages[language] = { ...this.messages[language], ...messages };
}
/**
* 获取支持的语言列表
*/
getSupportedLanguages() {
return Object.keys(this.messages);
}
/**
* 设置错误处理器
*/
setErrorHandler(onError, retry = 0) {
this.config.errorHandler = { onError, retry };
}
/**
* 获取错误处理器配置
*/
getErrorHandler() {
return this.config.errorHandler;
}
/**
* 清除错误处理器
*/
clearErrorHandler() {
this.config.errorHandler = { onError: undefined, retry: 0 };
}
}
/**
* 简化的存储管理器
*/
class StorageManager {
constructor(config) {
// 默认使用 'devflow-token',可以通过 tokenKey 配置覆盖
this.tokenKey = config.tokenKey || 'devflow-token';
this.config = config;
}
/**
* 获取token
* 优先使用用户配置中的token,如果没有则从localStorage获取
*/
getToken() {
// 优先使用用户配置中的token
if (this.config.token) {
return this.config.token;
}
// 如果用户没有配置token,则从localStorage获取
if (typeof window !== 'undefined') {
return localStorage.getItem(this.tokenKey);
}
return null;
}
/**
* 设置token
*/
setToken(token) {
// 更新配置中的token
this.config.token = token;
// 同时保存到localStorage作为备份
if (typeof window !== 'undefined') {
localStorage.setItem(this.tokenKey, token);
}
}
/**
* 清除token
*/
clearToken() {
// 清除配置中的token
this.config.token = undefined;
// 同时清除localStorage中的token
if (typeof window !== 'undefined') {
localStorage.removeItem(this.tokenKey);
}
}
/**
* 获取token键名
*/
getTokenKey() {
return this.tokenKey;
}
/**
* 更新配置
*/
updateConfig(config) {
this.config = config;
this.tokenKey = config.tokenKey || 'devflow-token';
}
}
/**
* HTTP客户端类
*/
class HttpClient {
constructor(configManager) {
this.token = null;
this.configManager = configManager;
this.storageManager = new StorageManager(configManager.getConfig());
const config = configManager.getConfig();
this.client = axios.create({
baseURL: `${config.baseURL}/api/${config.apiVersion || 'v1'}`,
timeout: config.timeout || 10000,
headers: {
'Content-Type': 'application/json',
'X-Language': config.language || 'zh',
'Accept-Language': config.language || 'zh',
...config.headers,
},
});
this.setupInterceptors();
}
/**
* 设置请求和响应拦截器
*/
setupInterceptors() {
// 请求拦截器
this.client.interceptors.request.use((config) => {
// 添加认证头
if (this.token) {
config.headers.Authorization = `Bearer ${this.token}`;
}
return config;
}, (error) => {
return Promise.reject(error);
});
// 响应拦截器
this.client.interceptors.response.use((response) => {
return response;
}, (error) => {
// 处理401错误,清除token
if (error.response?.status === 401) {
this.clearToken();
}
return Promise.reject(error);
});
}
/**
* 设置认证token
*/
setToken(token) {
this.token = token;
this.storageManager.setToken(token);
}
/**
* 清除认证token
*/
clearToken() {
this.token = null;
this.storageManager.clearToken();
}
/**
* 获取当前token
*/
getToken() {
return this.token;
}
/**
* 从存储恢复token
*/
restoreToken() {
const token = this.storageManager.getToken();
if (token) {
this.token = token;
}
}
/**
* 更新配置
*/
updateConfig(configManager) {
this.configManager = configManager;
this.storageManager.updateConfig(configManager.getConfig());
// 重新创建 axios 实例以使用新的配置
const config = configManager.getConfig();
this.client = axios.create({
baseURL: `${config.baseURL}/api/${config.apiVersion || 'v1'}`,
timeout: config.timeout || 10000,
headers: {
'Content-Type': 'application/json',
'X-Language': config.language || 'zh',
'Accept-Language': config.language || 'zh',
...config.headers,
},
});
// 重新设置拦截器
this.setupInterceptors();
// 重新获取token(优先使用新配置中的token)
this.restoreToken();
}
/**
* 执行带重试的请求
*/
async executeWithRetry(requestFn) {
const config = this.configManager.getConfig();
const maxRetries = config.errorHandler?.retry || 0;
let lastError;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await requestFn();
return { data: response.data };
}
catch (error) {
lastError = error;
// 如果不是最后一次尝试,等待一段时间后重试
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000; // 指数退避
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
return { error: this.transformError(lastError) };
}
/**
* 转换错误信息
*/
transformError(error) {
const config = this.configManager.getConfig();
const data = error.response?.data?.error || {};
const apiError = {
detail: data?.detail || data?.message || this.configManager.getMessage('error.unknown'),
timestamp: data?.timestamp,
status_code: data?.status_code || 0,
error_code: data?.error_code || 'UNKNOWN_ERROR',
};
// 调用配置的错误处理器
if (config.errorHandler?.onError) {
try {
config.errorHandler.onError(apiError);
}
catch (handlerError) {
console.error('Error handler failed:', handlerError);
}
}
return apiError;
}
/**
* GET请求
*/
async get(url, config) {
return this.executeWithRetry(() => this.client.get(url, config));
}
/**
* POST请求
*/
async post(url, data, config) {
return this.executeWithRetry(() => this.client.post(url, data, config));
}
/**
* PUT请求
*/
async put(url, data, config) {
return this.executeWithRetry(() => this.client.put(url, data, config));
}
/**
* DELETE请求
*/
async delete(url, config) {
return this.executeWithRetry(() => this.client.delete(url, config));
}
/**
* PATCH请求
*/
async patch(url, data, config) {
return this.executeWithRetry(() => this.client.patch(url, data, config));
}
}
/**
* 认证模块
*/
class AuthModule {
constructor(httpClient, configManager) {
this.httpClient = httpClient;
this.configManager = configManager;
}
/**
* 用户注册
*/
async signUp(request) {
return this.httpClient.post('/auth/register', request);
}
/**
* 用户登录
*/
async signInWithPassword(request) {
const response = await this.httpClient.post('/auth/login', request);
// 如果登录成功,保存token
if (response.data?.access_token) {
this.httpClient.setToken(response.data.access_token);
}
return response;
}
/**
* 获取当前用户信息
*/
async getUser() {
return this.httpClient.get('/auth/me');
}
/**
* 更新当前用户信息
*/
async updateUser(request) {
return this.httpClient.put('/auth/me', request);
}
/**
* 修改密码
*/
async changePassword(request) {
return this.httpClient.post('/auth/change-password', request);
}
/**
* 用户登出
*/
async signOut() {
const response = await this.httpClient.post('/auth/logout');
// 清除本地token
this.httpClient.clearToken();
return response;
}
/**
* 刷新访问令牌
*/
async refreshToken(refreshToken) {
const response = await this.httpClient.post('/auth/refresh', {
refresh_token: refreshToken
});
// 如果刷新成功,保存新token
if (response.data?.access_token) {
this.httpClient.setToken(response.data.access_token);
}
return response;
}
/**
* 检查是否已登录
*/
isAuthenticated() {
// 通过HTTP客户端获取token来判断是否已登录
return !!this.httpClient.getToken();
}
/**
* 获取当前token
*/
getToken() {
return this.httpClient.getToken();
}
}
/**
* 用户管理模块
*/
class UsersModule {
constructor(httpClient, configManager) {
this.httpClient = httpClient;
this.configManager = configManager;
}
/**
* 获取用户列表
*/
async getUsers(params = {}) {
const queryParams = new URLSearchParams();
if (params.page)
queryParams.append('page', params.page.toString());
if (params.page_size)
queryParams.append('page_size', params.page_size.toString());
if (params.search)
queryParams.append('search', params.search);
if (params.is_active !== undefined)
queryParams.append('is_active', params.is_active.toString());
if (params.role)
queryParams.append('role', params.role);
if (params.is_superuser !== undefined)
queryParams.append('is_superuser', params.is_superuser.toString());
const url = `/users${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
return this.httpClient.get(url);
}
/**
* 获取用户详情
*/
async getUser(userId) {
return this.httpClient.get(`/users/${userId}`);
}
/**
* 管理员创建用户
*/
async createUser(request) {
return this.httpClient.post('/users', request);
}
/**
* 管理员更新用户
*/
async updateUser(userId, request) {
return this.httpClient.put(`/users/${userId}`, request);
}
/**
* 删除用户
*/
async deleteUser(userId) {
return this.httpClient.delete(`/users/${userId}`);
}
/**
* 激活用户
*/
async activateUser(userId) {
return this.httpClient.put(`/users/${userId}/activate`);
}
/**
* 停用用户
*/
async deactivateUser(userId) {
return this.httpClient.put(`/users/${userId}/deactivate`);
}
/**
* 设置用户角色
*/
async setUserRoles(userId, roleNames) {
const request = { role_names: roleNames };
return this.httpClient.put(`/users/${userId}/roles`, request);
}
/**
* 重置用户密码
*/
async resetUserPassword(userId, newPassword) {
const request = { new_password: newPassword };
return this.httpClient.post(`/users/${userId}/reset-password`, request);
}
}
/**
* 审计日志模块
*/
class AuditModule {
constructor(httpClient, configManager) {
this.httpClient = httpClient;
this.configManager = configManager;
}
/**
* 获取审计日志列表
*/
async getLogs(params = {}) {
const queryParams = new URLSearchParams();
if (params.user_id)
queryParams.append('user_id', params.user_id);
if (params.action)
queryParams.append('action', params.action);
if (params.resource_type)
queryParams.append('resource_type', params.resource_type);
if (params.resource_id)
queryParams.append('resource_id', params.resource_id);
if (params.status)
queryParams.append('status', params.status);
if (params.ip_address)
queryParams.append('ip_address', params.ip_address);
if (params.start_time)
queryParams.append('start_time', params.start_time);
if (params.end_time)
queryParams.append('end_time', params.end_time);
if (params.page)
queryParams.append('page', params.page.toString());
if (params.page_size)
queryParams.append('page_size', params.page_size.toString());
const url = `/audit/logs${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
return this.httpClient.get(url);
}
/**
* 获取我的审计日志
*/
async getMyLogs(params = {}) {
const queryParams = new URLSearchParams();
if (params.action)
queryParams.append('action', params.action);
if (params.resource_type)
queryParams.append('resource_type', params.resource_type);
if (params.days)
queryParams.append('days', params.days.toString());
if (params.page)
queryParams.append('page', params.page.toString());
if (params.page_size)
queryParams.append('page_size', params.page_size.toString());
const url = `/audit/logs/my${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
return this.httpClient.get(url);
}
/**
* 获取用户活动摘要
*/
async getActivitySummary(params = {}) {
const queryParams = new URLSearchParams();
if (params.user_id)
queryParams.append('user_id', params.user_id);
if (params.days)
queryParams.append('days', params.days.toString());
const url = `/audit/activity/summary${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
return this.httpClient.get(url);
}
/**
* 获取系统审计统计
*/
async getSystemStats(params = {}) {
const queryParams = new URLSearchParams();
if (params.days)
queryParams.append('days', params.days.toString());
const url = `/audit/stats/system${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
return this.httpClient.get(url);
}
}
/**
* 数据操作模块
*/
class DataModule {
constructor(httpClient, configManager) {
this.conditions = [];
this.sorts = [];
this.fields = [];
this.httpClient = httpClient;
this.configManager = configManager;
}
/**
* 从指定表获取查询构建器
*/
from(table) {
this.currentTable = table;
this.resetQueryState();
return this;
}
/**
* 重置查询状态
*/
resetQueryState() {
this.conditions = [];
this.sorts = [];
this.fields = [];
this.pageNum = undefined;
this.pageSize = undefined;
this.limitNum = undefined;
this.offsetNum = undefined;
}
/**
* 智能过滤 - 自动忽略空值条件
*/
addCondition(field, operator, value) {
// 忽略空值条件
if (value === null || value === undefined || value === '') {
return this;
}
this.conditions.push({ field, operator, value });
return this;
}
/**
* 等于
*/
eq(field, value) {
return this.addCondition(field, 'eq', value);
}
/**
* 不等于
*/
neq(field, value) {
return this.addCondition(field, 'ne', value);
}
/**
* 不等于(别名)
*/
ne(field, value) {
return this.neq(field, value);
}
/**
* 大于
*/
gt(field, value) {
return this.addCondition(field, 'gt', value);
}
/**
* 大于等于
*/
gte(field, value) {
return this.addCondition(field, 'gte', value);
}
/**
* 小于
*/
lt(field, value) {
return this.addCondition(field, 'lt', value);
}
/**
* 小于等于
*/
lte(field, value) {
return this.addCondition(field, 'lte', value);
}
/**
* 模糊匹配(区分大小写)
*/
like(field, value) {
return this.addCondition(field, 'like', value);
}
/**
* 模糊匹配(不区分大小写)
*/
ilike(field, value) {
return this.addCondition(field, 'ilike', value);
}
/**
* 以指定字符串开头
*/
startsWith(field, value) {
return this.addCondition(field, 'starts_with', value);
}
/**
* 以指定字符串开头(别名)
*/
starts_with(field, value) {
return this.startsWith(field, value);
}
/**
* 以指定字符串开头(别名)
*/
startswith(field, value) {
return this.startsWith(field, value);
}
/**
* 以指定字符串结尾
*/
endsWith(field, value) {
return this.addCondition(field, 'ends_with', value);
}
/**
* 以指定字符串结尾(别名)
*/
ends_with(field, value) {
return this.endsWith(field, value);
}
/**
* 以指定字符串结尾(别名)
*/
endswith(field, value) {
return this.endsWith(field, value);
}
/**
* 正则表达式匹配
*/
regex(field, value) {
return this.addCondition(field, 'regex', value);
}
/**
* 不区分大小写的正则表达式
*/
iregex(field, value) {
return this.addCondition(field, 'iregex', value);
}
/**
* SIMILAR TO 操作符
*/
similar(field, value) {
return this.addCondition(field, 'similar', value);
}
/**
* NOT SIMILAR TO 操作符
*/
notSimilar(field, value) {
return this.addCondition(field, 'not_similar', value);
}
/**
* NOT SIMILAR TO 操作符(别名)
*/
not_similar(field, value) {
return this.notSimilar(field, value);
}
/**
* 包含在列表中
*/
in(field, values) {
return this.addCondition(field, 'in', values);
}
/**
* 不包含在列表中
*/
notIn(field, values) {
return this.addCondition(field, 'not_in', values);
}
/**
* 不包含在列表中(别名)
*/
nin(field, values) {
return this.notIn(field, values);
}
/**
* 在指定范围内
*/
between(field, start, end) {
return this.addCondition(field, 'between', [start, end]);
}
/**
* 范围查询
*/
range(field, start, end) {
return this.addCondition(field, 'range', [start, end]);
}
/**
* 字段为 NULL
*/
isNull(field) {
return this.addCondition(field, 'is_null', true);
}
/**
* 字段为 NULL(别名)
*/
isnull(field) {
return this.isNull(field);
}
/**
* 字段不为 NULL
*/
isNotNull(field) {
return this.addCondition(field, 'is_not_null', true);
}
/**
* 字段不为 NULL(别名)
*/
isnotnull(field) {
return this.isNotNull(field);
}
/**
* 字段为空
*/
isEmpty(field) {
return this.addCondition(field, 'is_empty', true);
}
/**
* 字段为空(别名)
*/
isempty(field) {
return this.isEmpty(field);
}
/**
* 字段不为空
*/
isNotEmpty(field) {
return this.addCondition(field, 'is_not_empty', true);
}
/**
* 字段不为空(别名)
*/
isnotempty(field) {
return this.isNotEmpty(field);
}
/**
* JSONB 包含
*/
contains(field, value) {
return this.addCondition(field, 'contains', value);
}
/**
* JSONB 被包含
*/
containedBy(field, value) {
return this.addCondition(field, 'contained_by', value);
}
/**
* JSONB 包含指定键
*/
hasKey(field, key) {
return this.addCondition(field, 'has_key', key);
}
/**
* JSONB 数组长度
*/
jsonLength(field, length) {
return this.addCondition(field, 'json_length', length);
}
/**
* 排序
*/
order(field, direction = 'desc') {
this.sorts.push({ field, direction });
return this;
}
/**
* 分页
*/
page(page, pageSize) {
this.pageNum = page;
this.pageSize = pageSize;
return this;
}
/**
* 限制数量
*/
limit(limit) {
this.limitNum = limit;
return this;
}
/**
* 偏移量
*/
offset(offset) {
this.offsetNum = offset;
return this;
}
/**
* 选择字段
*/
selectFields(fields) {
if (fields) {
this.fields = fields;
}
return this;
}
/**
* 构建查询参数
*/
buildQueryParams() {
const params = {
where_conditions: this.conditions,
order_by: this.sorts
};
if (this.fields.length > 0) {
params.fields = this.fields;
}
if (this.pageNum && this.pageSize) {
params.page = this.pageNum;
params.page_size = this.pageSize;
}
else if (this.limitNum) {
params.limit = this.limitNum;
if (this.offsetNum) {
params.offset = this.offsetNum;
}
}
return params;
}
/**
* 查询数据
*/
async select(fields) {
if (!this.currentTable) {
throw new Error('No table specified. Use .from(table) first.');
}
if (fields) {
this.fields = fields;
}
const params = this.buildQueryParams();
const response = await this.httpClient.post(`/data/${this.currentTable}/select`, params);
// 重置查询状态
this.resetQueryState();
return response;
}
/**
* 查询数据(别名)
*/
async query() {
return this.select();
}
/**
* 获取单条记录
*/
async get(id) {
if (!this.currentTable) {
throw new Error('No table specified. Use .from(table) first.');
}
const response = await this.httpClient.get(`/data/tables/${this.currentTable}/records/${id}`);
// 重置查询状态
this.resetQueryState();
return response;
}
/**
* 插入数据
*/
async insert(data) {
if (!this.currentTable) {
throw new Error('No table specified. Use .from(table) first.');
}
// 验证标准字段
if (Array.isArray(data)) {
data.forEach(item => this.validateStandardFields(item, 'insert'));
}
else {
this.validateStandardFields(data, 'insert');
}
const response = await this.httpClient.post(`/data/${this.currentTable}/insert`, data);
// 重置查询状态
this.resetQueryState();
return response;
}
/**
* 更新数据
*/
async update(data, confirmAll = false) {
if (!this.currentTable) {
throw new Error('No table specified. Use .from(table) first.');
}
// 验证标准字段
this.validateStandardFields(data, 'update');
const requestBody = {
data,
where_conditions: confirmAll ? [] : this.conditions
};
const response = await this.httpClient.put(`/data/${this.currentTable}/update`, requestBody);
// 重置查询状态
this.resetQueryState();
return response;
}
/**
* 删除数据
*/
async delete(confirmAll = false, hardDelete = false) {
if (!this.currentTable) {
throw new Error('No table specified. Use .from(table) first.');
}
const requestBody = {
where_conditions: confirmAll ? [] : this.conditions,
hard_delete: hardDelete
};
const response = await this.httpClient.post(`/data/${this.currentTable}/delete`, requestBody);
// 重置查询状态
this.resetQueryState();
return response;
}
/**
* 验证标准字段
*/
validateStandardFields(data, operation) {
const standardFields = Object.keys(data).filter(key => STANDARD_FIELDS.includes(key));
if (standardFields.length > 0) {
const warning = this.configManager.getMessage('warning.standard_field', {
field: standardFields.join(', ')
});
console.warn(`${operation} 警告: ${warning}`);
}
}
/**
* 获取所有表的数据操作接口
*/
get tables() {
return {
from: (table) => this.from(table)
};
}
}
/**
* 表管理模块
*/
class TableModule {
constructor(httpClient, configManager) {
this.httpClient = httpClient;
this.configManager = configManager;
}
/**
* 创建表
*/
async createTable(request) {
return this.httpClient.post(`/table/tables/${request.name}`, {
columns: request.columns
});
}
/**
* 获取表列表
*/
async getTables(params = {}) {
const queryParams = new URLSearchParams();
if (params.page)
queryParams.append('page', params.page.toString());
if (params.page_size)
queryParams.append('page_size', params.page_size.toString());
if (params.search)
queryParams.append('search', params.search);
const url = `/table/tables${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
return this.httpClient.get(url);
}
/**
* 获取表信息
*/
async getTableInfo(tableName) {
return this.httpClient.get(`/table/tables/${tableName}`);
}
/**
* 更新表结构
*/
async updateTable(tableName, request) {
return this.httpClient.put(`/table/tables/${tableName}`, request);
}
/**
* 删除表
*/
async deleteTable(tableName) {
return this.httpClient.delete(`/table/tables/${tableName}`);
}
/**
* 获取表统计信息
*/
async getTableStats(tableName) {
return this.httpClient.get(`/table/tables/${tableName}/stats`);
}
/**
* 验证表名是否合法
*/
async validateTableName(tableName) {
return this.httpClient.post(`/table/validate-name?table_name=${tableName}`);
}
/**
* 获取表前缀配置信息
*/
async getTablePrefixInfo() {
return this.httpClient.get('/table/prefix-info');
}
}
/**
* WebSocket连接类
*/
class WebSocketConnection {
constructor(config, configManager) {
this.ws = null;
this.subscriptions = new Map();
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.reconnectInterval = 1000;
this.config = config;
this.configManager = configManager;
}
/**
* 建立连接
*/
connect() {
return new Promise((resolve, reject) => {
try {
// 从配置中获取baseURL
const baseURL = this.configManager.getConfig().baseURL;
const wsURL = baseURL.replace(/^https?:\/\//, 'ws://').replace(/^https:\/\//, 'wss://');
const url = `${wsURL}/api/v1/websocket/ws?token=${this.config.token}`;
this.ws = new WebSocket(url);
this.ws.onopen = () => {
console.log('WebSocket连接已建立');
this.reconnectAttempts = 0;
resolve();
};
this.ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
this.handleMessage(data);
}
catch (error) {
console.error('解析WebSocket消息失败:', error);
}
};
this.ws.onerror = (error) => {
console.error('WebSocket错误:', error);
if (this.config.onError) {
this.config.onError(error);
}
reject(error);
};
this.ws.onclose = () => {
console.log('WebSocket连接已关闭');
if (this.config.onClose) {
this.config.onClose();
}
this.attemptReconnect();
};
}
catch (error) {
reject(error);
}
});
}
/**
* 处理接收到的消息
*/
handleMessage(message) {
if (message.type === 'data_change' && message.table) {
const callback = this.subscriptions.get(message.table);
if (callback) {
callback(message);
}
}
if (this.config.onMessage) {
this.config.onMessage(message);
}
}
/**
* 尝试重连
*/
attemptReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
setTimeout(() => {
this.connect().catch(() => {
this.attemptReconnect();
});
}, this.reconnectInterval * this.reconnectAttempts);
}
}
/**
* 订阅表变更
*/
subscribe(table, callback) {
this.subscriptions.set(table, callback);
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
const message = {
type: 'subscribe',
table
};
this.ws.send(JSON.stringify(message));
}
}
/**
* 取消订阅
*/
unsubscribe(table) {
this.subscriptions.delete(table);
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
const message = {
type: 'unsubscribe',
table
};
this.ws.send(JSON.stringify(message));
}
}
/**
* 关闭连接
*/
close() {
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
/**
* 检查连接状态
*/
isConnected() {
return this.ws?.readyState === WebSocket.OPEN;
}
}
/**
* WebSocket模块
*/
class WebSocketModule {
constructor(configManager) {
this.configManager = configManager;
}
/**
* 建立WebSocket连接
*/
connect(config) {
return new WebSocketConnection(config, this.configManager);
}
}
/**
* 默认配置
*/
const DEFAULT_CONFIG = {
baseURL: 'http://localhost:8000',
apiVersion: 'v1',
timeout: 10000,
language: 'zh'
};
/**
* 全局单例实例
*/
let globalInstance = null;
/**
* DevFlow 主客户端类
*/
class DevFlowClient {
constructor(config) {
this.configManager = new ConfigManager(config);
this.httpClient = new HttpClient(this.configManager);
this.authModule = new AuthModule(this.httpClient, this.configManager);
this.usersModule = new UsersModule(this.httpClient, this.configManager);
this.auditModule = new AuditModule(this.httpClient, this.configManager);
this.dataModule = new DataModule(this.httpClient, this.configManager);
this.tableModule = new TableModule(this.httpClient, this.configManager);
this.websocketModule = new WebSocketModule(this.configManager);
// 恢复token
this.httpClient.restoreToken();
}
/**
* 设置配置
*/
setConfig(config) {
this.configManager.updateConfig(config);
// 更新HTTP客户端的配置
this.httpClient.updateConfig(this.configManager);
// 重新创建模块以使用新的配置
this.authModule = new AuthModule(this.httpClient, this.configManager);
this.usersModule = new UsersModule(this.httpClient, this.configManager);
this.auditModule = new AuditModule(this.httpClient, this.configManager);
this.dataModule = new DataModule(this.httpClient, this.configManager);
this.tableModule = new TableModule(this.httpClient, this.configManager);
this.websocketModule = new WebSocketModule(this.configManager);
}
/**
* 获取配置
*/
getConfig() {
return this.configManager.getConfig();
}
/**
* 设置认证token
*/
setToken(token) {
this.httpClient.setToken(token);
}
/**
* 清除认证token
*/
clearToken() {
this.httpClient.clearToken();
}
/**
* 设置语言
*/
setLanguage(language) {
this.configManager.setLanguage(language);
}
/**
* 获取当前语言
*/
getCurrentLanguage() {
return this.configManager.getCurrentLanguage();
}
/**
* 国际化函数
*/
t(key, params = {}) {
return this.configManager.getMessage(key, params);
}
/**
* 扩展国际化消息
*/
extendMessages(language, messages) {
this.configManager.extendMessages(language, messages);
}
/**
* 获取支持的语言列表
*/
getSupportedLanguages() {
return this.configManager.getSupportedLanguages();
}
/**
* 认证模块
*/
get auth() {
return this.authModule;
}
/**
* 用户管理模块
*/
get users() {
return this.usersModule;
}
/**
* 审计日志模块
*/
get audit() {
return this.auditModule;
}
/**
* 数据操作模块
*/
get data() {
return this.dataModule;
}
/**
* 表管理模块
*/
get table() {
return this.tableModule;
}
/**
* WebSocket模块
*/
get websocket() {
return this.websocketModule;
}
/**
* 从指定表获取查询构建器(简化写法)
*/
from(table) {
return this.dataModule.from(table);
}
/**
* 创建实时数据通道(兼容旧版本)
*/
channel(table) {
// 这里可以返回一个兼容的实时通道对象
return {
on: (event, callback) => {
// 实现实时订阅逻辑
},
off: (event) => {
// 实现取消订阅逻辑
}
};
}
/**
* 实时数据模块(兼容旧版本)
*/
get realtime() {
return {
channel: (table) => this.channel(table)
};
}
/**
* 表结构模块(兼容旧版本)
*/
get schema() {
return this.table;
}
}
/**
* 创建DevFlow客户端实例
*/
function createClient(config) {
return new DevFlowClient(config);
}
/**
* 创建DevFlow客户端实例(别名)
*/
function createDevFlowClient(config) {
return createClient(config);
}
/**
* 获取或创建全局单例实例
*/
function devflowSingleton(config) {
if (!globalInstance) {
globalInstance = new DevFlowClient(config || DEFAULT_CONFIG);
}
else if (config) {
globalInstance.setConfig(config);
}
return globalInstance;
}
/**
* 重置全局单例实例
*/
function resetDevFlow() {
globalInstance = null;
}
var jsxRuntime = {exports: {}};
var reactJsxRuntime_production = {};
/**
* @license React
* react-jsx-runtime.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var hasRequiredReactJsxRuntime_production;
function requireReactJsxRuntime_production () {
if (hasRequiredReactJsxRuntime_production) return reactJsxRuntime_production;
hasRequiredReactJsxRuntime_production = 1;
var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"),
REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
function jsxProd(type, config, maybeKey) {
var key = null;
void 0 !== maybeKey && (key = "" + maybeKey);
void 0 !== config.key && (key = "" + config.key);
if ("key" in config) {
maybeKey = {};
for (var propName in config)
"key" !== propName && (maybeKey[propName] = config[propName]);
} else maybeKey = config;
config = maybeKey.ref;
return {
$$typeof: REACT_ELEMENT_TYPE,
type: type,
key: key,
ref: void 0 !== config ? config : null,
props: maybeKey
};
}
reactJsxRuntime_production.Fragment = REACT_FRAGMENT_TYPE;
reactJsxRuntime_production.jsx = jsxProd;
reactJsxRuntime_production.jsxs = jsxProd;
return reactJsxRuntime_production;
}
var reactJsxRuntime_development = {};
/**
* @license React
* react-jsx-runtime.development.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var hasRequiredReactJsxRuntime_development;
function requireReactJsxRuntime_development () {
if (hasRequiredReactJsxRuntime_development) return reactJsxRuntime_development;
hasRequiredReactJsxRuntime_development = 1;
"production" !== process.env.NODE_ENV &&
(function () {
function getComponentNameFromType(type) {
if (null == type) return null;
if ("function" === typeof type)
return type.$$typeof === REACT_CLIENT_REFERENCE
? null
: type.displayName || type.name || null;
if ("string" === typeof type) return type;
switch (type) {
case REACT_FRAGMENT_TYPE:
return "Fragment";
case REACT_PROFILER_TYPE:
return "Profiler";
case REACT_STRICT_MODE_TYPE:
return "StrictMode";
case REACT_SUSPENSE_TYPE:
return "Suspense";
case REACT_SUSPENSE_LIST_TYPE:
return "SuspenseList";
case REACT_ACTIVITY_TYPE:
return "Activity";
}
if ("object" === typeof type)
switch (
("number" === typeof type.tag &&
console.error(
"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
),
type.$$typeof)
) {
case REACT_PORTAL_TYPE:
return "Portal";
case REACT_CONTEXT_TYPE:
return (type.displayName || "Context") + ".Provider";
case REACT_CONSUMER_TYPE:
return (type._context.displayName || "Context") + ".Consumer";
case REACT_FORWARD_REF_TYPE:
var innerType = type.render;
type = type.displayName;
type ||
((type = innerType.displayName || innerType.name || ""),
(type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef"));
return type;
case REACT_MEMO_TYPE:
return (
(innerType = type.displayName || null),
null !== innerType
? innerType
: getComponentNameFromType(type.type) || "Memo"
);
case REACT_LAZY_TYPE:
innerType = type._payload;
type = type._init;
try {
return getComponentNameFromType(type(innerType));
} catch (x) {}
}
return null;
}
function testStringCoercion(value) {
return "" + value;
}
function checkKeyStringCoercion(value) {
try {
testStringCoercion(value);
var JSCompiler_inline_result = !1;
} catch (e) {
JSCompiler_inline_result = true;
}
if (JSCompiler_inline_result) {
JSCompiler_inline_result = console;
var JSCompiler_temp_const = JSCompiler_inline_result.error;
var JSCompiler_inline_result$jscomp$0 =
("function" === typeof Symbol &&
Symbol.toStringTag &&
value[Symbol.toStringTag]) ||
value.constructor.name ||
"Object";
JSCompiler_temp_const.call(
JSCompiler_inline_result,
"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
JSCompiler_inline_result$jscomp$0
);
return testStringCoercion(value);
}
}
function getTaskName(type) {
if (type === REACT_FRAGMENT_TYPE) return "<>";
if (
"object" === typeof type &&
null !== type &&
type.$$typeof === REACT_LAZY_TYPE
)
return "<...>";
try {
var name = getComponentNameFromType(type);
return name ? "<" + name + ">" : "<...>";
} catch (x) {
return "<...>";
}
}
function getOwner() {
var dispatcher = ReactSharedInternals.A;
return null === dispatcher ? null : dispatcher.getOwner();
}
function UnknownOwner() {
return Error("react-stack-top-frame");
}
function hasValidKey(config) {
if (hasOwnProperty.call(config, "key")) {
var getter = Object.getOwnPropertyDescriptor(config, "key").get;
if (getter && getter.isReactWarning) return false;
}
return void 0 !== config.key;
}
function defineKeyPropWarningGetter(props, displayName) {
function warnAboutAccessingKey() {
specialPropKeyWarningShown ||
((specialPropKeyWarningShown = true),
console.error(
"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
displayName
));
}
warnAboutAccessingKey.isReactWarning = true;
Object.defineProperty(props, "key", {
get: warnAboutAccessingKey,
configurable: true
});
}
function elementRefGetterWithDeprecationWarning() {
var componentName = getComponentNameFromType(this.type);
didWarnAboutElementRef[componentName] ||
((didWarnAboutElementRef[componentName] = true),
console.error(
"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
));
componentName = this.props.ref;
return void 0 !== componentName ? componentName : null;
}
function ReactElement(
type,
key,
self,
source,
owner,
props,
debugStack,
debugTask
) {
self = props.ref;
type = {
$$typeof: REACT_ELEMENT_TYPE,
type: type,
key: key,
props: props,
_owner: owner
};
null !== (void 0 !== self ? self : null)
? Object.defineProperty(type, "ref", {
enumerable: false,
get: elementRefGetterWithDeprecationWarning
})
: Object.defineProperty(type, "ref", { enumerable: false, value: null });
type._store = {};
Object.defineProperty(type._store, "validated", {
configurable: false,
enumerable: false,
writable: true,
value: 0
});
Object.defineProperty(type, "_debugInfo", {
configurable: false,
enumerable: false,
writable: true,
value: null
});
Object.defineProperty(type, "_debugStack", {
configurable: false,
enumerable: false,
writable: true,
value: debugStack
});
Object.defineProperty(type, "_debugTask", {
configurable: false,
enumerable: false,
writable: true,
value: debugTask
});
Object.freeze && (Object.freeze(type.props), Object.freeze(type));
return type;
}
function jsxDEVImpl(
type,
config,
maybeKey,
isStaticChildren,
source,
self,
debugStack,
debugTask
) {
var children = config.children;
if (void 0 !== children)
if (isStaticChildren)
if (isArrayImpl(children)) {
for (
isStaticChildren = 0;
isStaticChildren < children.length;
isStaticChildren++
)
validateChildKeys(children[isStaticChildren]);
Object.freeze && Object.freeze(children);
} else
console.error(
"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
);
else validateChildKeys(children);
if (hasOwnProperty.call(config, "key")) {
children = getComponentNameFromType(type);
var keys = Object.keys(config).filter(function (k) {
return "key" !== k;
});
isStaticChildren =
0 < keys.length
? "{key: someKey, " + keys.join(": ..., ") + ": ...}"
: "{key: someKey}";
didWarnAboutKeySpread[children + isStaticChildren] ||
((keys =
0 < keys.length ? "{" + keys.join(": ..., ") + ": ...}" : "{}"),
console.error(
'A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />',
isStaticChildren,
children,
keys,
children
),
(didWarnAboutKeySpread[children + isStaticChildren] = true));
}
children = null;
void 0 !== maybeKey &&
(checkKeyStringCoercion(maybeKey), (children = "" + maybeKey));
hasValidKey(config) &&
(checkKeyStringCoercion(config.key), (children = "" + config.key));
if ("key" in config) {
maybeKey = {};
for (var propName in config)
"key" !== propName && (maybeKey[propName] = config[propName]);
} else maybeKey = config;
children &&
defineKeyPropWarningGetter(
maybeKey,
"function" === typeof type
? type.displayName || type.name || "Unknown"
: type
);
return ReactElement(
type,
children,
self,
source,
getOwner(),
maybeKey,
debugStack,
debugTask
);
}
function validateChildKeys(node) {
"object" === typeof node &&
null !== node &&
node.$$typeof === REACT_ELEMENT_TYPE &&
node._store &&
(node._store.validated = 1);
}
var React$1 = React,
REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"),
REACT_PORTAL_TYPE = Symbol.for("react.portal"),
REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"),
REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"),
REACT_PROFILER_TYPE = Symbol.for("react.profiler");
var REACT_CONSUMER_TYPE = Symbol.for("react.consumer"),
REACT_CONTEXT_TYPE = Symbol.for("react.context"),
REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"),
REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"),
REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"),
REACT_MEMO_TYPE = Symbol.for("react.memo"),
REACT_LAZY_TYPE = Symbol.for("react.lazy"),
REACT_ACTIVITY_TYPE = Symbol.for("react.activity"),
REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"),
ReactSharedInternals =
React$1.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
hasOwnProperty = Object.prototype.hasOwnProperty,
isArrayImpl = Array.isArray,
createTask = console.createTask
? console.createTask
: function () {
return null;
};
React$1 = {
"react-stack-bottom-frame": function (callStackForError) {
return callStackForError();
}
};
var specialPropKeyWarningShown;
var didWarnAboutElementRef = {};
var unknownOwnerDebugStack = React$1["react-stack-bottom-frame"].bind(
React$1,
UnknownOwner
)();
var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
var didWarnAboutKeySpread = {};
reactJsxRuntime_development.Fragment = REACT_FRAGMENT_TYPE;
reactJsxRuntime_development.j