/** * 服务模块 * @type {module} */ import { createModal, markEdited } from './utils.js'; /** * 渲染服务部分 * @param {HTMLElement} component - 组件实例 * @param {HTMLElement} container - 容器元素 * @param {Element} rootElement - XML根元素 */ export function renderServicesSection(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); // 获取ServicesList元素 const servicesList = rootElement.querySelector('ServicesList'); if (!servicesList) { const emptyMsg = document.createElement('div'); emptyMsg.textContent = '没有找到服务列表配置'; emptyMsg.style.color = '#888'; emptyMsg.style.fontStyle = 'italic'; emptyMsg.style.marginBottom = '16px'; section.appendChild(emptyMsg); } else { // 获取所有Service元素 const services = servicesList.querySelectorAll('Service'); if (services.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 { // 为每个Service创建一个列表项 services.forEach((service, index) => { const serviceItem = document.createElement('div'); serviceItem.className = 'list-item'; // 创建服务标题和操作按钮 const header = document.createElement('div'); header.className = 'list-item-header'; const serviceTitle = document.createElement('div'); serviceTitle.className = 'list-item-title'; serviceTitle.textContent = service.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', () => deleteService(component, index)); actions.appendChild(deleteButton); header.appendChild(serviceTitle); header.appendChild(actions); serviceItem.appendChild(header); // 显示服务属性 const propertiesContainer = document.createElement('div'); propertiesContainer.className = 'property-group'; propertiesContainer.style.marginTop = '12px'; Array.from(service.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 === 'Name') { // 如果是Name属性,我们需要查看是否有ClassName属性 const classNameAttr = service.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 = `ServicesList/Service[${index}]@${attr.name}`; nameInput.title = '服务名称'; nameInput.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); serviceTitle.textContent = nameInput.value || `服务 ${index + 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 = `ServicesList/Service[${index}]@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); // 直接添加到serviceItem,而不是添加到propertiesContainer serviceItem.appendChild(rowContainer); // 将ClassName标记为已处理,后面不需要再处理 service.setAttribute('ClassName_processed', 'true'); } else if (attr.name === 'ClassName') { // 如果是ClassName且已处理,则跳过 if (service.getAttribute('ClassName_processed') === 'true') { return; } // 如果Name还没被处理,我们需要创建完整的行 const nameAttr = service.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 = `ServicesList/Service[${index}]@Name`; nameInput.title = '服务名称'; nameInput.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); serviceTitle.textContent = nameInput.value || `服务 ${index + 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 = `ServicesList/Service[${index}]@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); serviceItem.appendChild(rowContainer); // 将Name标记为已处理 service.setAttribute('Name_processed', 'true'); } else { // 其他属性 const input = document.createElement('input'); input.className = 'property-input'; input.type = 'text'; input.value = attr.value; input.dataset.path = `ServicesList/Service[${index}]@${attr.name}`; input.addEventListener('change', () => { component.isEdited = markEdited(component.shadowRoot, component.isEdited); }); propertyItem.appendChild(label); propertyItem.appendChild(input); propertiesContainer.appendChild(propertyItem); } }); // 只有当有其他属性时才添加属性组 if (propertiesContainer.children.length > 0) { // 添加一个标题来分隔基本属性和其他属性 const otherPropsTitle = document.createElement('div'); otherPropsTitle.textContent = '其他属性'; otherPropsTitle.style.fontWeight = 'bold'; otherPropsTitle.style.fontSize = '0.9em'; otherPropsTitle.style.margin = '8px 0'; serviceItem.appendChild(otherPropsTitle); serviceItem.appendChild(propertiesContainer); } // 清除处理标记 Array.from(service.attributes).forEach(attr => { if (attr.name === 'Name_processed' || attr.name === 'ClassName_processed') { service.removeAttribute(attr.name); } }); section.appendChild(serviceItem); }); } // 添加新服务按钮 const addButton = document.createElement('button'); addButton.className = 'add-button'; addButton.style.marginTop = '16px'; addButton.textContent = '添加服务'; addButton.title = '添加新的服务'; addButton.addEventListener('click', () => showAddServiceDialog(component)); section.appendChild(addButton); } container.appendChild(section); } /** * 显示添加服务对话框 * @param {HTMLElement} component - 组件实例 */ export function showAddServiceDialog(component) { // 创建表单内容 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 = 'XNService'; 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; }); addService(component, props); }); } /** * 添加服务 * @param {HTMLElement} component - 组件实例 * @param {Object} properties - 属性对象 */ export function addService(component, properties = {}) { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(component.xmlContent, 'text/xml'); // 查找或创建ServicesList容器 let servicesList = xmlDoc.querySelector('ServicesList'); if (!servicesList) { servicesList = xmlDoc.createElement('ServicesList'); xmlDoc.documentElement.appendChild(servicesList); } // 创建新的服务元素 const newService = xmlDoc.createElement('Service'); // 设置默认属性 const defaultProps = { Name: '新服务', ClassName: 'XNService' }; // 合并默认属性和传入的属性 const finalProps = { ...defaultProps, ...properties }; // 设置属性 for (const [name, value] of Object.entries(finalProps)) { newService.setAttribute(name, value); } // 添加到服务列表 servicesList.appendChild(newService); // 重新生成XML内容 const serializer = new XMLSerializer(); component.xmlContent = serializer.serializeToString(xmlDoc); // 更新编辑器 component.updateFileContent(); component.isEdited = markEdited(component.shadowRoot, component.isEdited); } /** * 删除服务 * @param {HTMLElement} component - 组件实例 * @param {number} serviceIndex - 服务索引 */ export function deleteService(component, serviceIndex) { if (confirm('确定要删除此服务吗?此操作不可撤销。')) { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(component.xmlContent, 'text/xml'); const servicesList = xmlDoc.querySelector('ServicesList'); if (servicesList) { const services = servicesList.querySelectorAll('Service'); if (serviceIndex >= 0 && serviceIndex < services.length) { const service = services[serviceIndex]; service.parentNode.removeChild(service); // 重新生成XML内容 const serializer = new XMLSerializer(); component.xmlContent = serializer.serializeToString(xmlDoc); // 更新编辑器 component.updateFileContent(); component.isEdited = markEdited(component.shadowRoot, component.isEdited); } } } }