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);
|
||
}
|
||
}
|
||
}
|
||
}
|