/** * 环境配置模块 * @type {module} */ import { createModal, markEdited } from './utils.js'; /** * 渲染环境部分 * @param {HTMLElement} component - 组件实例 * @param {HTMLElement} container - 容器元素 * @param {Element} rootElement - XML根元素 */ export function renderEnvironmentSection(component, container, rootElement) { const envElement = rootElement.querySelector('Environment'); if (!envElement) { return; // 如果找不到Environment元素,直接返回 } const section = document.createElement('div'); section.className = 'editor-section'; const title = document.createElement('div'); title.className = 'section-title'; title.textContent = '环境配置'; section.appendChild(title); const propertyGroup = document.createElement('div'); propertyGroup.className = 'property-group'; // 获取并显示所有Environment属性 Array.from(envElement.attributes).forEach(attr => { const propertyItem = document.createElement('div'); propertyItem.className = 'property-item'; const label = document.createElement('label'); label.className = 'property-label'; label.textContent = attr.name; // 对CPUAffinity属性使用特殊处理 if (attr.name === 'CPUAffinity') { const inputContainer = document.createElement('div'); inputContainer.style.display = 'flex'; inputContainer.style.position = 'relative'; const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.style.flexGrow = '1'; input.title = 'CPU亲和性'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); const dropdownButton = document.createElement('button'); dropdownButton.className = 'dropdown-button'; dropdownButton.type = 'button'; // 确保按钮类型为button dropdownButton.innerHTML = '▼'; dropdownButton.style.width = '30px'; dropdownButton.style.border = '1px solid #ddd'; dropdownButton.style.borderLeft = 'none'; dropdownButton.style.borderRadius = '0 4px 4px 0'; dropdownButton.style.backgroundColor = '#f5f5f5'; dropdownButton.style.cursor = 'pointer'; // 创建下拉框容器 const dropdown = document.createElement('div'); dropdown.className = 'cpu-dropdown'; dropdown.style.position = 'absolute'; dropdown.style.top = '100%'; dropdown.style.left = '0'; dropdown.style.right = '0'; dropdown.style.backgroundColor = 'white'; dropdown.style.border = '1px solid #ddd'; dropdown.style.borderRadius = '4px'; dropdown.style.boxShadow = '0 2px 10px rgba(0,0,0,0.1)'; dropdown.style.zIndex = '50'; // 提高z-index确保在最上层 dropdown.style.padding = '10px'; dropdown.style.display = 'none'; // 生成CPU核心选项 const cpuCount = 16; // 假设最多16个核心 const selectedCores = attr.value.split(',').map(core => parseInt(core.trim())).filter(core => !isNaN(core)); for (let i = 0; i < cpuCount; i++) { const checkboxContainer = document.createElement('div'); checkboxContainer.style.marginBottom = '6px'; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = `cpu-${i}`; checkbox.value = i; checkbox.checked = selectedCores.includes(i); checkbox.style.marginRight = '6px'; const checkboxLabel = document.createElement('label'); checkboxLabel.htmlFor = `cpu-${i}`; checkboxLabel.textContent = `CPU ${i}`; checkbox.addEventListener('change', () => { // 获取所有选中的核心 const checkedCores = Array.from(dropdown.querySelectorAll('input[type="checkbox"]:checked')) .map(cb => cb.value) .sort((a, b) => a - b); // 更新输入框的值 input.value = checkedCores.join(','); input.dispatchEvent(new Event('change')); }); checkboxContainer.appendChild(checkbox); checkboxContainer.appendChild(checkboxLabel); dropdown.appendChild(checkboxContainer); } // 添加应用和取消按钮 const buttonContainer = document.createElement('div'); buttonContainer.style.display = 'flex'; buttonContainer.style.justifyContent = 'flex-end'; buttonContainer.style.marginTop = '10px'; buttonContainer.style.gap = '8px'; const closeButton = document.createElement('button'); closeButton.textContent = '关闭'; closeButton.style.padding = '6px 12px'; closeButton.style.backgroundColor = '#f0f0f0'; closeButton.style.border = '1px solid #ddd'; closeButton.style.borderRadius = '4px'; closeButton.style.cursor = 'pointer'; closeButton.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); dropdown.style.display = 'none'; }); buttonContainer.appendChild(closeButton); dropdown.appendChild(buttonContainer); // 使用更可靠的方法显示下拉菜单 const toggleDropdown = (e) => { e.preventDefault(); e.stopPropagation(); if (dropdown.style.display === 'none' || !dropdown.style.display) { dropdown.style.display = 'block'; // 添加全局一次性点击事件,用于关闭下拉框 setTimeout(() => { const closeDropdown = (event) => { if (!dropdown.contains(event.target) && event.target !== dropdownButton) { dropdown.style.display = 'none'; document.removeEventListener('click', closeDropdown); } }; document.addEventListener('click', closeDropdown); }, 0); } else { dropdown.style.display = 'none'; } }; // 点击下拉按钮时显示或隐藏下拉框 dropdownButton.addEventListener('click', toggleDropdown); inputContainer.appendChild(input); inputContainer.appendChild(dropdownButton); inputContainer.appendChild(dropdown); propertyItem.appendChild(label); propertyItem.appendChild(inputContainer); } else if (attr.name === 'BaseFrequency') { // 对数字类型的属性使用number类型输入框 const input = document.createElement('input'); input.className = 'property-input'; input.type = 'number'; input.min = '0'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.title = '仿真运行基础频率,单位Hz'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else if (attr.name === 'OSName') { const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.title = '操作系统名称'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else if (attr.name === 'Version') { const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.title = '操作系统版本'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else if (attr.name === 'RTXVersion') { const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.title = '实时内核版本'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else if (attr.name === 'WorkPath') { const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.title = '仿真工作路径,XNCore环境变量所在路径'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else if (attr.name === 'ModelsPath') { const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.title = '模型相对路径,相对于仿真工作路径'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else if (attr.name === 'ServicesPath') { const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.title = '服务相对路径,相对于仿真工作路径'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else if (attr.name === 'DomainID') { // 对数字类型的属性使用number类型输入框 const input = document.createElement('input'); input.className = 'property-input'; input.type = 'number'; input.min = '0'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.title = 'DDS通信域ID'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else { const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `Environment@${attr.name}`; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } propertyGroup.appendChild(propertyItem); }); section.appendChild(propertyGroup); // 添加"添加新属性"按钮 const addButton = document.createElement('button'); addButton.className = 'add-button'; addButton.textContent = '添加新属性'; addButton.title = '添加新的运行环境属性'; addButton.addEventListener('click', () => showAddPropertyDialog(component, 'Environment')); section.appendChild(addButton); container.appendChild(section); } /** * 添加新属性对话框 * @param {HTMLElement} component - 组件实例 * @param {string} elementName - 元素名称 */ export function showAddPropertyDialog(component, elementName) { // 创建表单内容 const formContent = document.createElement('div'); formContent.className = 'modal-form'; // 属性名输入 const nameRow = document.createElement('div'); nameRow.className = 'form-row'; const nameLabel = document.createElement('label'); nameLabel.className = 'form-label'; nameLabel.textContent = '属性名称'; const nameInput = document.createElement('input'); nameInput.className = 'form-input'; nameInput.type = 'text'; nameInput.placeholder = '请输入属性名称'; nameRow.appendChild(nameLabel); nameRow.appendChild(nameInput); formContent.appendChild(nameRow); // 属性值输入 const valueRow = document.createElement('div'); valueRow.className = 'form-row'; const valueLabel = document.createElement('label'); valueLabel.className = 'form-label'; valueLabel.textContent = '属性值'; const valueInput = document.createElement('input'); valueInput.className = 'form-input'; valueInput.type = 'text'; valueInput.placeholder = '请输入属性值'; valueRow.appendChild(valueLabel); valueRow.appendChild(valueInput); formContent.appendChild(valueRow); // 显示对话框 createModal(component.shadowRoot, '添加新属性', formContent, () => { const propertyName = nameInput.value.trim(); const propertyValue = valueInput.value; if (propertyName) { addNewProperty(component, elementName, propertyName, propertyValue); } }); } /** * 添加新属性 * @param {HTMLElement} component - 组件实例 * @param {string} elementName - 元素名称 * @param {string} propertyName - 属性名 * @param {string} propertyValue - 属性值 */ export function addNewProperty(component, elementName, propertyName, propertyValue) { // 更新UI const section = Array.from(component.shadowRoot.querySelectorAll('.section-title')).find(el => { if (elementName === 'Environment' && el.textContent === '环境配置') return true; return false; })?.parentElement; if (section) { const propertyGroup = section.querySelector('.property-group'); if (propertyGroup) { const propertyItem = document.createElement('div'); propertyItem.className = 'property-item'; const label = document.createElement('label'); label.className = 'property-label'; label.textContent = propertyName; const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = propertyValue; input.dataset.path = `${elementName}@${propertyName}`; input.dataset.isNew = 'true'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); propertyGroup.appendChild(propertyItem); component.isEdited = markEdited(component.shadowRoot, component.isEdited); // 静默更新XML if (component.updateXmlFromVisualEditor) { component.updateXmlFromVisualEditor(true); } } } } /** * 获取CPU亲和性设置 * @param {Document} xmlDoc - XML文档 * @returns {number[]} 可用的CPU核心列表 */ export function getCPUAffinityOptions(xmlDoc) { // 从环境配置中获取CPUAffinity的值 const envElement = xmlDoc.querySelector('Environment'); if (!envElement) return []; const cpuAffinity = envElement.getAttribute('CPUAffinity') || '0'; const availableCores = cpuAffinity.split(',').map(core => parseInt(core.trim())).filter(core => !isNaN(core)); return availableCores; }