2025-04-28 12:25:20 +08:00

448 lines
20 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 服务模块
* @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);
}
}
}
}