/** * 模型组模块 */ import { createModal, markEdited } from './utils.js'; import { getCPUAffinityOptions } from './environment-section.js'; /** * 渲染模型组部分 * @param {HTMLElement} component - 组件实例 * @param {HTMLElement} container - 容器元素 * @param {Element} rootElement - XML根元素 */ export function renderModelGroupsSection(component, container, rootElement) { const section = document.createElement('div'); section.className = 'editor-section'; const title = document.createElement('div'); title.className = 'section-title'; title.textContent = '模型组配置'; section.appendChild(title); // 获取所有ModelGroup元素 const modelGroups = rootElement.querySelectorAll('ModelGroup'); if (modelGroups.length === 0) { const emptyMsg = document.createElement('div'); emptyMsg.textContent = '没有找到模型组配置'; emptyMsg.style.color = '#888'; emptyMsg.style.fontStyle = 'italic'; emptyMsg.style.marginBottom = '16px'; section.appendChild(emptyMsg); } else { // 为每个ModelGroup创建一个列表项 modelGroups.forEach((modelGroup, index) => { const groupItem = document.createElement('div'); groupItem.className = 'list-item'; groupItem.dataset.index = index; // 创建组标题和操作按钮 const header = document.createElement('div'); header.className = 'list-item-header'; const groupTitle = document.createElement('div'); groupTitle.className = 'list-item-title'; groupTitle.textContent = modelGroup.getAttribute('Name') || `模型组 ${index + 1}`; const actions = document.createElement('div'); actions.className = 'list-item-actions'; const deleteButton = document.createElement('button'); deleteButton.className = 'action-icon'; deleteButton.title = '删除模型组'; deleteButton.style.border = 'none'; deleteButton.style.background = 'none'; deleteButton.style.cursor = 'pointer'; deleteButton.style.padding = '4px'; deleteButton.style.display = 'flex'; deleteButton.style.alignItems = 'center'; deleteButton.style.justifyContent = 'center'; const deleteImg = document.createElement('img'); deleteImg.src = 'assets/icons/png/delete_b.png'; deleteImg.alt = '删除'; deleteImg.style.width = '16px'; deleteImg.style.height = '16px'; deleteButton.appendChild(deleteImg); deleteButton.addEventListener('click', () => deleteModelGroup(component, index)); actions.appendChild(deleteButton); header.appendChild(groupTitle); header.appendChild(actions); groupItem.appendChild(header); // 显示模型组属性 const propertiesContainer = document.createElement('div'); propertiesContainer.className = 'property-group'; propertiesContainer.style.marginTop = '12px'; // 获取可用的CPU核心选项 const availableCores = getCPUAffinityOptions(component.xmlDoc); Array.from(modelGroup.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; // 根据属性名使用不同的输入控件 if (attr.name === 'FreqGroup') { // FreqGroup使用限制范围的数字输入框 const input = document.createElement('input'); input.className = 'property-input'; input.type = 'number'; input.min = '0'; input.max = '6'; input.value = attr.value; input.dataset.path = `ModelGroup[${index}]@${attr.name}`; input.title = '频率组,取值范围0-6'; input.addEventListener('change', () => { // 确保值在有效范围内 if (parseInt(input.value) > 6) { input.value = '6'; } component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else if (attr.name === 'Priority') { // Priority使用限制范围的数字输入框 const input = document.createElement('input'); input.className = 'property-input'; input.type = 'number'; input.min = '0'; input.max = '99'; input.value = attr.value; input.dataset.path = `ModelGroup[${index}]@${attr.name}`; input.title = '线程优先级,取值范围0-99'; input.addEventListener('change', () => { // 确保值在有效范围内 if (parseInt(input.value) > 99) { input.value = '99'; } component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } else if (attr.name === 'CPUAff') { // CPUAff使用下拉框 const select = document.createElement('select'); select.className = 'property-input'; select.dataset.path = `ModelGroup[${index}]@${attr.name}`; select.title = '选择一个可用的亲和CPU核心'; // 添加可用的CPU核心选项 availableCores.forEach(core => { const option = document.createElement('option'); option.value = core; option.textContent = `CPU ${core}`; // 如果当前值匹配,设为选中 if (parseInt(attr.value) === core) { option.selected = true; } select.appendChild(option); }); // 如果没有可用选项,添加一个默认选项 if (availableCores.length === 0) { const option = document.createElement('option'); option.value = attr.value; option.textContent = `CPU ${attr.value}`; option.selected = true; select.appendChild(option); } select.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(select); } else if (attr.name === 'Name') { // 模型组名称 const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `ModelGroup[${index}]@${attr.name}`; input.title = '模型组名称'; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); groupTitle.textContent = input.value || `模型组 ${index + 1}`; }); 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 = `ModelGroup[${index}]@${attr.name}`; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); } propertiesContainer.appendChild(propertyItem); }); groupItem.appendChild(propertiesContainer); // 显示模型列表 const modelsTitle = document.createElement('div'); modelsTitle.textContent = '模型列表'; modelsTitle.style.fontWeight = 'bold'; modelsTitle.style.margin = '16px 0 12px'; groupItem.appendChild(modelsTitle); const models = modelGroup.querySelectorAll('Model'); const modelsContainer = document.createElement('div'); modelsContainer.style.marginLeft = '16px'; if (models.length === 0) { const emptyModelMsg = document.createElement('div'); emptyModelMsg.textContent = '没有找到模型'; emptyModelMsg.style.color = '#888'; emptyModelMsg.style.fontStyle = 'italic'; emptyModelMsg.style.marginBottom = '12px'; modelsContainer.appendChild(emptyModelMsg); } else { models.forEach((model, modelIndex) => { renderModelItem(component, modelsContainer, model, modelIndex, index); }); } groupItem.appendChild(modelsContainer); // 添加模型按钮 const addModelButton = document.createElement('button'); addModelButton.className = 'add-button'; addModelButton.style.marginTop = '12px'; addModelButton.textContent = '添加模型'; addModelButton.title = '添加新模型到当前模型组'; addModelButton.addEventListener('click', () => showAddModelDialog(component, index)); groupItem.appendChild(addModelButton); section.appendChild(groupItem); }); } // 添加新模型组按钮 const addButton = document.createElement('button'); addButton.className = 'add-button'; addButton.style.marginTop = '16px'; addButton.textContent = '添加模型组'; addButton.title = '添加新的模型组'; addButton.addEventListener('click', () => showAddModelGroupDialog(component)); section.appendChild(addButton); container.appendChild(section); } /** * 渲染模型项 * @param {HTMLElement} component - 组件实例 * @param {HTMLElement} container - 容器元素 * @param {Element} model - 模型XML元素 * @param {number} modelIndex - 模型索引 * @param {number} groupIndex - 模型组索引 */ function renderModelItem(component, container, model, modelIndex, groupIndex) { const modelItem = document.createElement('div'); modelItem.className = 'list-item'; modelItem.style.marginBottom = '12px'; const modelHeader = document.createElement('div'); modelHeader.className = 'list-item-header'; const modelTitle = document.createElement('div'); modelTitle.className = 'list-item-title'; modelTitle.textContent = model.getAttribute('Name') || `模型 ${modelIndex + 1}`; const modelActions = document.createElement('div'); modelActions.className = 'list-item-actions'; const deleteModelButton = document.createElement('button'); deleteModelButton.className = 'action-icon'; deleteModelButton.title = '删除模型'; deleteModelButton.style.border = 'none'; deleteModelButton.style.background = 'none'; deleteModelButton.style.cursor = 'pointer'; deleteModelButton.style.padding = '4px'; deleteModelButton.style.display = 'flex'; deleteModelButton.style.alignItems = 'center'; deleteModelButton.style.justifyContent = 'center'; const deleteModelImg = document.createElement('img'); deleteModelImg.src = 'assets/icons/png/delete_b.png'; deleteModelImg.alt = '删除'; deleteModelImg.style.width = '16px'; deleteModelImg.style.height = '16px'; deleteModelButton.appendChild(deleteModelImg); deleteModelButton.addEventListener('click', () => deleteModel(component, groupIndex, modelIndex)); modelActions.appendChild(deleteModelButton); modelHeader.appendChild(modelTitle); modelHeader.appendChild(modelActions); modelItem.appendChild(modelHeader); // 显示模型属性 const modelProperties = document.createElement('div'); modelProperties.className = 'property-group'; modelProperties.style.marginTop = '12px'; Array.from(model.attributes).forEach(attr => { if (attr.name === 'Name') { // 如果是Name属性,我们需要查看是否有ClassName属性 const classNameAttr = model.getAttribute('ClassName'); // 创建一个行容器,直接放在标题下方 const rowContainer = document.createElement('div'); rowContainer.style.display = 'flex'; rowContainer.style.width = '100%'; rowContainer.style.gap = '10px'; rowContainer.style.marginTop = '8px'; rowContainer.style.marginBottom = '8px'; // 名称标签和输入框组 const nameGroup = document.createElement('div'); nameGroup.style.display = 'flex'; nameGroup.style.alignItems = 'center'; nameGroup.style.flex = '1'; const nameLabel = document.createElement('label'); nameLabel.className = 'property-label'; nameLabel.textContent = 'Name'; nameLabel.style.marginRight = '5px'; nameLabel.style.minWidth = '60px'; const nameInput = document.createElement('input'); nameInput.className = 'property-input'; nameInput.type = 'text'; nameInput.value = attr.value; nameInput.dataset.path = `ModelGroup[${groupIndex}]/Model[${modelIndex}]@${attr.name}`; nameInput.title = '模型名称'; nameInput.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); modelTitle.textContent = nameInput.value || `模型 ${modelIndex + 1}`; }); nameGroup.appendChild(nameLabel); nameGroup.appendChild(nameInput); // 类名标签和输入框组 const classGroup = document.createElement('div'); classGroup.style.display = 'flex'; classGroup.style.alignItems = 'center'; classGroup.style.flex = '1'; const classLabel = document.createElement('label'); classLabel.className = 'property-label'; classLabel.textContent = 'ClassName'; classLabel.style.marginRight = '5px'; classLabel.style.minWidth = '80px'; const classInput = document.createElement('input'); classInput.className = 'property-input'; classInput.type = 'text'; classInput.value = classNameAttr || ''; classInput.dataset.path = `ModelGroup[${groupIndex}]/Model[${modelIndex}]@ClassName`; classInput.title = '模型C++类名'; classInput.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); classGroup.appendChild(classLabel); classGroup.appendChild(classInput); // 将名称组和类名组添加到行容器 rowContainer.appendChild(nameGroup); rowContainer.appendChild(classGroup); // 直接添加到modelItem,而不是添加到modelProperties modelItem.appendChild(rowContainer); // 将ClassName标记为已处理,后面不需要再处理 model.setAttribute('ClassName_processed', 'true'); } else if (attr.name === 'ClassName') { // 如果是ClassName且已处理,则跳过 if (model.getAttribute('ClassName_processed') === 'true') { return; } // 如果Name还没被处理,我们需要创建完整的行 const nameAttr = model.getAttribute('Name'); // 创建一个行容器 const rowContainer = document.createElement('div'); rowContainer.style.display = 'flex'; rowContainer.style.width = '100%'; rowContainer.style.gap = '10px'; rowContainer.style.marginTop = '8px'; rowContainer.style.marginBottom = '8px'; // 名称标签和输入框组 const nameGroup = document.createElement('div'); nameGroup.style.display = 'flex'; nameGroup.style.alignItems = 'center'; nameGroup.style.flex = '1'; const nameLabel = document.createElement('label'); nameLabel.className = 'property-label'; nameLabel.textContent = 'Name'; nameLabel.style.marginRight = '5px'; nameLabel.style.minWidth = '60px'; const nameInput = document.createElement('input'); nameInput.className = 'property-input'; nameInput.type = 'text'; nameInput.value = nameAttr || ''; nameInput.dataset.path = `ModelGroup[${groupIndex}]/Model[${modelIndex}]@Name`; nameInput.title = '模型名称'; nameInput.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); modelTitle.textContent = nameInput.value || `模型 ${modelIndex + 1}`; }); nameGroup.appendChild(nameLabel); nameGroup.appendChild(nameInput); // 类名标签和输入框组 const classGroup = document.createElement('div'); classGroup.style.display = 'flex'; classGroup.style.alignItems = 'center'; classGroup.style.flex = '1'; const classLabel = document.createElement('label'); classLabel.className = 'property-label'; classLabel.textContent = 'ClassName'; classLabel.style.marginRight = '5px'; classLabel.style.minWidth = '80px'; const classInput = document.createElement('input'); classInput.className = 'property-input'; classInput.type = 'text'; classInput.value = attr.value; classInput.dataset.path = `ModelGroup[${groupIndex}]/Model[${modelIndex}]@ClassName`; classInput.title = '模型C++类名'; classInput.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); classGroup.appendChild(classLabel); classGroup.appendChild(classInput); // 将名称组和类名组添加到行容器 rowContainer.appendChild(nameGroup); rowContainer.appendChild(classGroup); // 直接添加到modelItem,而不是添加到modelProperties modelItem.appendChild(rowContainer); // 将Name标记为已处理 model.setAttribute('Name_processed', 'true'); } else { // 其他属性加入属性组 const propertyItem = document.createElement('div'); propertyItem.className = 'property-item'; const label = document.createElement('label'); label.className = 'property-label'; label.textContent = attr.name; const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `ModelGroup[${groupIndex}]/Model[${modelIndex}]@${attr.name}`; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); modelProperties.appendChild(propertyItem); } }); // 只有当有其他属性时才添加属性组 if (modelProperties.children.length > 0) { // 添加一个标题来分隔基本属性和其他属性 const otherPropsTitle = document.createElement('div'); otherPropsTitle.textContent = '其他属性'; otherPropsTitle.style.fontWeight = 'bold'; otherPropsTitle.style.fontSize = '0.9em'; otherPropsTitle.style.margin = '8px 0'; modelItem.appendChild(otherPropsTitle); modelItem.appendChild(modelProperties); } // 清除处理标记 Array.from(model.attributes).forEach(attr => { if (attr.name === 'Name_processed' || attr.name === 'ClassName_processed') { model.removeAttribute(attr.name); } }); container.appendChild(modelItem); } /** * 显示添加模型组对话框 * @param {HTMLElement} component - 组件实例 */ export function showAddModelGroupDialog(component) { // 创建表单内容 const formContent = document.createElement('div'); formContent.className = 'modal-form'; // 获取可用的CPU核心选项 const availableCores = getCPUAffinityOptions(component.xmlDoc); // 常用属性输入字段 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.name = 'Name'; nameInput.type = 'text'; nameInput.value = '新模型组'; nameRow.appendChild(nameLabel); nameRow.appendChild(nameInput); formContent.appendChild(nameRow); // FreqGroup输入字段 const freqGroupRow = document.createElement('div'); freqGroupRow.className = 'form-row'; const freqGroupLabel = document.createElement('label'); freqGroupLabel.className = 'form-label'; freqGroupLabel.textContent = '频率组'; const freqGroupInput = document.createElement('input'); freqGroupInput.className = 'form-input'; freqGroupInput.name = 'FreqGroup'; freqGroupInput.type = 'number'; freqGroupInput.min = '0'; freqGroupInput.max = '6'; freqGroupInput.value = '0'; freqGroupInput.title = '频率组,取值范围0-6'; freqGroupRow.appendChild(freqGroupLabel); freqGroupRow.appendChild(freqGroupInput); formContent.appendChild(freqGroupRow); // Priority输入字段 const priorityRow = document.createElement('div'); priorityRow.className = 'form-row'; const priorityLabel = document.createElement('label'); priorityLabel.className = 'form-label'; priorityLabel.textContent = '优先级'; const priorityInput = document.createElement('input'); priorityInput.className = 'form-input'; priorityInput.name = 'Priority'; priorityInput.type = 'number'; priorityInput.min = '0'; priorityInput.max = '99'; priorityInput.value = '99'; priorityInput.title = '线程优先级,取值范围0-99'; priorityRow.appendChild(priorityLabel); priorityRow.appendChild(priorityInput); formContent.appendChild(priorityRow); // CPUAff下拉字段 const cpuAffRow = document.createElement('div'); cpuAffRow.className = 'form-row'; const cpuAffLabel = document.createElement('label'); cpuAffLabel.className = 'form-label'; cpuAffLabel.textContent = 'CPU亲和性'; const cpuAffSelect = document.createElement('select'); cpuAffSelect.className = 'form-input'; cpuAffSelect.name = 'CPUAff'; cpuAffSelect.title = '选择一个可用的CPU核心'; // 添加可用的CPU核心选项 if (availableCores.length > 0) { availableCores.forEach(core => { const option = document.createElement('option'); option.value = core; option.textContent = `CPU ${core}`; cpuAffSelect.appendChild(option); }); } else { // 如果没有可用选项,添加一个默认选项 const option = document.createElement('option'); option.value = '0'; option.textContent = `CPU 0`; cpuAffSelect.appendChild(option); } cpuAffRow.appendChild(cpuAffLabel); cpuAffRow.appendChild(cpuAffSelect); formContent.appendChild(cpuAffRow); // 显示对话框 createModal(component.shadowRoot, '添加新模型组', formContent, () => { const props = { Name: nameInput.value, FreqGroup: freqGroupInput.value, Priority: priorityInput.value, CPUAff: cpuAffSelect.value }; addModelGroup(component, props); }); } /** * 显示添加模型对话框 * @param {HTMLElement} component - 组件实例 * @param {number} groupIndex - 模型组索引 */ export function showAddModelDialog(component, groupIndex) { // 创建表单内容 const formContent = document.createElement('div'); formContent.className = 'modal-form'; // 创建一个行容器来放置Name和ClassName const rowContainer = document.createElement('div'); rowContainer.style.display = 'flex'; rowContainer.style.width = '100%'; rowContainer.style.gap = '10px'; rowContainer.style.marginBottom = '10px'; // 名称部分 const nameGroup = document.createElement('div'); nameGroup.style.display = 'flex'; nameGroup.style.flexDirection = 'column'; nameGroup.style.flex = '1'; const nameLabel = document.createElement('label'); nameLabel.className = 'form-label'; nameLabel.textContent = '名称'; nameLabel.style.marginBottom = '5px'; const nameInput = document.createElement('input'); nameInput.className = 'form-input'; nameInput.name = 'Name'; nameInput.type = 'text'; nameInput.value = '新模型'; nameGroup.appendChild(nameLabel); nameGroup.appendChild(nameInput); // 类名部分 const classGroup = document.createElement('div'); classGroup.style.display = 'flex'; classGroup.style.flexDirection = 'column'; classGroup.style.flex = '1'; const classLabel = document.createElement('label'); classLabel.className = 'form-label'; classLabel.textContent = '类名'; classLabel.style.marginBottom = '5px'; const classInput = document.createElement('input'); classInput.className = 'form-input'; classInput.name = 'ClassName'; classInput.type = 'text'; classInput.value = 'XNModel'; classGroup.appendChild(classLabel); classGroup.appendChild(classInput); // 将两个组添加到容器中 rowContainer.appendChild(nameGroup); rowContainer.appendChild(classGroup); // 将容器添加到表单中 formContent.appendChild(rowContainer); // 显示对话框 createModal(component.shadowRoot, '添加新模型', formContent, () => { const props = {}; formContent.querySelectorAll('.form-input').forEach(input => { props[input.name] = input.value; }); addModel(component, groupIndex, props); }); } /** * 添加模型组 * @param {HTMLElement} component - 组件实例 * @param {Object} properties - 属性对象 */ export function addModelGroup(component, properties = {}) { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(component.xmlContent, 'text/xml'); // 创建新的模型组 const newGroup = xmlDoc.createElement('ModelGroup'); // 设置默认属性 const defaultProps = { Name: '新模型组', FreqGroup: '0', Priority: '99', CPUAff: '0' }; // 合并默认属性和传入的属性 const finalProps = { ...defaultProps, ...properties }; // 设置属性 for (const [name, value] of Object.entries(finalProps)) { newGroup.setAttribute(name, value); } // 查找或创建ModelGroupList容器 let modelGroupList = xmlDoc.querySelector('ModelGroupList'); if (!modelGroupList) { modelGroupList = xmlDoc.createElement('ModelGroupList'); xmlDoc.documentElement.appendChild(modelGroupList); } // 添加到ModelGroupList modelGroupList.appendChild(newGroup); // 重新生成XML内容 const serializer = new XMLSerializer(); component.xmlContent = serializer.serializeToString(xmlDoc); // 更新编辑器 component.updateFileContent(); component.isEdited = markEdited(component.shadowRoot, component.isEdited); } /** * 删除模型组 * @param {HTMLElement} component - 组件实例 * @param {number} groupIndex - 模型组索引 */ export function deleteModelGroup(component, groupIndex) { if (confirm('确定要删除此模型组吗?此操作不可撤销。')) { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(component.xmlContent, 'text/xml'); const modelGroups = xmlDoc.querySelectorAll('ModelGroup'); if (groupIndex >= 0 && groupIndex < modelGroups.length) { const group = modelGroups[groupIndex]; group.parentNode.removeChild(group); // 重新生成XML内容 const serializer = new XMLSerializer(); component.xmlContent = serializer.serializeToString(xmlDoc); // 更新编辑器 component.updateFileContent(); component.isEdited = markEdited(component.shadowRoot, component.isEdited); } } } /** * 添加模型 * @param {HTMLElement} component - 组件实例 * @param {number} groupIndex - 模型组索引 * @param {Object} properties - 属性对象 */ export function addModel(component, groupIndex, properties = {}) { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(component.xmlContent, 'text/xml'); const modelGroups = xmlDoc.querySelectorAll('ModelGroup'); if (groupIndex >= 0 && groupIndex < modelGroups.length) { const group = modelGroups[groupIndex]; // 创建新的模型元素 const newModel = xmlDoc.createElement('Model'); // 设置默认属性 const defaultProps = { Name: '新模型', ClassName: 'XNModel' }; // 合并默认属性和传入的属性 const finalProps = { ...defaultProps, ...properties }; // 设置属性 for (const [name, value] of Object.entries(finalProps)) { newModel.setAttribute(name, value); } // 添加到模型组 group.appendChild(newModel); // 重新生成XML内容 const serializer = new XMLSerializer(); component.xmlContent = serializer.serializeToString(xmlDoc); // 更新编辑器 component.updateFileContent(); component.isEdited = markEdited(component.shadowRoot, component.isEdited); } } /** * 删除模型 * @param {HTMLElement} component - 组件实例 * @param {number} groupIndex - 模型组索引 * @param {number} modelIndex - 模型索引 */ export function deleteModel(component, groupIndex, modelIndex) { if (confirm('确定要删除此模型吗?此操作不可撤销。')) { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(component.xmlContent, 'text/xml'); const modelGroups = xmlDoc.querySelectorAll('ModelGroup'); if (groupIndex >= 0 && groupIndex < modelGroups.length) { const group = modelGroups[groupIndex]; const models = group.querySelectorAll('Model'); if (modelIndex >= 0 && modelIndex < models.length) { const model = models[modelIndex]; model.parentNode.removeChild(model); // 重新生成XML内容 const serializer = new XMLSerializer(); component.xmlContent = serializer.serializeToString(xmlDoc); // 更新编辑器 component.updateFileContent(); component.isEdited = markEdited(component.shadowRoot, component.isEdited); } } } }