UNPKG

@devflow-cc/react

Version:

一个功能强大的React库,用于构建数据驱动的应用程序,支持实时通信、身份验证和数据库操作

1,836 lines (1,817 loc) 55.3 kB
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