/** * @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(); // 渲染sidebar后,绑定添加模型组按钮事件 const addModelGroupBtn = this.shadowRoot.getElementById('addModelGroupBtn'); if (addModelGroupBtn) { addModelGroupBtn.onclick = () => this.showAddModelGroupDialog(); } } /** * @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'); const newConfName = dialog.querySelector('#newConfName'); dialog.querySelector('#cancelButton').addEventListener('click', () => { document.body.removeChild(dialog); resolve(null); // 取消时返回null }); dialog.querySelector('#confirmButton').addEventListener('click', () => { const selectedValue = select.value; const confName = newConfName.value.trim(); if (!confName) { alert('请输入构型名称'); return; } const selectedConfig = selectedValue === 'none' ? undefined : // 选择"不使用基准构型"时返回undefined configs.find(c => c.ConfID === parseInt(selectedValue)); document.body.removeChild(dialog); resolve({ ...selectedConfig, ConfName: confName }); }); 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 - 是否是新建构型 */ async 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'); 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 = 'flex'; // 填充其他表单数据 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; // 在加载模型卡片右上角增加添加模型组按钮 const modelCard = this.shadowRoot.querySelectorAll('.editor-sidebar .status-card')[0]; const modelCardTitle = modelCard.querySelector('.status-card-title'); if (modelCard && modelCardTitle && this.userAccessLevel >= 2) { // 移除已存在的按钮(如果有) const existingBtn = this.shadowRoot.getElementById('addModelGroupBtn'); if (existingBtn) { existingBtn.remove(); } // 添加新按钮 const addBtn = document.createElement('img'); addBtn.src = '/assets/icons/png/plus_b.png'; addBtn.alt = '添加模型组'; addBtn.title = '添加模型组'; addBtn.id = 'addModelGroupBtn'; addBtn.style.cssText = 'width:20px;height:20px;cursor:pointer;position:absolute;top:18px;right:18px;z-index:2;'; modelCard.style.position = 'relative'; modelCard.appendChild(addBtn); addBtn.addEventListener('click', () => this.showAddModelGroupDialog()); } // 在加载服务卡片右上角增加添加按钮 const serviceCard = this.shadowRoot.querySelectorAll('.editor-sidebar .status-card')[1]; const serviceCardTitle = serviceCard.querySelector('.status-card-title'); if (serviceCard && serviceCardTitle && this.userAccessLevel >= 2) { // 移除已存在的按钮(如果有) const existingBtn = this.shadowRoot.getElementById('addServiceBtn'); if (existingBtn) { existingBtn.remove(); } // 添加新按钮 const addBtn = document.createElement('img'); addBtn.src = '/assets/icons/png/plus_b.png'; addBtn.alt = '添加服务'; addBtn.title = '添加服务'; addBtn.id = 'addServiceBtn'; addBtn.style.cssText = 'width:20px;height:20px;cursor:pointer;position:absolute;top:18px;right:18px;z-index:2;'; serviceCard.style.position = 'relative'; serviceCard.appendChild(addBtn); addBtn.addEventListener('click', () => this.showAddServiceDialog()); } // 如果不是新建构型,获取模型组数据和服务列表 if (!isNew && configuration.ConfID) { try { // 并行请求模型组数据和服务列表 const [modelGroupsResponse, servicesResponse] = await Promise.all([ fetch(`/api/configurations/${configuration.ConfID}/model-groups`), fetch(`/api/configurations/${configuration.ConfID}/services`) ]); if (!modelGroupsResponse.ok) { throw new Error('获取模型组数据失败'); } const modelGroups = await modelGroupsResponse.json(); // 更新加载模型卡片 const pendingModelsList = this.shadowRoot.getElementById('pendingModelsList'); if (modelGroups && modelGroups.length > 0) { // 获取每个模型组下的模型 const modelGroupsWithModels = await Promise.all(modelGroups.map(async (group) => { try { const modelsResponse = await fetch(`/api/model-groups/${group.GroupID}/models`); if (!modelsResponse.ok) { throw new Error(`获取模型组 ${group.GroupName} 的模型失败`); } const models = await modelsResponse.json(); return { ...group, models }; } catch (error) { console.error(`获取模型组 ${group.GroupName} 的模型失败:`, error); return { ...group, models: [] }; } })); pendingModelsList.innerHTML = modelGroupsWithModels.map(group => `
${group.GroupName} ${this.userAccessLevel >= 2 ? ` 添加模型 编辑 删除 ` : ''}
频率:${group.Freq || 0} Hz / 优先级:${group.Priority || 0} / 亲和性:${group.CPUAff || '无'}
${group.models && group.models.length > 0 ? group.models.map(model => `
${model.ModelName || '未知模型'} ${model.ModelVersion || '未知版本'}
${this.userAccessLevel >= 2 ? ` 删除 ` : ''}
`).join('') : '
暂无模型
' }
`).join(''); // 绑定模型组按钮事件 if (this.userAccessLevel >= 2) { // 添加模型按钮 this.shadowRoot.querySelectorAll('.group-add-btn').forEach(btn => { btn.addEventListener('click', (e) => { const groupId = btn.getAttribute('data-group-id'); this.onAddModel && this.onAddModel(groupId); }); }); // 编辑模型组按钮 this.shadowRoot.querySelectorAll('.group-edit-btn').forEach(btn => { btn.addEventListener('click', (e) => { const groupId = btn.getAttribute('data-group-id'); const group = modelGroupsWithModels.find(g => String(g.GroupID) === String(groupId)); if (group) this.showEditGroupDialog(group); }); }); // 删除模型组按钮 this.shadowRoot.querySelectorAll('.group-delete-btn').forEach(btn => { btn.addEventListener('click', async (e) => { const groupId = btn.getAttribute('data-group-id'); if (!groupId) return; if (!confirm('确定要删除该模型组吗?')) return; try { const resp = await fetch(`/api/model-groups/${groupId}`, { method: 'DELETE', credentials: 'include' }); if (!resp.ok) { const data = await resp.json(); throw new Error(data.error || '删除失败'); } this.showEditor(this.selectedConfiguration, this.selectedPlane, false); } catch (err) { alert('删除失败:' + err.message); } }); }); // 删除模型按钮 this.shadowRoot.querySelectorAll('.model-delete-btn').forEach(btn => { btn.addEventListener('click', async (e) => { e.stopPropagation(); const groupId = btn.getAttribute('data-group-id'); const className = btn.getAttribute('data-class-name'); if (!groupId || !className) return; if (!confirm('确定要删除该模型吗?')) return; try { const resp = await fetch(`/api/model-groups/${groupId}/models/${encodeURIComponent(className)}`, { method: 'DELETE', credentials: 'include' }); if (!resp.ok) { const data = await resp.json(); throw new Error(data.error || '删除失败'); } this.showEditor(this.selectedConfiguration, this.selectedPlane, false); } catch (err) { alert('删除失败:' + err.message); } }); }); } } else { pendingModelsList.innerHTML = '
暂无待加载模型
'; } // 更新服务列表 const pendingServicesList = this.shadowRoot.getElementById('pendingServicesList'); if (!servicesResponse.ok) { throw new Error('获取服务列表失败'); } const services = await servicesResponse.json(); if (services && services.length > 0) { pendingServicesList.innerHTML = services.map(service => `
${service.ServiceName || service.ClassName || '未知服务'} ${service.ServiceVersion || '未知'}
${this.userAccessLevel >= 2 ? ` 删除 ` : ''}
`).join(''); // 绑定服务删除按钮事件 if (this.userAccessLevel >= 2) { this.shadowRoot.querySelectorAll('.service-delete-btn').forEach(btn => { btn.addEventListener('click', async (e) => { e.stopPropagation(); const serviceName = btn.getAttribute('data-service-name'); if (!serviceName) return; if (!confirm('确定要删除该服务吗?')) return; try { const resp = await fetch(`/api/configurations/${configuration.ConfID}/services/${encodeURIComponent(serviceName)}`, { method: 'DELETE', credentials: 'include' }); if (!resp.ok) { const data = await resp.json(); throw new Error(data.error || '删除失败'); } this.showEditor(this.selectedConfiguration, this.selectedPlane, false); } catch (err) { alert('删除失败:' + err.message); } }); }); } } else { pendingServicesList.innerHTML = '
暂无待加载服务
'; } } catch (error) { console.error('获取数据失败:', error); const pendingModelsList = this.shadowRoot.getElementById('pendingModelsList'); const pendingServicesList = this.shadowRoot.getElementById('pendingServicesList'); pendingModelsList.innerHTML = '
获取模型组数据失败
'; pendingServicesList.innerHTML = '
获取服务列表失败
'; } } // 控制右侧卡片显示:新建构型时隐藏 const editorSidebar = this.shadowRoot.querySelector('.editor-sidebar'); if (isNew) { editorSidebar.style.display = 'none'; } else { editorSidebar.style.display = 'flex'; } } /** * @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.selectedConfiguration.ConfName || ''; 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}
`; } /** * @method onAddModel * @description 添加模型功能,弹窗选择ATA章节、模型、版本,确认后添加 * @param {string} groupId - 模型组ID */ async onAddModel(groupId) { const planeName = this.selectedPlane; const confID = this.selectedConfiguration.ConfID; if (!planeName || !confID) { alert('缺少机型或构型信息'); return; } // 创建弹窗 const dialog = document.createElement('div'); dialog.className = 'add-model-dialog'; dialog.innerHTML = `
添加模型
`; document.body.appendChild(dialog); // 关闭弹窗 dialog.querySelector('#cancelAddModel').onclick = () => document.body.removeChild(dialog); // 获取ATA章节 const ataSelect = dialog.querySelector('#ataSelect'); const modelSelect = dialog.querySelector('#modelSelect'); const versionSelect = dialog.querySelector('#versionSelect'); let ataList = [], modelList = [], versionList = []; try { const ataResp = await fetch('/api/ata-chapters'); ataList = await ataResp.json(); ataSelect.innerHTML = '' + ataList.map(a => ``).join(''); } catch { ataSelect.innerHTML = ''; } // 章节选择事件 ataSelect.onchange = async () => { const chapterId = ataSelect.value; modelSelect.disabled = true; versionSelect.disabled = true; modelSelect.innerHTML = ''; versionSelect.innerHTML = ''; if (!chapterId) { modelSelect.innerHTML = ''; return; } try { const modelResp = await fetch(`/api/chapter-models/${chapterId}?planeName=${encodeURIComponent(planeName)}`); modelList = await modelResp.json(); modelSelect.innerHTML = '' + modelList.map(m => ``).join(''); modelSelect.disabled = false; } catch { modelSelect.innerHTML = ''; } }; // 模型选择事件 modelSelect.onchange = async () => { const className = modelSelect.value; versionSelect.disabled = true; versionSelect.innerHTML = ''; if (!className) { versionSelect.innerHTML = ''; return; } try { const versionResp = await fetch(`/api/model-versions/${className}?planeName=${encodeURIComponent(planeName)}&confID=${encodeURIComponent(confID)}`); versionList = await versionResp.json(); versionSelect.innerHTML = '' + versionList.map(v => ``).join(''); versionSelect.disabled = false; } catch { versionSelect.innerHTML = ''; } }; // 确认添加 dialog.querySelector('#confirmAddModel').onclick = async () => { const chapterId = ataSelect.value; const className = modelSelect.value; const version = versionSelect.value; if (!chapterId || !className || !version) { alert('请选择完整信息'); return; } // 获取选中模型的详细信息 const model = modelList.find(m => m.ClassName === className); if (!model) { alert('模型信息异常'); return; } // 组装要添加的数据 const postData = { GroupID: groupId, ClassName: className, ModelName: model.ModelName, ModelName_CN: model.ModelName_CN, ModelVersion: version }; try { const resp = await fetch(`/api/model-groups/${groupId}/models`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify(postData) }); if (!resp.ok) { const data = await resp.json(); throw new Error(data.error || '添加失败'); } document.body.removeChild(dialog); this.showEditor(this.selectedConfiguration, this.selectedPlane, false); } catch (err) { alert('添加失败:' + err.message); } }; } /** * @method showEditGroupDialog * @description 显示模型组编辑对话框,编辑频率、优先级、亲和性 * @param {Object} group - 模型组对象 */ showEditGroupDialog(group) { const dialog = document.createElement('div'); dialog.className = 'edit-group-dialog'; dialog.innerHTML = `
编辑模型组参数
`; document.body.appendChild(dialog); dialog.querySelector('#cancelEditGroup').onclick = () => document.body.removeChild(dialog); dialog.querySelector('#confirmEditGroup').onclick = async () => { const freq = parseInt(dialog.querySelector('#editFreq').value) || 0; const priority = parseInt(dialog.querySelector('#editPriority').value) || 0; const cpuAff = dialog.querySelector('#editCPUAff').value.trim(); try { const resp = await fetch(`/api/model-groups/${group.GroupID}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ ...group, Freq: freq, Priority: priority, CPUAff: cpuAff }) }); if (!resp.ok) { const data = await resp.json(); throw new Error(data.error || '保存失败'); } document.body.removeChild(dialog); this.showEditor(this.selectedConfiguration, this.selectedPlane, false); } catch (err) { alert('保存失败:' + err.message); } }; } /** * @method showAddModelGroupDialog * @description 显示添加模型组对话框 */ showAddModelGroupDialog() { const cpuAffinityStr = this.shadowRoot.getElementById('cpuAffinity').value || ''; const cpuOptions = cpuAffinityStr.split(',').map(s => s.trim()).filter(s => s !== '' && !isNaN(Number(s))); const dialog = document.createElement('div'); dialog.className = 'add-model-group-dialog'; dialog.innerHTML = `
添加模型组
`; document.body.appendChild(dialog); // 亲和性多选下拉逻辑 const cpuAffInput = dialog.querySelector('#cpuAffInput'); const cpuAffDropdown = dialog.querySelector('#cpuAffDropdown'); cpuAffInput.addEventListener('click', () => { cpuAffDropdown.style.display = cpuAffDropdown.style.display === 'block' ? 'none' : 'block'; }); document.addEventListener('mousedown', function handler(e) { if (!dialog.contains(e.target)) { cpuAffDropdown.style.display = 'none'; document.removeEventListener('mousedown', handler); } }); cpuAffDropdown.querySelectorAll('input[type="checkbox"]').forEach(checkbox => { checkbox.addEventListener('change', () => { const selected = Array.from(cpuAffDropdown.querySelectorAll('input[type="checkbox"]:checked')).map(cb => cb.value); cpuAffInput.value = selected.join(','); }); }); dialog.querySelector('#cancelAddModelGroup').onclick = () => document.body.removeChild(dialog); dialog.querySelector('#confirmAddModelGroup').onclick = async () => { const name = dialog.querySelector('#newModelGroupName').value.trim(); const freq = parseFloat(dialog.querySelector('#freqInput').value); const priority = parseInt(dialog.querySelector('#priorityInput').value); const cpuAffSel = cpuAffInput.value; if (!name) { alert('请输入模型组名称'); return; } if (isNaN(freq) || freq <= 0 || freq > 1000) { alert('频率必须为0~1000之间的正浮点数'); return; } if (isNaN(priority) || priority < 1 || priority > 99) { alert('优先级必须为1-99之间的整数'); return; } if (!cpuAffSel) { alert('请选择亲和性'); return; } // 组装数据 const postData = { ConfID: this.selectedConfiguration.ConfID, GroupName: name, Freq: freq, Priority: priority, CPUAff: cpuAffSel }; try { const resp = await fetch(`/api/configurations/${this.selectedConfiguration.ConfID}/model-groups`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify(postData) }); if (!resp.ok) { const data = await resp.json(); throw new Error(data.error || '添加失败'); } document.body.removeChild(dialog); this.showEditor(this.selectedConfiguration, this.selectedPlane, false); } catch (err) { alert('添加失败:' + err.message); } }; } /** * @method showAddServiceDialog * @description 显示添加服务对话框 */ async showAddServiceDialog() { const dialog = document.createElement('div'); dialog.className = 'add-service-dialog'; dialog.innerHTML = `
添加服务
`; document.body.appendChild(dialog); // 获取服务列表 const serviceSelect = dialog.querySelector('#serviceSelect'); const versionSelect = dialog.querySelector('#versionSelect'); let serviceList = []; try { const response = await fetch('/api/services'); if (!response.ok) throw new Error('获取服务列表失败'); serviceList = await response.json(); serviceSelect.innerHTML = '' + serviceList.map(service => ``).join(''); } catch (error) { console.error('获取服务列表失败:', error); serviceSelect.innerHTML = ''; } // 服务选择事件 serviceSelect.onchange = async () => { const className = serviceSelect.value; versionSelect.disabled = true; versionSelect.innerHTML = ''; if (!className) { versionSelect.innerHTML = ''; return; } try { const response = await fetch(`/api/service-versions/${className}`); if (!response.ok) throw new Error('获取版本列表失败'); const versions = await response.json(); versionSelect.innerHTML = '' + versions.map(version => ``).join(''); versionSelect.disabled = false; } catch (error) { console.error('获取版本列表失败:', error); versionSelect.innerHTML = ''; } }; // 取消按钮事件 dialog.querySelector('#cancelAddService').onclick = () => { document.body.removeChild(dialog); }; // 确认按钮事件 dialog.querySelector('#confirmAddService').onclick = async () => { const className = serviceSelect.value; const version = versionSelect.value; if (!className || !version) { alert('请选择完整的服务信息'); return; } // 查找ServiceName const selectedService = serviceList.find(s => s.ClassName === className); const serviceName = selectedService ? (selectedService.ServiceName || selectedService.ServiceName_CN || className) : className; try { const response = await fetch(`/api/configurations/${this.selectedConfiguration.ConfID}/services`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ ClassName: className, ServiceVersion: version, ServiceName: serviceName }) }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || '添加服务失败'); } document.body.removeChild(dialog); this.showEditor(this.selectedConfiguration, this.selectedPlane, false); } catch (error) { console.error('添加服务失败:', error); alert('添加服务失败:' + error.message); } }; } } // 注册自定义元素 customElements.define('configuration-config', ConfigurationConfig);