/** * @class ConfigurationConfig * @classdesc 构型配置开发组件,采用卡片风格,展示机型信息和构型信息。 * @extends HTMLElement */ class ConfigurationConfig extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.currentView = 'planes'; // 'planes' 或 'configurations' 或 'editor' this.selectedPlane = null; this.selectedConfiguration = null; this.userAccessLevel = 0; // 添加用户权限级别属性 /** * 初始化DOM结构,采用卡片风格,展示机型信息和构型信息。 */ this.shadowRoot.innerHTML = `
加载中...
`; // 绑定事件 this.shadowRoot.getElementById('backButton').addEventListener('click', (e) => { e.preventDefault(); if (this.currentView === 'editor') { this.showConfigurations(this.selectedPlane); } else { this.showPlanes(); } }); // 绑定编辑器按钮事件 this.shadowRoot.getElementById('saveButton').addEventListener('click', () => this.saveConfiguration()); this.shadowRoot.getElementById('cancelButton').addEventListener('click', () => { this.showConfigurations(this.selectedPlane); }); // 添加输入验证 this.shadowRoot.getElementById('cpuAffinity').addEventListener('input', (e) => { // 只允许数字和英文逗号 e.target.value = e.target.value.replace(/[^0-9,]/g, ''); }); this.shadowRoot.getElementById('domainId').addEventListener('input', (e) => { // 只允许数字 e.target.value = e.target.value.replace(/[^0-9]/g, ''); // 限制范围在0-232之间 const value = parseInt(e.target.value); if (value > 232) { e.target.value = '232'; } }); // 获取机型数据 this.loadPlanes(); } /** * @method loadPlanes * @description 从服务器获取机型数据并更新UI */ async loadPlanes() { try { const response = await fetch('/api/planes'); if (!response.ok) { throw new Error('获取机型数据失败'); } const planes = await response.json(); this.renderPlanes(planes); } catch (error) { console.error('加载机型数据失败:', error); this.showError('加载机型数据失败,请稍后重试'); } } /** * @method loadConfigurations * @description 从服务器获取构型数据并更新UI * @param {string} planeName - 机型名称 */ async loadConfigurations(planeName) { try { const response = await fetch(`/api/configurations?plane=${encodeURIComponent(planeName)}`); if (!response.ok) { throw new Error('获取构型数据失败'); } const configs = await response.json(); this.renderConfigurations(configs, planeName); } catch (error) { console.error('加载构型数据失败:', error); this.showError('加载构型数据失败,请稍后重试'); } } /** * @method renderPlanes * @description 渲染机型卡片 * @param {Array} planes - 机型数据数组 */ renderPlanes(planes) { const container = this.shadowRoot.getElementById('contentContainer'); if (!planes || planes.length === 0) { container.innerHTML = '
暂无机型数据
'; return; } container.innerHTML = planes.map(plane => `
${plane.Icon ? `${plane.PlaneName}` : ''}
${plane.PlaneName || '未知机型'}
${plane.Description || '暂无描述'}
`).join(''); // 添加点击事件 container.querySelectorAll('.config-card').forEach(card => { card.addEventListener('click', () => { const planeName = card.dataset.plane; this.showConfigurations(planeName); }); }); } /** * @method showBaseConfigDialog * @description 显示基准构型选择对话框 * @param {Array} configs - 构型数据数组 * @param {string} planeName - 机型名称 * @returns {Promise} 返回选择的基准构型或undefined(表示不使用基准构型) */ showBaseConfigDialog(configs, planeName) { return new Promise((resolve) => { const dialog = document.createElement('div'); dialog.className = 'base-config-dialog'; dialog.innerHTML = `
选择基准构型
`; const select = dialog.querySelector('#baseConfigSelect'); dialog.querySelector('#cancelButton').addEventListener('click', () => { document.body.removeChild(dialog); resolve(null); // 取消时返回null }); dialog.querySelector('#confirmButton').addEventListener('click', () => { const selectedValue = select.value; const selectedConfig = selectedValue === 'none' ? undefined : // 选择"不使用基准构型"时返回undefined configs.find(c => c.ConfID === parseInt(selectedValue)); document.body.removeChild(dialog); resolve(selectedConfig); }); document.body.appendChild(dialog); }); } /** * @method checkUserAccessLevel * @description 检查用户访问权限级别 */ async checkUserAccessLevel() { try { const response = await fetch('/api/check-auth', { credentials: 'include' }); const result = await response.json(); if (result.success) { this.userAccessLevel = parseInt(result.user.access_level); // 重新渲染构型列表以更新删除按钮的显示状态 if (this.currentView === 'configurations' && this.selectedPlane) { this.loadConfigurations(this.selectedPlane); } } } catch (error) { console.error('获取用户权限失败:', error); } } /** * @method renderConfigurations * @description 渲染构型卡片 * @param {Array} configs - 构型数据数组 * @param {string} planeName - 机型名称 */ renderConfigurations(configs, planeName) { const container = this.shadowRoot.getElementById('contentContainer'); if (!configs || configs.length === 0) { container.innerHTML = '
暂无构型数据
'; return; } // 添加新建构型卡片(根据权限显示) container.innerHTML = ` ${this.userAccessLevel >= 2 ? `
+ 新建构型
` : ''} ${configs.map(config => `
${config.ConfName || '未知构型'}
${this.userAccessLevel >= 2 ? ` ` : ''}
`).join('')} `; // 添加新建构型卡片点击事件(仅在权限足够时添加) if (this.userAccessLevel >= 2) { container.querySelector('#newConfigCard')?.addEventListener('click', async () => { const baseConfig = await this.showBaseConfigDialog(configs, planeName); if (baseConfig !== null) { const defaultConfig = { ConfName: '', OSName: baseConfig?.OSName || '', OSVersion: baseConfig?.OSVersion || '', RTXVersion: baseConfig?.RTXVersion || '', CPUAffinity: baseConfig?.CPUAffinity || '', DomainID: baseConfig?.DomainID || '', WorkPath: baseConfig?.WorkPath || '', ModelsPath: baseConfig?.ModelsPath || '', ServicesPath: baseConfig?.ServicesPath || '', ConsoleDebug: baseConfig?.ConsoleDebug ?? 1, ConsoleInfo: baseConfig?.ConsoleInfo ?? 1, ConsoleWarning: baseConfig?.ConsoleWarning ?? 1, ConsoleError: baseConfig?.ConsoleError ?? 1, LogDebug: baseConfig?.LogDebug ?? 0, LogInfo: baseConfig?.LogInfo ?? 1, LogWarning: baseConfig?.LogWarning ?? 1, LogError: baseConfig?.LogError ?? 1, sourceConfId: baseConfig?.ConfID // 添加源构型ID }; this.showEditor(defaultConfig, planeName, true); } }); } // 添加构型卡片点击事件 container.querySelectorAll('.config-card:not(.new-config)').forEach(card => { card.addEventListener('click', (e) => { // 如果点击的是删除按钮,不触发编辑 if (e.target.closest('.delete-button')) { return; } const configId = parseInt(card.dataset.configId, 10); const config = configs.find(c => c.ConfID === configId); if (config) { this.showEditor(config, planeName, false); } }); }); // 添加删除按钮点击事件 container.querySelectorAll('.delete-button').forEach(button => { button.addEventListener('click', async (e) => { e.stopPropagation(); // 阻止事件冒泡 // 再次检查权限 if (this.userAccessLevel < 2) { alert('您没有删除构型的权限'); return; } const configId = parseInt(button.dataset.configId, 10); const config = configs.find(c => c.ConfID === configId); if (config && confirm(`确定要删除构型"${config.ConfName}"吗?\n注意:删除后将无法恢复,且会同时删除该构型下的所有模型组、模型和服务。`)) { try { const response = await fetch(`/api/configurations/${configId}`, { method: 'DELETE', credentials: 'include' }); const responseData = await response.json(); if (!response.ok) { throw new Error(responseData.error || '删除构型失败'); } // 重新加载构型列表 this.loadConfigurations(planeName); } catch (error) { console.error('删除构型失败:', error); alert(error.message || '删除构型失败,请稍后重试'); } } }); }); } /** * @method showEditor * @description 显示构型编辑器 * @param {Object} configuration - 构型数据 * @param {string} planeName - 机型名称 * @param {boolean} isNew - 是否是新建构型 */ showEditor(configuration, planeName, isNew) { this.currentView = 'editor'; this.selectedConfiguration = configuration; this.isNewConfiguration = isNew; // 更新UI const pageTitle = this.shadowRoot.getElementById('pageTitle'); const backSection = this.shadowRoot.getElementById('backSection'); const backButtonText = this.shadowRoot.querySelector('#backButton span:last-child'); const contentContainer = this.shadowRoot.getElementById('contentContainer'); const editorContainer = this.shadowRoot.getElementById('editorContainer'); const confNameInput = this.shadowRoot.getElementById('confName'); if (!pageTitle || !backSection || !contentContainer || !editorContainer) { return; } pageTitle.textContent = isNew ? `${planeName} - 新建构型` : `${planeName} - ${configuration.ConfName} 构型`; backSection.style.display = 'block'; backButtonText.textContent = '返回构型列表'; contentContainer.style.display = 'none'; editorContainer.style.display = 'block'; // 设置构型名称输入框状态 confNameInput.readOnly = !isNew; if (isNew) { confNameInput.value = ''; } else { confNameInput.value = configuration.ConfName || ''; } // 填充其他表单数据 this.shadowRoot.getElementById('osName').value = configuration.OSName || ''; this.shadowRoot.getElementById('osVersion').value = configuration.OSVersion || ''; this.shadowRoot.getElementById('rtxVersion').value = configuration.RTXVersion || ''; this.shadowRoot.getElementById('cpuAffinity').value = configuration.CPUAffinity || ''; this.shadowRoot.getElementById('domainId').value = configuration.DomainID !== undefined ? Math.floor(configuration.DomainID) : ''; this.shadowRoot.getElementById('modelsPath').value = configuration.ModelsPath || ''; this.shadowRoot.getElementById('servicesPath').value = configuration.ServicesPath || ''; this.shadowRoot.getElementById('workPath').value = configuration.WorkPath || ''; // 设置复选框状态 this.shadowRoot.getElementById('consoleDebug').checked = configuration.ConsoleDebug === 1; this.shadowRoot.getElementById('consoleInfo').checked = configuration.ConsoleInfo === 1; this.shadowRoot.getElementById('consoleWarning').checked = configuration.ConsoleWarning === 1; this.shadowRoot.getElementById('consoleError').checked = configuration.ConsoleError === 1; this.shadowRoot.getElementById('logDebug').checked = configuration.LogDebug === 1; this.shadowRoot.getElementById('logInfo').checked = configuration.LogInfo === 1; this.shadowRoot.getElementById('logWarning').checked = configuration.LogWarning === 1; this.shadowRoot.getElementById('logError').checked = configuration.LogError === 1; } /** * @method ensurePathEndsWithSlash * @description 确保路径以斜杠结尾 * @param {string} path - 要处理的路径 * @returns {string} 处理后的路径 */ ensurePathEndsWithSlash(path) { if (!path) return path; return path.endsWith('/') ? path : path + '/'; } /** * @method saveConfiguration * @description 保存构型配置 */ async saveConfiguration() { // 检查权限 if (this.userAccessLevel < 2) { alert('您没有保存构型的权限'); return; } // 验证域ID const domainId = parseInt(this.shadowRoot.getElementById('domainId').value); if (isNaN(domainId) || domainId < 0 || domainId > 232) { alert('域ID必须在0-232之间'); return; } // 验证构型名称 const confName = this.shadowRoot.getElementById('confName').value.trim(); if (!confName) { alert('构型名称不能为空'); return; } const updatedConfig = { ...this.selectedConfiguration, ConfName: confName, OSName: this.shadowRoot.getElementById('osName').value, OSVersion: this.shadowRoot.getElementById('osVersion').value, RTXVersion: this.shadowRoot.getElementById('rtxVersion').value, CPUAffinity: this.shadowRoot.getElementById('cpuAffinity').value, DomainID: domainId, ModelsPath: this.ensurePathEndsWithSlash(this.shadowRoot.getElementById('modelsPath').value), ServicesPath: this.ensurePathEndsWithSlash(this.shadowRoot.getElementById('servicesPath').value), WorkPath: this.ensurePathEndsWithSlash(this.shadowRoot.getElementById('workPath').value), ConsoleDebug: this.shadowRoot.getElementById('consoleDebug').checked ? 1 : 0, ConsoleInfo: this.shadowRoot.getElementById('consoleInfo').checked ? 1 : 0, ConsoleWarning: this.shadowRoot.getElementById('consoleWarning').checked ? 1 : 0, ConsoleError: this.shadowRoot.getElementById('consoleError').checked ? 1 : 0, LogDebug: this.shadowRoot.getElementById('logDebug').checked ? 1 : 0, LogInfo: this.shadowRoot.getElementById('logInfo').checked ? 1 : 0, LogWarning: this.shadowRoot.getElementById('logWarning').checked ? 1 : 0, LogError: this.shadowRoot.getElementById('logError').checked ? 1 : 0 }; // 如果是新建构型,保留源构型ID if (this.isNewConfiguration && this.selectedConfiguration.sourceConfId) { updatedConfig.sourceConfId = this.selectedConfiguration.sourceConfId; } try { const url = this.isNewConfiguration ? '/api/configurations' : `/api/configurations/${this.selectedConfiguration.ConfID}`; const method = this.isNewConfiguration ? 'POST' : 'PUT'; const response = await fetch(url, { method: method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(updatedConfig), credentials: 'include' }); const responseData = await response.json(); if (!response.ok) { if (responseData.error === '路径验证失败') { const errorMessages = responseData.details.map(detail => `${detail.path === 'workPath' ? '工作路径' : detail.path === 'modelsPath' ? '模型路径' : '服务路径'}: ${detail.error}` ).join('\n'); alert(`路径验证失败:\n${errorMessages}`); } else { throw new Error(responseData.error || '保存构型失败'); } return; } this.selectedConfiguration = responseData; this.showConfigurations(this.selectedPlane); } catch (error) { console.error('保存构型失败:', error); alert(error.message || '保存构型失败,请稍后重试'); } } /** * @method showConfigurations * @description 显示指定机型的构型列表 * @param {string} planeName - 机型名称 */ async showConfigurations(planeName) { this.currentView = 'configurations'; this.selectedPlane = planeName; // 更新UI this.shadowRoot.getElementById('pageTitle').textContent = `${planeName} - 构型列表`; this.shadowRoot.getElementById('backSection').style.display = 'block'; this.shadowRoot.querySelector('#backButton span:last-child').textContent = '返回机型列表'; this.shadowRoot.getElementById('contentContainer').classList.add('configurations'); this.shadowRoot.getElementById('contentContainer').style.display = 'grid'; this.shadowRoot.getElementById('editorContainer').style.display = 'none'; // 检查用户权限 await this.checkUserAccessLevel(); // 加载构型数据 this.loadConfigurations(planeName); } /** * @method showPlanes * @description 显示机型列表 */ showPlanes() { this.currentView = 'planes'; this.selectedPlane = null; this.selectedConfiguration = null; // 更新UI this.shadowRoot.getElementById('pageTitle').textContent = '机型'; this.shadowRoot.getElementById('backSection').style.display = 'none'; this.shadowRoot.getElementById('contentContainer').classList.remove('configurations'); this.shadowRoot.getElementById('contentContainer').style.display = 'grid'; this.shadowRoot.getElementById('editorContainer').style.display = 'none'; // 重新加载机型数据 this.loadPlanes(); } /** * @method showError * @description 显示错误信息 * @param {string} message - 错误信息 */ showError(message) { const container = this.shadowRoot.getElementById('contentContainer'); container.innerHTML = `
${message}
`; } } // 注册自定义元素 customElements.define('configuration-config', ConfigurationConfig);