593 lines
24 KiB
JavaScript
593 lines
24 KiB
JavaScript
|
/**
|
|||
|
* UI元素渲染模块
|
|||
|
* @type {module}
|
|||
|
*/
|
|||
|
import { escapeHtml } from './utils.js';
|
|||
|
import { updateElementValue } from './xml-handler.js';
|
|||
|
|
|||
|
/**
|
|||
|
* 渲染基本信息部分
|
|||
|
* @param {Element} container - 容器元素
|
|||
|
* @param {Element} rootElement - XML根元素
|
|||
|
* @param {Document} xmlDoc - XML文档对象
|
|||
|
* @param {Function} showDateTimeDialog - 显示日期时间对话框的回调函数
|
|||
|
* @param {Function} markEdited - 标记已编辑的回调函数
|
|||
|
*/
|
|||
|
export function renderBasicInfoSection(container, rootElement, xmlDoc, showDateTimeDialog, markEdited) {
|
|||
|
const section = document.createElement('div');
|
|||
|
section.className = 'section';
|
|||
|
|
|||
|
const sectionHeader = document.createElement('div');
|
|||
|
sectionHeader.className = 'section-header';
|
|||
|
|
|||
|
const sectionTitle = document.createElement('div');
|
|||
|
sectionTitle.className = 'section-title-text';
|
|||
|
sectionTitle.textContent = '基本信息';
|
|||
|
|
|||
|
sectionHeader.appendChild(sectionTitle);
|
|||
|
section.appendChild(sectionHeader);
|
|||
|
|
|||
|
// 基本信息字段及描述
|
|||
|
const basicInfoFields = [
|
|||
|
{ name: 'Name', label: '模型名称', placeholder: '请输入模型名称', tooltip: '模型的名称,用于在系统中标识此模型' },
|
|||
|
{ name: 'Description', label: '模型描述', placeholder: '请输入模型描述', tooltip: '对模型功能和用途的简要描述' },
|
|||
|
{ name: 'Author', label: '作者', placeholder: '请输入作者', tooltip: '模型创建者或维护者的姓名' },
|
|||
|
{ name: 'Version', label: '版本', placeholder: '请输入版本号,如: 1.0.0', tooltip: '模型的版本号,建议使用语义化版本号格式' },
|
|||
|
{ name: 'CreateTime', label: '创建时间', placeholder: '创建时间,如: 2023-12-31 12:00:00', tooltip: '模型首次创建的日期和时间', type: 'datetime' },
|
|||
|
{ name: 'ChangeTime', label: '修改时间', placeholder: '修改时间,如: 2023-12-31 12:00:00', tooltip: '模型最后一次修改的日期和时间', type: 'datetime' }
|
|||
|
];
|
|||
|
|
|||
|
// 创建两列布局容器
|
|||
|
const twoColumnForm = document.createElement('div');
|
|||
|
twoColumnForm.className = 'form-container two-column-form';
|
|||
|
twoColumnForm.style.display = 'grid';
|
|||
|
twoColumnForm.style.gridTemplateColumns = 'repeat(2, 1fr)';
|
|||
|
twoColumnForm.style.gap = '16px';
|
|||
|
|
|||
|
// 处理基本信息字段
|
|||
|
basicInfoFields.forEach(field => {
|
|||
|
// 获取元素值
|
|||
|
const element = rootElement.querySelector(field.name);
|
|||
|
const value = element ? element.textContent : '';
|
|||
|
|
|||
|
// 创建属性行
|
|||
|
const row = document.createElement('div');
|
|||
|
row.className = 'property-row';
|
|||
|
|
|||
|
// 创建标签
|
|||
|
const label = document.createElement('div');
|
|||
|
label.className = 'property-label';
|
|||
|
label.textContent = field.label;
|
|||
|
label.style.width = '90px'; // 设置固定宽度使标签对齐
|
|||
|
|
|||
|
// 创建输入容器
|
|||
|
const inputContainer = document.createElement('div');
|
|||
|
inputContainer.className = 'input-container';
|
|||
|
inputContainer.style.flex = '1';
|
|||
|
inputContainer.style.display = 'flex';
|
|||
|
|
|||
|
// 创建输入框
|
|||
|
const input = document.createElement('input');
|
|||
|
input.type = 'text';
|
|||
|
input.className = 'property-input';
|
|||
|
input.dataset.field = field.name;
|
|||
|
input.value = value;
|
|||
|
input.placeholder = field.placeholder;
|
|||
|
input.title = field.tooltip;
|
|||
|
|
|||
|
// 添加输入事件处理
|
|||
|
input.addEventListener('change', () => {
|
|||
|
updateElementValue(xmlDoc, field.name, input.value);
|
|||
|
markEdited();
|
|||
|
});
|
|||
|
|
|||
|
inputContainer.appendChild(input);
|
|||
|
|
|||
|
// 对于日期时间类型,添加日期选择按钮
|
|||
|
if (field.type === 'datetime') {
|
|||
|
input.style.flex = '1';
|
|||
|
|
|||
|
const datetimeButton = document.createElement('button');
|
|||
|
datetimeButton.type = 'button';
|
|||
|
datetimeButton.className = 'icon-button calendar-button';
|
|||
|
datetimeButton.title = '选择日期和时间';
|
|||
|
datetimeButton.addEventListener('click', () => {
|
|||
|
showDateTimeDialog(input);
|
|||
|
});
|
|||
|
|
|||
|
// 添加一个刷新按钮,快速设置为当前时间
|
|||
|
const refreshButton = document.createElement('button');
|
|||
|
refreshButton.type = 'button';
|
|||
|
refreshButton.className = 'icon-button refresh-button-sm';
|
|||
|
refreshButton.title = '设置为当前时间';
|
|||
|
refreshButton.addEventListener('click', () => {
|
|||
|
const now = new Date();
|
|||
|
const dateStr = now.toISOString().split('T')[0];
|
|||
|
const timeStr = now.toTimeString().split(' ')[0];
|
|||
|
const datetimeStr = `${dateStr} ${timeStr}`;
|
|||
|
|
|||
|
input.value = datetimeStr;
|
|||
|
updateElementValue(xmlDoc, field.name, datetimeStr);
|
|||
|
markEdited(); // 确保触发修改标志
|
|||
|
});
|
|||
|
|
|||
|
inputContainer.appendChild(datetimeButton);
|
|||
|
inputContainer.appendChild(refreshButton);
|
|||
|
}
|
|||
|
|
|||
|
// 组装行
|
|||
|
row.appendChild(label);
|
|||
|
row.appendChild(inputContainer);
|
|||
|
twoColumnForm.appendChild(row);
|
|||
|
});
|
|||
|
|
|||
|
section.appendChild(twoColumnForm);
|
|||
|
container.appendChild(section);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 渲染高级设置部分
|
|||
|
* @param {Element} container - 容器元素
|
|||
|
* @param {Element} rootElement - XML根元素
|
|||
|
* @param {Document} xmlDoc - XML文档对象
|
|||
|
* @param {Function} renderCommandListTable - 渲染命令列表表格的函数
|
|||
|
* @param {Function} markEdited - 标记已编辑的回调函数
|
|||
|
*/
|
|||
|
export function renderAdvancedSection(container, rootElement, xmlDoc, renderCommandListTable, markEdited) {
|
|||
|
const section = document.createElement('div');
|
|||
|
section.className = 'section';
|
|||
|
|
|||
|
const sectionHeader = document.createElement('div');
|
|||
|
sectionHeader.className = 'section-header';
|
|||
|
|
|||
|
const sectionTitle = document.createElement('div');
|
|||
|
sectionTitle.className = 'section-title-text';
|
|||
|
sectionTitle.textContent = '运行设置';
|
|||
|
|
|||
|
sectionHeader.appendChild(sectionTitle);
|
|||
|
section.appendChild(sectionHeader);
|
|||
|
|
|||
|
// 创建表单
|
|||
|
const form = document.createElement('div');
|
|||
|
form.className = 'form-container';
|
|||
|
|
|||
|
// 创建节点和优先级所在的行
|
|||
|
const nodeAndPriorityRow = document.createElement('div');
|
|||
|
nodeAndPriorityRow.className = 'property-row';
|
|||
|
nodeAndPriorityRow.style.display = 'grid';
|
|||
|
nodeAndPriorityRow.style.gridTemplateColumns = 'auto 1fr auto 1fr';
|
|||
|
nodeAndPriorityRow.style.gap = '16px';
|
|||
|
nodeAndPriorityRow.style.alignItems = 'center';
|
|||
|
|
|||
|
// ----- 节点部分 -----
|
|||
|
|
|||
|
// 创建节点标签
|
|||
|
const nodeLabel = document.createElement('div');
|
|||
|
nodeLabel.className = 'property-label';
|
|||
|
nodeLabel.textContent = '运行节点';
|
|||
|
nodeLabel.style.width = '90px'; // 与基本信息部分统一宽度
|
|||
|
|
|||
|
// 创建节点输入容器
|
|||
|
const nodeContainer = document.createElement('div');
|
|||
|
nodeContainer.className = 'input-container';
|
|||
|
nodeContainer.style.display = 'flex';
|
|||
|
nodeContainer.style.gap = '10px';
|
|||
|
nodeContainer.style.width = 'calc(100% - 20px)'; // 控制整体宽度
|
|||
|
|
|||
|
// 获取当前节点值
|
|||
|
const nodeElement = rootElement.querySelector('Node');
|
|||
|
const nodeValue = nodeElement ? nodeElement.textContent : '0-0';
|
|||
|
|
|||
|
// 解析当前节点值,格式为"x-y"
|
|||
|
let [freqGroup, nodeIndex] = nodeValue.split('-').map(Number);
|
|||
|
if (isNaN(freqGroup)) freqGroup = 0;
|
|||
|
if (isNaN(nodeIndex)) nodeIndex = 0;
|
|||
|
|
|||
|
// 创建运行频率下拉框
|
|||
|
const freqGroupSelect = document.createElement('select');
|
|||
|
freqGroupSelect.className = 'property-input custom-select';
|
|||
|
freqGroupSelect.style.flex = '1';
|
|||
|
freqGroupSelect.style.width = '120px';
|
|||
|
freqGroupSelect.style.maxWidth = '120px';
|
|||
|
freqGroupSelect.style.padding = '5px';
|
|||
|
freqGroupSelect.style.appearance = 'none';
|
|||
|
freqGroupSelect.style.backgroundImage = 'url("assets/icons/png/chevron-down_b.png")';
|
|||
|
freqGroupSelect.style.backgroundRepeat = 'no-repeat';
|
|||
|
freqGroupSelect.style.backgroundPosition = 'right 8px center';
|
|||
|
freqGroupSelect.style.backgroundSize = '14px';
|
|||
|
freqGroupSelect.style.paddingRight = '30px';
|
|||
|
freqGroupSelect.title = '选择运行频率:0=基频,1=半频,2=1/4频,3=1/8频,以此类推';
|
|||
|
|
|||
|
// 创建运行频率标签
|
|||
|
const freqGroupLabel = document.createElement('div');
|
|||
|
freqGroupLabel.className = 'property-sublabel';
|
|||
|
freqGroupLabel.textContent = '运行频率';
|
|||
|
freqGroupLabel.style.fontSize = '12px';
|
|||
|
freqGroupLabel.style.marginBottom = '3px';
|
|||
|
freqGroupLabel.title = '选择运行频率:0=基频,1=半频,2=1/4频,3=1/8频,以此类推';
|
|||
|
|
|||
|
// 创建连接符
|
|||
|
const connector = document.createElement('div');
|
|||
|
connector.textContent = '——';
|
|||
|
connector.style.display = 'flex';
|
|||
|
connector.style.alignItems = 'flex-start';
|
|||
|
connector.style.marginTop = '25px';
|
|||
|
connector.style.fontWeight = 'bold';
|
|||
|
connector.style.padding = '0 8px';
|
|||
|
connector.style.fontSize = '16px';
|
|||
|
|
|||
|
// 创建节点索引标签
|
|||
|
const nodeIndexLabel = document.createElement('div');
|
|||
|
nodeIndexLabel.className = 'property-sublabel';
|
|||
|
nodeIndexLabel.textContent = '节点号';
|
|||
|
nodeIndexLabel.style.fontSize = '12px';
|
|||
|
nodeIndexLabel.style.marginBottom = '3px';
|
|||
|
nodeIndexLabel.title = '选择节点编号,范围根据运行频率决定';
|
|||
|
|
|||
|
// 创建运行频率容器
|
|||
|
const freqGroupContainer = document.createElement('div');
|
|||
|
freqGroupContainer.style.display = 'flex';
|
|||
|
freqGroupContainer.style.flexDirection = 'column';
|
|||
|
freqGroupContainer.style.width = '120px';
|
|||
|
|
|||
|
// 创建节点索引容器
|
|||
|
const nodeIndexContainer = document.createElement('div');
|
|||
|
nodeIndexContainer.style.display = 'flex';
|
|||
|
nodeIndexContainer.style.flexDirection = 'column';
|
|||
|
nodeIndexContainer.style.width = '80px';
|
|||
|
|
|||
|
// 设置节点行的工具提示
|
|||
|
nodeContainer.title = '运行节点格式为"运行频率-节点编号",运行频率值越大,可用节点数越多';
|
|||
|
|
|||
|
// 添加运行频率选项
|
|||
|
const freqOptions = [
|
|||
|
{ value: 0, text: '基频' },
|
|||
|
{ value: 1, text: '半频' },
|
|||
|
{ value: 2, text: '1/4频' },
|
|||
|
{ value: 3, text: '1/8频' },
|
|||
|
{ value: 4, text: '1/16频' },
|
|||
|
{ value: 5, text: '1/32频' }
|
|||
|
];
|
|||
|
|
|||
|
freqOptions.forEach(option => {
|
|||
|
const optionElement = document.createElement('option');
|
|||
|
optionElement.value = option.value;
|
|||
|
optionElement.textContent = option.text;
|
|||
|
if (parseInt(option.value) === freqGroup) {
|
|||
|
optionElement.selected = true;
|
|||
|
}
|
|||
|
freqGroupSelect.appendChild(optionElement);
|
|||
|
});
|
|||
|
|
|||
|
// 创建节点索引下拉框
|
|||
|
const nodeIndexSelect = document.createElement('select');
|
|||
|
nodeIndexSelect.className = 'property-input custom-select';
|
|||
|
nodeIndexSelect.style.width = '80px';
|
|||
|
nodeIndexSelect.style.padding = '5px';
|
|||
|
nodeIndexSelect.style.appearance = 'none';
|
|||
|
nodeIndexSelect.style.backgroundImage = 'url("assets/icons/png/chevron-down_b.png")';
|
|||
|
nodeIndexSelect.style.backgroundRepeat = 'no-repeat';
|
|||
|
nodeIndexSelect.style.backgroundPosition = 'right 8px center';
|
|||
|
nodeIndexSelect.style.backgroundSize = '14px';
|
|||
|
nodeIndexSelect.style.paddingRight = '30px';
|
|||
|
nodeIndexSelect.title = '选择节点编号,范围从0到2^(运行频率组-1)';
|
|||
|
|
|||
|
// 更新节点索引下拉框的选项
|
|||
|
const updateNodeOptions = (freqGroupValue) => {
|
|||
|
nodeIndexSelect.innerHTML = ''; // 清空现有选项
|
|||
|
|
|||
|
// 根据运行频率计算节点数量
|
|||
|
const nodeCount = Math.pow(2, freqGroupValue);
|
|||
|
|
|||
|
// 添加节点选项
|
|||
|
for (let i = 0; i < nodeCount; i++) {
|
|||
|
const optionElement = document.createElement('option');
|
|||
|
optionElement.value = i;
|
|||
|
optionElement.textContent = i;
|
|||
|
if (i === nodeIndex) {
|
|||
|
optionElement.selected = true;
|
|||
|
}
|
|||
|
nodeIndexSelect.appendChild(optionElement);
|
|||
|
}
|
|||
|
|
|||
|
// 如果当前选中的节点索引超出了范围,则重置为0
|
|||
|
if (nodeIndex >= nodeCount) {
|
|||
|
nodeIndex = 0;
|
|||
|
nodeIndexSelect.value = nodeIndex;
|
|||
|
// 更新XML值
|
|||
|
updateElementValue(xmlDoc, 'Node', `${freqGroupValue}-${nodeIndex}`);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
// 初始化节点选项
|
|||
|
updateNodeOptions(freqGroup);
|
|||
|
|
|||
|
// 添加运行频率下拉框的变更事件
|
|||
|
freqGroupSelect.addEventListener('change', () => {
|
|||
|
const newFreqGroup = parseInt(freqGroupSelect.value);
|
|||
|
updateNodeOptions(newFreqGroup);
|
|||
|
// 更新XML值
|
|||
|
updateElementValue(xmlDoc, 'Node', `${newFreqGroup}-${nodeIndexSelect.value}`);
|
|||
|
markEdited();
|
|||
|
});
|
|||
|
|
|||
|
// 添加节点索引下拉框的变更事件
|
|||
|
nodeIndexSelect.addEventListener('change', () => {
|
|||
|
// 更新XML值
|
|||
|
updateElementValue(xmlDoc, 'Node', `${freqGroupSelect.value}-${nodeIndexSelect.value}`);
|
|||
|
markEdited();
|
|||
|
});
|
|||
|
|
|||
|
// 添加到容器
|
|||
|
freqGroupContainer.appendChild(freqGroupLabel);
|
|||
|
freqGroupContainer.appendChild(freqGroupSelect);
|
|||
|
|
|||
|
nodeIndexContainer.appendChild(nodeIndexLabel);
|
|||
|
nodeIndexContainer.appendChild(nodeIndexSelect);
|
|||
|
|
|||
|
nodeContainer.appendChild(freqGroupContainer);
|
|||
|
nodeContainer.appendChild(connector);
|
|||
|
nodeContainer.appendChild(nodeIndexContainer);
|
|||
|
|
|||
|
// ----- 优先级部分 -----
|
|||
|
|
|||
|
// 获取优先级值
|
|||
|
const priorityElement = rootElement.querySelector('Priority');
|
|||
|
const priorityValue = priorityElement ? priorityElement.textContent : '';
|
|||
|
|
|||
|
// 创建优先级标签
|
|||
|
const priorityLabel = document.createElement('div');
|
|||
|
priorityLabel.className = 'property-label';
|
|||
|
priorityLabel.textContent = '运行优先级';
|
|||
|
priorityLabel.style.width = '90px'; // 与其他标签统一宽度
|
|||
|
|
|||
|
// 创建优先级输入容器
|
|||
|
const priorityContainer = document.createElement('div');
|
|||
|
priorityContainer.className = 'input-container';
|
|||
|
priorityContainer.style.display = 'flex';
|
|||
|
priorityContainer.style.width = '100%';
|
|||
|
|
|||
|
// 创建优先级输入框
|
|||
|
const priorityInput = document.createElement('input');
|
|||
|
priorityInput.type = 'text';
|
|||
|
priorityInput.className = 'property-input';
|
|||
|
priorityInput.dataset.field = 'Priority';
|
|||
|
priorityInput.value = priorityValue;
|
|||
|
priorityInput.placeholder = '运行优先级,如: 99';
|
|||
|
priorityInput.title = '模型运行的优先级,数字越大优先级越高';
|
|||
|
|
|||
|
// 添加优先级输入事件处理
|
|||
|
priorityInput.addEventListener('change', () => {
|
|||
|
updateElementValue(xmlDoc, 'Priority', priorityInput.value);
|
|||
|
markEdited();
|
|||
|
});
|
|||
|
|
|||
|
priorityContainer.appendChild(priorityInput);
|
|||
|
|
|||
|
// 组装节点和优先级到同一行
|
|||
|
nodeAndPriorityRow.appendChild(nodeLabel);
|
|||
|
nodeAndPriorityRow.appendChild(nodeContainer);
|
|||
|
nodeAndPriorityRow.appendChild(priorityLabel);
|
|||
|
nodeAndPriorityRow.appendChild(priorityContainer);
|
|||
|
|
|||
|
form.appendChild(nodeAndPriorityRow);
|
|||
|
|
|||
|
// 添加数据包动态库路径字段
|
|||
|
const mathLibElement = rootElement.querySelector('MathLib');
|
|||
|
const mathLibValue = mathLibElement ? mathLibElement.textContent : '';
|
|||
|
|
|||
|
// 创建数据包动态库路径行
|
|||
|
const mathLibRow = document.createElement('div');
|
|||
|
mathLibRow.className = 'property-row';
|
|||
|
|
|||
|
// 创建标签
|
|||
|
const mathLibLabel = document.createElement('div');
|
|||
|
mathLibLabel.className = 'property-label';
|
|||
|
mathLibLabel.textContent = '数据包动态库路径';
|
|||
|
mathLibLabel.style.width = '90px'; // 与其他标签统一宽度
|
|||
|
|
|||
|
// 创建输入容器
|
|||
|
const mathLibContainer = document.createElement('div');
|
|||
|
mathLibContainer.className = 'input-container';
|
|||
|
mathLibContainer.style.flex = '1';
|
|||
|
mathLibContainer.style.display = 'flex';
|
|||
|
mathLibContainer.style.marginLeft = '0'; // 确保左对齐
|
|||
|
|
|||
|
// 创建输入框
|
|||
|
const mathLibInput = document.createElement('input');
|
|||
|
mathLibInput.type = 'text';
|
|||
|
mathLibInput.className = 'property-input';
|
|||
|
mathLibInput.dataset.field = 'MathLib';
|
|||
|
mathLibInput.value = mathLibValue;
|
|||
|
mathLibInput.placeholder = '数据包动态库路径';
|
|||
|
mathLibInput.title = '模型使用的数据包动态库的相对文件路径,相对于模型库目录';
|
|||
|
|
|||
|
// 添加输入事件处理
|
|||
|
mathLibInput.addEventListener('change', () => {
|
|||
|
updateElementValue(xmlDoc, 'MathLib', mathLibInput.value);
|
|||
|
markEdited();
|
|||
|
});
|
|||
|
|
|||
|
mathLibContainer.appendChild(mathLibInput);
|
|||
|
|
|||
|
// 组装行
|
|||
|
mathLibRow.appendChild(mathLibLabel);
|
|||
|
mathLibRow.appendChild(mathLibContainer);
|
|||
|
form.appendChild(mathLibRow);
|
|||
|
|
|||
|
// 添加命令列表表格
|
|||
|
renderCommandListTable(form, rootElement);
|
|||
|
|
|||
|
section.appendChild(form);
|
|||
|
container.appendChild(section);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 递归渲染XML元素
|
|||
|
* @param {Element} container - 容器元素
|
|||
|
* @param {Element} parentElement - 父元素
|
|||
|
* @param {string} parentPath - 父元素路径
|
|||
|
* @param {number} level - 缩进级别
|
|||
|
* @param {Function} isValidElementName - 验证元素名称的函数
|
|||
|
* @param {Function} updateElementByPath - 更新元素值的函数
|
|||
|
* @param {Function} deleteElement - 删除元素的函数
|
|||
|
* @param {Function} addElement - 添加元素的函数
|
|||
|
* @param {Function} showAddElementDialog - 显示添加元素对话框的函数
|
|||
|
* @param {Function} showEditElementDialog - 显示编辑元素对话框的函数
|
|||
|
*/
|
|||
|
export function renderElements(container, parentElement, parentPath, level = 0,
|
|||
|
isValidElementName, updateElementByPath, deleteElement, addElement,
|
|||
|
showAddElementDialog, showEditElementDialog) {
|
|||
|
|
|||
|
// 过滤出需要在其他设置中显示的元素
|
|||
|
const commonElements = ['Name', 'Description', 'Author', 'Version', 'CreateTime', 'ChangeTime',
|
|||
|
'Node', 'Priority', 'MathLib', 'CommandList'];
|
|||
|
|
|||
|
Array.from(parentElement.children).forEach(element => {
|
|||
|
// 跳过常见元素,这些在基本信息和高级设置中已经显示
|
|||
|
if (commonElements.includes(element.nodeName)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
const elementName = element.nodeName;
|
|||
|
const elementPath = `${parentPath}/${elementName}`;
|
|||
|
|
|||
|
// 创建元素行
|
|||
|
const elementRow = document.createElement('div');
|
|||
|
elementRow.className = 'element-row';
|
|||
|
elementRow.dataset.path = elementPath;
|
|||
|
|
|||
|
// 添加缩进
|
|||
|
const indent = level * 20; // 每级缩进20px
|
|||
|
elementRow.style.paddingLeft = `${indent}px`;
|
|||
|
|
|||
|
// 创建元素框
|
|||
|
const elementBox = document.createElement('div');
|
|||
|
elementBox.className = 'element-box';
|
|||
|
|
|||
|
// 添加展开/折叠按钮(如果有子元素)
|
|||
|
if (element.children.length > 0) {
|
|||
|
const toggleButton = document.createElement('button');
|
|||
|
toggleButton.className = 'toggle-button';
|
|||
|
toggleButton.innerHTML = '▼'; // 默认展开
|
|||
|
toggleButton.addEventListener('click', () => {
|
|||
|
const childContainer = elementRow.nextElementSibling;
|
|||
|
if (childContainer && childContainer.classList.contains('element-children')) {
|
|||
|
if (childContainer.style.display === 'none') {
|
|||
|
childContainer.style.display = 'block';
|
|||
|
toggleButton.innerHTML = '▼';
|
|||
|
} else {
|
|||
|
childContainer.style.display = 'none';
|
|||
|
toggleButton.innerHTML = '►';
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
elementBox.appendChild(toggleButton);
|
|||
|
} else {
|
|||
|
// 如果没有子元素,添加占位符
|
|||
|
const toggleSpacer = document.createElement('div');
|
|||
|
toggleSpacer.className = 'toggle-spacer';
|
|||
|
elementBox.appendChild(toggleSpacer);
|
|||
|
}
|
|||
|
|
|||
|
// 添加元素名称
|
|||
|
const nameElement = document.createElement('div');
|
|||
|
nameElement.className = 'element-name';
|
|||
|
nameElement.textContent = elementName;
|
|||
|
elementBox.appendChild(nameElement);
|
|||
|
|
|||
|
// 添加元素值/编辑控件
|
|||
|
const valueContainer = document.createElement('div');
|
|||
|
valueContainer.className = 'element-value-container';
|
|||
|
|
|||
|
// 获取元素值
|
|||
|
let elementValue = '';
|
|||
|
if (element.children.length === 0) {
|
|||
|
elementValue = element.textContent;
|
|||
|
}
|
|||
|
|
|||
|
// 创建输入框(如果是叶子节点)
|
|||
|
if (element.children.length === 0) {
|
|||
|
const valueInput = document.createElement('input');
|
|||
|
valueInput.type = 'text';
|
|||
|
valueInput.className = 'element-value-input';
|
|||
|
valueInput.value = elementValue;
|
|||
|
valueInput.placeholder = '输入值';
|
|||
|
valueInput.dataset.path = elementPath;
|
|||
|
|
|||
|
// 添加改变事件
|
|||
|
valueInput.addEventListener('change', (e) => {
|
|||
|
const newValue = e.target.value;
|
|||
|
updateElementByPath(elementPath, newValue);
|
|||
|
});
|
|||
|
|
|||
|
valueContainer.appendChild(valueInput);
|
|||
|
}
|
|||
|
|
|||
|
elementBox.appendChild(valueContainer);
|
|||
|
|
|||
|
// 添加操作按钮
|
|||
|
const actionsContainer = document.createElement('div');
|
|||
|
actionsContainer.className = 'element-actions';
|
|||
|
|
|||
|
// 删除按钮
|
|||
|
const deleteButton = document.createElement('button');
|
|||
|
deleteButton.className = 'element-action-button';
|
|||
|
deleteButton.textContent = '删除';
|
|||
|
deleteButton.style.backgroundColor = '#E77979';
|
|||
|
deleteButton.addEventListener('click', () => {
|
|||
|
deleteElement(element, elementPath);
|
|||
|
});
|
|||
|
actionsContainer.appendChild(deleteButton);
|
|||
|
|
|||
|
elementBox.appendChild(actionsContainer);
|
|||
|
elementRow.appendChild(elementBox);
|
|||
|
container.appendChild(elementRow);
|
|||
|
|
|||
|
// 如果有子元素,创建子元素容器
|
|||
|
if (element.children.length > 0) {
|
|||
|
const childContainer = document.createElement('div');
|
|||
|
childContainer.className = 'element-children';
|
|||
|
childContainer.dataset.parentPath = elementPath;
|
|||
|
childContainer.style.paddingLeft = '20px'; // 子元素缩进
|
|||
|
|
|||
|
// 递归渲染子元素
|
|||
|
renderElements(childContainer, element, elementPath, level + 1,
|
|||
|
isValidElementName, updateElementByPath, deleteElement, addElement,
|
|||
|
showAddElementDialog, showEditElementDialog);
|
|||
|
|
|||
|
container.appendChild(childContainer);
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 渲染其它设置部分
|
|||
|
* @param {Element} container - 容器元素
|
|||
|
* @param {Element} rootElement - XML根元素
|
|||
|
* @param {Function} renderElements - 递归渲染XML元素的函数
|
|||
|
*/
|
|||
|
export function renderOtherSettingsSection(container, rootElement, renderElementsFunc) {
|
|||
|
const section = document.createElement('div');
|
|||
|
section.className = 'settings-section other-settings';
|
|||
|
|
|||
|
const header = document.createElement('div');
|
|||
|
header.className = 'section-header';
|
|||
|
header.innerHTML = `
|
|||
|
<h3>其他设置</h3>
|
|||
|
<div class="section-note" style="font-size: 12px; color: #666; margin-top: 5px;">如需添加参数,请手动编辑配置文件</div>
|
|||
|
`;
|
|||
|
|
|||
|
section.appendChild(header);
|
|||
|
|
|||
|
// 创建元素容器
|
|||
|
const elementsContainer = document.createElement('div');
|
|||
|
elementsContainer.id = 'otherSettingsContainer';
|
|||
|
elementsContainer.className = 'elements-container';
|
|||
|
|
|||
|
// 渲染所有元素
|
|||
|
renderElementsFunc(elementsContainer, rootElement, '/' + rootElement.nodeName);
|
|||
|
|
|||
|
section.appendChild(elementsContainer);
|
|||
|
container.appendChild(section);
|
|||
|
}
|