/**
* SmartUI AutoLoader - 智能 UI 组件自动加载系统(生产增强版)
*
* 核心功能:
* 1. 自动识别后端功能模块
* 2. 根据模块类型智能匹配 UI 组件(54 个组件完整映射)
* 3. 字段层级自动渲染(支持 20+ 种字段类型)
* 4. Schema 驱动的界面生成
* 5. 动态加载对应的后端 API 接口
* 6. 自动注入 AI 对话组件
* 7. 支持热插拔式模块扩展
*
* 使用方式:
*
*
*/
(function(global) {
'use strict';
// 配置选项
const defaultConfig = {
apiBaseUrl: 'http://124.70.146.192:8001',
cdnBaseUrl: 'https://console-test.duoweiying.cn/smart-control-center',
enableAIChat: true,
autoLoadComponents: true,
debug: false,
timeout: 10000
};
// ========== 核心优化 1: 完整的 54 个组件映射表 ==========
const MODULE_COMPONENT_MAP = {
// ===== P0 核心业务组件 (10 个) =====
'digital_human_live': {
component: 'digital-human-live-component',
icon: '🎭',
category: 'core_business',
apiPrefix: '/api/digital-human',
title: '数字人直播'
},
'short_video_platform': {
component: 'short-video-platform-component',
icon: '📹',
category: 'core_business',
apiPrefix: '/api/short-video',
title: '短视频平台'
},
'material_library': {
component: 'material-library-component',
icon: '📦',
category: 'core_business',
apiPrefix: '/api/materials',
title: '素材库管理'
},
'content_generation': {
component: 'content-generation-workbench',
icon: '✍️',
category: 'core_business',
apiPrefix: '/api/content',
title: '内容创作工作台'
},
'platform_integration': {
component: 'platform-integration-manager',
icon: '🔗',
category: 'core_business',
apiPrefix: '/api/platforms',
title: '平台集成管理'
},
'live_stream_control': {
component: 'live-stream-control-component',
icon: '🎬',
category: 'core_business',
apiPrefix: '/api/live-stream',
title: '直播控制'
},
'multi_platform_publisher': {
component: 'multi-platform-publisher',
icon: '📢',
category: 'core_business',
apiPrefix: '/api/publish',
title: '多平台发布'
},
'ai_content_optimizer': {
component: 'ai-content-optimizer',
icon: '✨',
category: 'core_business',
apiPrefix: '/api/ai-optimize',
title: 'AI 内容优化'
},
'data_analytics': {
component: 'data-analytics-dashboard',
icon: '📊',
category: 'core_business',
apiPrefix: '/api/analytics',
title: '数据分析看板'
},
'user_behavior_tracker': {
component: 'user-behavior-tracker',
icon: '👁️',
category: 'core_business',
apiPrefix: '/api/user-tracking',
title: '用户行为追踪'
},
// ===== P1 重要组件 (7 个) =====
'desktop_automation': {
component: 'desktop-automation-console',
icon: '🖥️',
category: 'important',
apiPrefix: '/api/desktop',
title: '桌面自动化控制台'
},
'project_collaboration': {
component: 'project-collaboration-component',
icon: '🤝',
category: 'important',
apiPrefix: '/api/projects',
title: '项目协作'
},
'profit_sharing': {
component: 'profit-sharing-component',
icon: '💰',
category: 'important',
apiPrefix: '/api/profit',
title: '利润分配'
},
'premium_user_management': {
component: 'premium-user-management-component',
icon: '👑',
category: 'important',
apiPrefix: '/api/premium-users',
title: '付费用户管理'
},
'global_search': {
component: 'global-search-component',
icon: '🔍',
category: 'important',
apiPrefix: '/api/search',
title: '全局搜索'
},
'newrank_platform': {
component: 'newrank-platform-component',
icon: '📈',
category: 'important',
apiPrefix: '/api/newrank',
title: '新榜平台'
},
'contribution_rewards': {
component: 'contribution-rewards-component',
icon: '🏆',
category: 'important',
apiPrefix: '/api/rewards',
title: '贡献奖励'
},
// ===== P2 辅助组件 (15 个) =====
'traffic_pool': {
component: 'traffic-pool-component',
icon: '🚦',
category: 'auxiliary',
apiPrefix: '/api/traffic',
title: '流量池管理'
},
'video_generation': {
component: 'video-generation-workflow',
icon: '🎥',
category: 'auxiliary',
apiPrefix: '/api/video-gen',
title: '视频生成工作流'
},
'feature_switch': {
component: 'feature-switch-component',
icon: '🔧',
category: 'auxiliary',
apiPrefix: '/api/features',
title: '功能开关'
},
'folder_manager': {
component: 'folder-manager-component',
icon: '📁',
category: 'auxiliary',
apiPrefix: '/api/files',
title: '文件管理器'
},
'navigation_assistant': {
component: 'navigation-assistant-component',
icon: '🧭',
category: 'auxiliary',
apiPrefix: '/api/navigation',
title: '导航助手'
},
'resource_management': {
component: 'resource-management-component',
icon: '📚',
category: 'auxiliary',
apiPrefix: '/api/resources',
title: '资源管理'
},
'storage_quota': {
component: 'storage-quota-component',
icon: '💾',
category: 'auxiliary',
apiPrefix: '/api/storage',
title: '存储配额'
},
'security_center': {
component: 'security-center-component',
icon: '🛡️',
category: 'auxiliary',
apiPrefix: '/api/security',
title: '安全中心'
},
'dialog': {
component: 'dialog-component',
icon: '💬',
category: 'auxiliary',
apiPrefix: null,
title: '对话框'
},
'drawer': {
component: 'drawer-component',
icon: '🗄️',
category: 'auxiliary',
apiPrefix: null,
title: '抽屉面板'
},
'form': {
component: 'form-component',
icon: '📝',
category: 'auxiliary',
apiPrefix: null,
title: '表单生成器'
},
'data_table': {
component: 'data-table-component',
icon: '📋',
category: 'auxiliary',
apiPrefix: null,
title: '数据表格'
},
'chart': {
component: 'chart-component',
icon: '📈',
category: 'auxiliary',
apiPrefix: null,
title: '图表组件'
},
'loading': {
component: 'loading-component',
icon: '⏳',
category: 'auxiliary',
apiPrefix: null,
title: '加载动画'
},
'ad_manager': {
component: 'ad-manager',
icon: '📣',
category: 'auxiliary',
apiPrefix: '/api/ads',
title: '广告管理'
},
// ===== P3 增强组件 (22 个) =====
'data_import_export': {
component: 'data-import-export-component',
icon: '🔄',
category: 'enhanced',
apiPrefix: '/api/import-export',
title: '数据导入导出'
},
'notification_center': {
component: 'notification-center-component',
icon: '🔔',
category: 'enhanced',
apiPrefix: '/api/notifications',
title: '通知中心'
},
'performance_monitor': {
component: 'performance-monitor-component',
icon: '⚡',
category: 'enhanced',
apiPrefix: '/api/performance',
title: '性能监控'
},
'log_query': {
component: 'log-query-component',
icon: '📜',
category: 'enhanced',
apiPrefix: '/api/logs',
title: '日志查询'
},
'task_scheduler': {
component: 'task-scheduler-component',
icon: '⏰',
category: 'enhanced',
apiPrefix: '/api/tasks',
title: '任务调度'
},
'api_gateway': {
component: 'api-gateway-component',
icon: '🌐',
category: 'enhanced',
apiPrefix: '/api/gateway',
title: 'API 网关'
},
'cache_manager': {
component: 'cache-manager-component',
icon: '🗄️',
category: 'enhanced',
apiPrefix: '/api/cache',
title: '缓存管理'
},
'ai_model_management': {
component: 'ai-model-management-component',
icon: '🧠',
category: 'enhanced',
apiPrefix: '/api/ai-models',
title: 'AI 模型管理'
},
'ai_skill_registry': {
component: 'ai-skill-registry-component',
icon: '⚙️',
category: 'enhanced',
apiPrefix: '/api/ai-skills',
title: 'AI 技能注册'
},
'health_monitor': {
component: 'health-monitor-component',
icon: '❤️',
category: 'enhanced',
apiPrefix: '/api/health',
title: '健康监控'
},
'auth_manager': {
component: 'auth-manager',
icon: '🔐',
category: 'enhanced',
apiPrefix: '/api/auth',
title: '认证授权'
},
'billing_admin': {
component: 'billing-admin',
icon: '💳',
category: 'enhanced',
apiPrefix: '/api/billing',
title: '计费管理'
},
'system_admin_panel': {
component: 'system-admin-panel',
icon: '🎛️',
category: 'enhanced',
apiPrefix: '/api/admin',
title: '系统管理面板'
},
'user_admin': {
component: 'user-admin',
icon: '👥',
category: 'enhanced',
apiPrefix: '/api/users',
title: '用户管理'
},
'training_platform': {
component: 'training-platform',
icon: '🎓',
category: 'enhanced',
apiPrefix: '/api/training',
title: '训练平台'
},
'tuike_dashboard': {
component: 'tuike-dashboard',
icon: '💸',
category: 'enhanced',
apiPrefix: '/api/tuike',
title: '推客仪表板'
},
'workflow_editor': {
component: 'workflow-editor',
icon: '📊',
category: 'enhanced',
apiPrefix: '/api/workflows',
title: '工作流编辑器'
},
'moderation_panel': {
component: 'moderation-panel',
icon: '✅',
category: 'enhanced',
apiPrefix: '/api/moderation',
title: '审核面板'
},
'chat_client': {
component: 'chat-client',
icon: '💬',
category: 'enhanced',
apiPrefix: '/api/chat',
title: '聊天客户端'
},
'ai_chat': {
component: 'ai-chat-component',
icon: '🤖',
category: 'enhanced',
apiPrefix: '/api/ai-chat',
title: 'AI 聊天'
},
'smart_ui_autoloader': {
component: 'smart-ui-autoloader',
icon: '🚀',
category: 'enhanced',
apiPrefix: null,
title: 'UI 自动加载器'
},
'ui_core': {
component: 'ui-core',
icon: '⚙️',
category: 'enhanced',
apiPrefix: null,
title: 'UI 核心引擎'
}
};
// ========== 核心优化 2: 字段层级自动匹配系统 ==========
const FIELD_TYPE_MAPPING = {
// 基础类型
'string': { component: 'text-input', type: 'input', icon: '📝' },
'text': { component: 'textarea', type: 'input', icon: '📄' },
'number': { component: 'number-input', type: 'input', icon: '🔢' },
'integer': { component: 'number-input', type: 'input', icon: '🔢' },
'float': { component: 'number-input', type: 'input', icon: '🔢', step: 'any' },
'double': { component: 'number-input', type: 'input', icon: '🔢', step: 'any' },
'boolean': { component: 'checkbox', type: 'input', icon: '☑️' },
'bool': { component: 'checkbox', type: 'input', icon: '☑️' },
'date': { component: 'date-picker', type: 'input', icon: '📅' },
'datetime': { component: 'datetime-picker', type: 'input', icon: '🕐' },
'time': { component: 'time-picker', type: 'input', icon: '⏰' },
'timestamp': { component: 'datetime-picker', type: 'input', icon: '🕐' },
// 选择类型
'enum': { component: 'select-dropdown', type: 'select', icon: '📋' },
'choice': { component: 'select-dropdown', type: 'select', icon: '📋' },
'options': { component: 'select-dropdown', type: 'select', icon: '📋' },
'radio': { component: 'radio-group', type: 'select', icon: '🔘' },
'checkbox': { component: 'checkbox-group', type: 'select', icon: '☑️' },
'multiple_choice': { component: 'checkbox-group', type: 'select', icon: '☑️' },
// 复杂类型
'array': { component: 'data-table', type: 'complex', icon: '📊' },
'list': { component: 'data-table', type: 'complex', icon: '📊' },
'object': { component: 'nested-form', type: 'complex', icon: '📁' },
'json': { component: 'code-editor', type: 'complex', icon: '💻' },
'map': { component: 'key-value-editor', type: 'complex', icon: '🗺️' },
// 媒体类型
'image': { component: 'image-uploader', type: 'media', icon: '🖼️' },
'images': { component: 'image-gallery-uploader', type: 'media', icon: '🖼️' },
'video': { component: 'video-uploader', type: 'media', icon: '🎬' },
'videos': { component: 'video-gallery-uploader', type: 'media', icon: '🎬' },
'audio': { component: 'audio-uploader', type: 'media', icon: '🎵' },
'file': { component: 'file-uploader', type: 'media', icon: '📎' },
'files': { component: 'file-gallery-uploader', type: 'media', icon: '📎' },
// 特殊类型
'url': { component: 'url-input', type: 'special', icon: '🔗' },
'email': { component: 'email-input', type: 'special', icon: '📧' },
'phone': { component: 'tel-input', type: 'special', icon: '📱' },
'mobile': { component: 'tel-input', type: 'special', icon: '📱' },
'color': { component: 'color-picker', type: 'special', icon: '🎨' },
'range': { component: 'slider', type: 'special', icon: '📏' },
'tags': { component: 'tag-input', type: 'special', icon: '🏷️' },
'category': { component: 'category-selector', type: 'special', icon: '📂' },
'search': { component: 'search-input', type: 'special', icon: '🔍' },
'password': { component: 'password-input', type: 'special', icon: '🔒' },
'hidden': { component: 'hidden-input', type: 'special', icon: '👁️' }
};
// 通用 UI 组件库 (所有模块共享)
const SHARED_COMPONENTS = [
{ name: 'toast', path: '/shared/components/feedback/toast.js', loaded: false },
{ name: 'loading', path: '/shared/components/feedback/loading.js', loaded: false },
{ name: 'dialog', path: '/shared/components/feedback/dialog.js', loaded: false },
{ name: 'data-table', path: '/shared/components/data/table.js', loaded: false },
{ name: 'stat-card', path: '/shared/components/display/stat-card.js', loaded: false },
{ name: 'ai-chat', path: '/components/ai-chat-component.js', loaded: false }
];
// Schema 渲染器类
class FieldSchemaRenderer {
constructor() {
this.fieldMapping = FIELD_TYPE_MAPPING;
}
/**
* 根据 Schema 自动渲染表单
*/
renderForm(schema, formData = {}, onSubmit) {
if (!schema || !schema.fields) {
console.error('Invalid schema');
return '';
}
const formId = `form-${schema.name}-${Date.now()}`;
return `
`;
}
/**
* 渲染单个字段
*/
renderField(field, value) {
const fieldType = field.type || 'string';
const componentConfig = this.fieldMapping[fieldType] || this.fieldMapping['string'];
return `
${field.label ? `` : ''}
${this.createInput(componentConfig.component, field, value)}
${field.description ? `${field.description}` : ''}
${field.required ? '*' : ''}
`;
}
/**
* 创建输入控件
*/
createInput(componentType, field, value) {
const name = field.name;
const defaultValue = value !== undefined ? value : field.default || '';
const required = field.required ? 'required' : '';
// 根据 componentType 创建对应的 HTML
switch(componentType) {
case 'text-input':
return ``;
case 'number-input':
const step = field.step || 1;
return ``;
case 'checkbox':
return ``;
case 'select-dropdown':
const options = field.options || field.enum || [];
return `
`;
case 'textarea':
const rows = field.rows || 4;
return ``;
case 'date-picker':
return ``;
case 'datetime-picker':
return ``;
case 'data-table':
return this.renderDataTable(field, value);
case 'image-uploader':
return this.renderImageUploader(field, value);
case 'file-uploader':
return this.renderFileUploader(field, value);
case 'tag-input':
return this.renderTagInput(field, value);
default:
return ``;
}
}
/**
* 渲染数据表格
*/
renderDataTable(field, data) {
if (!data || !Array.isArray(data) || data.length === 0) {
return '暂无数据
';
}
const columns = field.columns || Object.keys(data[0]);
return `
${columns.map(col => `| ${col} | `).join('')}
${data.map((row, index) => `
${columns.map(col => `| ${row[col]} | `).join('')}
`).join('')}
`;
}
/**
* 渲染图片上传器
*/
renderImageUploader(field, value) {
return `
`;
}
/**
* 渲染文件上传器
*/
renderFileUploader(field, value) {
return `
${value ? `
📄 ${value}
` : ''}
`;
}
/**
* 渲染标签输入器
*/
renderTagInput(field, value) {
const tags = Array.isArray(value) ? value.join(', ') : (value || '');
return `
`;
}
}
// 主加载器对象
const SmartUILoader = {
config: null,
loadedModules: new Set(),
loadedComponents: new Set(),
currentModule: null,
schemaRenderer: new FieldSchemaRenderer(),
/**
* 初始化加载器
*/
initialize(userConfig = {}) {
this.config = { ...defaultConfig, ...userConfig };
if (this.config.debug) {
console.log('[SmartUI] 初始化配置:', this.config);
console.log('[SmartUI] 已注册组件映射:', Object.keys(MODULE_COMPONENT_MAP).length, '个');
console.log('[SmartUI] 已注册字段类型:', Object.keys(FIELD_TYPE_MAPPING).length, '种');
}
// 加载共享组件
this.loadSharedComponents();
// 监听 DOM 就绪
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.onDOMReady());
} else {
this.onDOMReady();
}
return this;
},
/**
* DOM 就绪后的处理
*/
async onDOMReady() {
if (this.config.debug) {
console.log('[SmartUI] DOM 已就绪,开始自动加载...');
}
// 1. 检测当前页面所在的模块
await this.detectCurrentModule();
// 2. 如果启用了自动加载,加载对应模块的组件
if (this.config.autoLoadComponents && this.currentModule) {
await this.loadModuleComponents(this.currentModule);
}
// 3. 注入 AI 对话组件 (如果启用)
if (this.config.enableAIChat) {
this.injectAIChat();
}
},
/**
* 检测当前模块
*/
async detectCurrentModule() {
// 方法 1: 从 URL 路径识别
const pathParts = window.location.pathname.split('/').filter(Boolean);
const moduleName = pathParts[pathParts.length - 1];
if (moduleName && MODULE_COMPONENT_MAP[moduleName]) {
this.currentModule = moduleName;
if (this.config.debug) {
console.log(`[SmartUI] 从 URL 检测到模块:${moduleName}`);
}
return;
}
// 方法 2: 从页面 data 属性读取
const moduleData = document.querySelector('[data-module]');
if (moduleData) {
const moduleName = moduleData.getAttribute('data-module');
if (MODULE_COMPONENT_MAP[moduleName]) {
this.currentModule = moduleName;
if (this.config.debug) {
console.log(`[SmartUI] 从 data-module 检测到模块:${moduleName}`);
}
return;
}
}
// 方法 3: 从页面标题匹配
const pageTitle = document.title.toLowerCase();
for (const [key, config] of Object.entries(MODULE_COMPONENT_MAP)) {
if (pageTitle.includes(config.title.toLowerCase())) {
this.currentModule = key;
if (this.config.debug) {
console.log(`[SmartUI] 从页面标题匹配到模块:${key}`);
}
return;
}
}
if (this.config.debug) {
console.warn('[SmartUI] 未检测到匹配的模块');
}
},
/**
* 加载模块组件
*/
async loadModuleComponents(moduleName) {
const moduleConfig = MODULE_COMPONENT_MAP[moduleName];
if (!moduleConfig) {
console.error(`[SmartUI] 未找到模块配置:${moduleName}`);
return;
}
if (this.config.debug) {
console.log(`[SmartUI] 加载模块组件:${moduleConfig.title}`, moduleConfig);
}
// 1. 动态加载组件 JS 文件
await this.loadComponent(moduleConfig.component);
// 2. 查找或创建容器
const container = this.findOrCreateContainer(moduleName);
// 3. 渲染组件
this.renderComponent(container, moduleConfig);
// 4. 加载 API 数据(如果有)
if (moduleConfig.apiPrefix) {
await this.loadAPIData(moduleConfig.apiPrefix, container);
}
},
/**
* 查找或创建容器
*/
findOrCreateContainer(moduleName) {
// 尝试从 data 属性获取容器
let container = document.querySelector(`[data-module="${moduleName}"]`);
if (!container) {
// 尝试通过 ID 查找
container = document.getElementById(`${moduleName}-container`) ||
document.getElementById(`${moduleName.replace(/_/g, '-')}-container`);
}
if (!container) {
// 创建默认容器
container = document.createElement('div');
container.id = `${moduleName}-container`;
container.className = 'smart-module-container';
container.style.cssText = 'max-width: 1400px; margin: 0 auto; padding: 20px;';
// 添加到 body
document.body.appendChild(container);
}
return container;
},
/**
* 渲染组件(修复版)
*/
renderComponent(container, moduleConfig) {
if (this.config.debug) {
console.log(`[SmartUI] 开始渲染组件:${moduleConfig.title}`);
console.log(`[SmartUI] 容器:`, container);
console.log(`[SmartUI] 组件名:${moduleConfig.component}`);
}
// 检查组件是否已加载
const componentName = moduleConfig.component.replace(/-/g, '_');
const ComponentClass = global[componentName] || global[moduleConfig.component];
if (this.config.debug) {
console.log(`[SmartUI] ComponentClass:`, ComponentClass);
}
if (!ComponentClass) {
console.error(`[SmartUI] ❌ 组件类不存在:${moduleConfig.component}`);
container.innerHTML = `
⚠️ 组件未找到
组件 "${moduleConfig.component}" 尚未加载或不存在
请检查 CDN 上是否有该组件文件
`;
return;
}
try {
// ✅ 关键修复:正确传递参数
// 组件构造函数期望:constructor(containerId, options)
const instance = new ComponentClass(
container.id, // 第一个参数:containerId
{ // 第二个参数:options
container: container,
apiBaseUrl: this.config.apiBaseUrl + (moduleConfig.apiPrefix || ''),
moduleKey: this.currentModule,
moduleConfig: moduleConfig,
debug: this.config.debug
}
);
if (this.config.debug) {
console.log(`[SmartUI] 组件实例已创建:`, instance);
console.log(`[SmartUI] API 地址:${instance.options?.apiBaseUrl || '未设置'}`);
}
// ✅ 关键修复:调用组件的 initialize 或 render 方法
if (typeof instance.initialize === 'function') {
console.log(`[SmartUI] 调用组件 initialize 方法`);
instance.initialize().then(() => {
if (this.config.debug) {
console.log(`[SmartUI] ✅ 组件 ${moduleConfig.title} 初始化完成`);
}
}).catch(error => {
console.error(`[SmartUI] ❌ 组件初始化失败:`, error);
container.innerHTML += `
❌ 初始化失败
${error.message}
`;
});
} else if (typeof instance.render === 'function') {
console.log(`[SmartUI] 调用组件 render 方法`);
instance.render();
if (this.config.debug) {
console.log(`[SmartUI] ✅ 组件 ${moduleConfig.title} 已渲染`);
}
} else {
console.warn(`[SmartUI] ⚠️ 组件 ${moduleConfig.component} 没有 initialize 或 render 方法`);
container.innerHTML = `
⚠️ 组件缺少必要的方法
请确保组件类有 initialize() 或 render() 方法
`;
}
// 存储组件实例引用
if (!this.loadedInstances) {
this.loadedInstances = {};
}
this.loadedInstances[moduleConfig.component] = instance;
if (this.config.debug) {
console.log(`[SmartUI] ✅ 组件 ${moduleConfig.title} 渲染完成`);
}
} catch (error) {
console.error(`[SmartUI] ❌ 组件渲染异常:`, error);
container.innerHTML = `
❌ 组件渲染失败
${error.message}
${error.stack}
`;
}
},
/**
* 加载 API 数据
*/
async loadAPIData(apiPrefix, container) {
try {
const response = await fetch(`${this.config.apiBaseUrl}${apiPrefix}/list`, {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
});
if (response.ok) {
const data = await response.json();
if (this.config.debug) {
console.log(`[SmartUI] API 数据已加载:`, data);
}
// 触发数据更新事件
const event = new CustomEvent('smart-ui:data-loaded', { detail: data });
container.dispatchEvent(event);
}
} catch (error) {
if (this.config.debug) {
console.warn(`[SmartUI] API 数据加载失败:`, error);
}
}
},
/**
* 加载单个组件
*/
async loadComponent(componentName) {
const scriptUrl = `${this.config.cdnBaseUrl}/components/${componentName}.js`;
if (this.loadedComponents.has(scriptUrl)) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = scriptUrl;
script.onload = () => {
this.loadedComponents.add(scriptUrl);
if (this.config.debug) {
console.log(`[SmartUI] 组件已加载:${componentName}`);
}
resolve();
};
script.onerror = () => {
console.error(`[SmartUI] 组件加载失败:${componentName}`);
reject(new Error(`Failed to load ${componentName}`));
};
document.head.appendChild(script);
});
},
/**
* 加载共享组件
*/
loadSharedComponents() {
SHARED_COMPONENTS.forEach(component => {
if (!component.loaded) {
const script = document.createElement('script');
script.src = `${this.config.cdnBaseUrl}${component.path}`;
script.onload = () => {
component.loaded = true;
if (this.config.debug) {
console.log(`[SmartUI] 共享组件已加载:${component.name}`);
}
};
document.head.appendChild(script);
}
});
},
/**
* 注入 AI 聊天组件
*/
injectAIChat() {
const chatContainer = document.createElement('div');
chatContainer.id = 'ai-chat-widget';
chatContainer.style.cssText = 'position: fixed; bottom: 20px; right: 20px; width: 350px; height: 500px; z-index: 9999;';
document.body.appendChild(chatContainer);
this.loadComponent('ai-chat-component').then(() => {
const AIChatComponent = global['ai_chat_component'] || global['ai-chat-component'];
if (AIChatComponent) {
new AIChatComponent({
containerId: 'ai-chat-widget',
apiBaseUrl: this.config.apiBaseUrl + '/api/ai-chat'
}).initialize();
}
});
},
/**
* 渲染 Schema 表单(公开方法)
*/
renderSchemaForm(schema, formData = {}, onSubmit) {
return this.schemaRenderer.renderForm(schema, formData, onSubmit);
},
/**
* 🚀 自动发现所有后端模块(应用市场模式核心)
*/
async discoverModules() {
console.log('[SmartUI] 正在从后端自动发现模块...');
try {
const response = await fetch(`${this.config.apiBaseUrl}/api/modules`, {
method: 'GET',
headers: { 'Content-Type': 'application/json' }
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
const modules = data.modules || [];
console.log(`[SmartUI] ✅ 发现 ${modules.length} 个模块`);
// 为每个模块智能匹配 UI组件
modules.forEach(module => {
module.component = this.matchComponent(module);
module.loaded = false;
if (this.config.debug) {
console.log(`[SmartUI] 模块 "${module.name}" → 组件 "${module.component}"`);
}
});
return modules;
} catch (error) {
console.warn('[SmartUI] ⚠️ 自动发现失败,使用内置映射表:', error);
// 降级方案:返回内置的 MODULE_COMPONENT_MAP
return Object.keys(MODULE_COMPONENT_MAP).map(key => ({
key: key,
...MODULE_COMPONENT_MAP[key],
loaded: false
}));
}
},
/**
* 🎯 智能匹配 UI组件(基于规则引擎)
*/
matchComponent(module) {
// 规则 1: 如果 MODULE_COMPONENT_MAP 中有定义,优先使用
if (MODULE_COMPONENT_MAP[module.key]) {
return MODULE_COMPONENT_MAP[module.key].component;
}
// 规则 2: 根据 category 匹配
const categoryRules = {
'core_business': 'business-workbench-component',
'important': 'advanced-form-component',
'auxiliary': 'simple-form-component',
'enhanced': 'generic-module-component'
};
if (categoryRules[module.category]) {
return categoryRules[module.category];
}
// 规则 3: 根据名称关键词匹配
const name = module.name || '';
const keywordRules = [
{ keywords: ['直播', 'stream', 'live'], component: 'live-stream-component' },
{ keywords: ['视频', 'video'], component: 'video-component' },
{ keywords: ['数据', 'data', '分析', 'analytics'], component: 'data-dashboard-component' },
{ keywords: ['内容', 'content', '创作'], component: 'content-generation-component' },
{ keywords: ['素材', 'material', '资源'], component: 'material-library-component' },
{ keywords: ['发布', 'publish', '分发'], component: 'publisher-component' },
{ keywords: ['AI', '智能', '优化'], component: 'ai-optimizer-component' },
{ keywords: ['搜索', 'search'], component: 'search-component' },
{ keywords: ['管理', 'manage'], component: 'management-component' },
{ keywords: ['监控', 'monitor', '监控'], component: 'monitor-component' }
];
for (const rule of keywordRules) {
if (rule.keywords.some(keyword => name.toLowerCase().includes(keyword))) {
return rule.component;
}
}
// 规则 4: 根据 schema 复杂度匹配
if (module.schema && module.schema.fields) {
const fieldCount = module.schema.fields.length;
if (fieldCount > 20) {
return 'advanced-form-component';
} else if (fieldCount > 10) {
return 'intermediate-form-component';
} else {
return 'simple-form-component';
}
}
// 默认组件
return 'generic-module-component';
},
/**
* 👤 检查用户权限(简化版)
*/
isUserVIP() {
// TODO: 实际应该调用后端 API 检查用户权限
// 这里返回 true 用于测试
return true;
},
/**
* 💬 发送消息到 AI(统一入口)
*/
sendToAI(message) {
if (!message) return;
console.log('[SmartUI] 发送消息到 AI:', message);
// 如果 AI 聊天窗口已加载,直接发送
const chatWidget = document.getElementById('ai-chat-widget');
if (chatWidget && chatWidget._chatComponent) {
chatWidget._chatComponent.sendMessage(message);
} else {
// 否则先注入 AI 聊天窗口
this.injectAIChat();
setTimeout(() => {
const widget = document.getElementById('ai-chat-widget');
if (widget && widget._chatComponent) {
widget._chatComponent.sendMessage(message);
}
}, 500);
}
}
};
// 导出到全局
global.SmartUILoader = SmartUILoader;
global.MODULE_COMPONENT_MAP = MODULE_COMPONENT_MAP;
global.FIELD_TYPE_MAPPING = FIELD_TYPE_MAPPING;
global.FieldSchemaRenderer = FieldSchemaRenderer;
})(typeof window !== 'undefined' ? window : this);
/**
* 多模态消息发送(支持文件/图片/视频上传)
*/
async sendMultimodalMessage(message, attachments = {}) {
const { files = [], images = [], videos = [] } = attachments;
// 检查是否需要登录(如果有附件或长消息)
const requiresAuth = files.length > 0 || images.length > 0 || videos.length > 0 || message.length > 100;
if (requiresAuth && !this.isAuthenticated()) {
await this.showLoginModal();
return;
}
// 显示用户消息
this.appendUserMessage(message, attachments);
// 构建 FormData 用于上传文件
const formData = new FormData();
formData.append('message', message);
files.forEach((file, index) => formData.append(`files[]`, file));
images.forEach((file, index) => formData.append(`images[]`, file));
videos.forEach((file, index) => formData.append(`videos[]`, file));
try {
const token = localStorage.getItem('authToken') || localStorage.getItem('admin_token');
const response = await fetch(`${this.config.apiBaseUrl}/api/chat/multimodal`, {
method: 'POST',
headers: token ? {
'Authorization': `Bearer ${token}`
} : {},
body: formData
});
const data = await response.json();
if (data.reply) {
this.appendAIMessage(data.reply);
} else if (data.detail) {
this.appendSystemMessage('处理失败:' + data.detail);
}
} catch (error) {
console.error('[多模态聊天] 发送失败:', error);
this.appendSystemMessage('发送失败,请检查网络连接');
}
}
/**
* 检查是否已认证
*/
isAuthenticated() {
const token = localStorage.getItem('authToken') || localStorage.getItem('admin_token');
return !!token;
}
/**
* 显示登录弹窗
*/
async showLoginModal() {
// 检查是否已有登录弹窗
if (document.querySelector('.login-modal-overlay')) {
return;
}
const modal = document.createElement('div');
modal.className = 'login-modal-overlay';
modal.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
`;
modal.innerHTML = `
`;
document.body.appendChild(modal);
}
/**
* 执行弹窗登录
*/
async performModalLogin() {
const username = document.getElementById('modal-login-username').value;
const password = document.getElementById('modal-login-password').value;
if (!username || !password) {
alert('请输入用户名和密码');
return;
}
try {
const response = await fetch(`${this.config.apiBaseUrl}/auth/login`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (response.ok && data.token) {
localStorage.setItem('authToken', data.token);
localStorage.setItem('user_info', JSON.stringify({
username: data.username || username,
role: data.role || 'user',
permissions: data.permissions || []
}));
alert('✅ 登录成功!');
document.querySelector('.login-modal-overlay').remove();
// 重新触发之前的操作
location.reload();
} else {
throw new Error(data.detail || '登录失败');
}
} catch (error) {
alert('❌ 登录失败:' + error.message);
}
}
/**
* 显示用户消息(支持附件)
*/
appendUserMessage(message, attachments = {}) {
const messagesContainer = document.getElementById('ai-chat-messages');
if (!messagesContainer) return;
const userMsg = document.createElement('div');
userMsg.style.cssText = 'text-align: right; margin-bottom: 15px;';
let attachmentsHtml = '';
if (attachments.files?.length > 0) {
attachmentsHtml += `📎 附件:${attachments.files.length}个文件
`;
}
if (attachments.images?.length > 0) {
attachmentsHtml += `🖼️ 图片:${attachments.images.length}张
`;
}
if (attachments.videos?.length > 0) {
attachmentsHtml += `🎬 视频:${attachments.videos.length}个
`;
}
userMsg.innerHTML = `
${message}
${attachmentsHtml}
`;
messagesContainer.appendChild(userMsg);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}