448 lines
20 KiB
JavaScript
448 lines
20 KiB
JavaScript
|
/**
|
|||
|
* 服务模块
|
|||
|
* @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);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|