448 lines
20 KiB
JavaScript
Raw Normal View History

2025-04-28 12:25:20 +08:00
/**
* 服务模块
* @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);
}
}
}
}