模型开发和服务开发页面更新

This commit is contained in:
jinchao 2025-05-28 10:01:28 +08:00
parent 896b46a1b1
commit 6b2158c26e
7 changed files with 644 additions and 142 deletions

Binary file not shown.

View File

@ -393,9 +393,15 @@ class ModelDevelopment extends HTMLElement {
async fetchModels(chapterId) {
try {
const headerTools = document.querySelector('header-tools');
const productName = headerTools.selectedProduct;
const response = await fetch(`/api/chapter-models/${chapterId}?productName=${encodeURIComponent(productName)}`);
const savedSelection = localStorage.getItem('xnsim-selection');
const selection = savedSelection ? JSON.parse(savedSelection) : {};
const plane = selection.plane;
if (!plane) {
throw new Error('请先选择机型!');
}
const response = await fetch(`/api/chapter-models/${chapterId}?planeName=${encodeURIComponent(plane)}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
@ -412,10 +418,19 @@ class ModelDevelopment extends HTMLElement {
async fetchModelVersions(className, modelName) {
try {
const headerTools = document.querySelector('header-tools');
const productName = headerTools.selectedProduct;
const savedSelection = localStorage.getItem('xnsim-selection');
const selection = savedSelection ? JSON.parse(savedSelection) : {};
const plane = selection.plane;
const confID = selection.configurationId;
const response = await fetch(`/api/model-versions/${encodeURIComponent(className)}?productName=${encodeURIComponent(productName)}`);
if (!plane) {
throw new Error('请先选择机型!');
}
if (!confID) {
throw new Error('请先选择构型!');
}
const response = await fetch(`/api/model-versions/${encodeURIComponent(className)}?planeName=${encodeURIComponent(plane)}&confID=${encodeURIComponent(confID)}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
@ -430,10 +445,6 @@ class ModelDevelopment extends HTMLElement {
async saveModelVersion(versionData) {
try {
const headerTools = document.querySelector('header-tools');
const productName = headerTools.selectedProduct;
versionData.ProductName = productName;
const response = await fetch('/api/model-versions', {
method: 'POST',
headers: {
@ -443,7 +454,8 @@ class ModelDevelopment extends HTMLElement {
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
const errorData = await response.json();
throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
}
return await response.json();
@ -664,6 +676,24 @@ class ModelDevelopment extends HTMLElement {
showVersionEditor(versionData) {
this.currentView = 'versionEditor';
// 确保 CmdList 是数组
if (versionData.CmdList) {
try {
// 如果 CmdList 是字符串,尝试解析它
if (typeof versionData.CmdList === 'string') {
versionData.CmdList = JSON.parse(versionData.CmdList);
}
// 确保 CmdList 是数组
if (!Array.isArray(versionData.CmdList)) {
versionData.CmdList = [];
}
} catch (e) {
console.error('解析 CmdList 失败:', e);
versionData.CmdList = [];
}
} else {
versionData.CmdList = [];
}
this.currentVersion = versionData;
this.isEditMode = versionData && versionData.Version ? true : false;
@ -803,6 +833,16 @@ class ModelDevelopment extends HTMLElement {
<label for="version">版本 (Version)*</label>
<input type="text" id="version" name="Version" value="${this.currentVersion.Version || '1.0.0'}" pattern="[0-9.]+" title="版本号只能包含数字和小数点例如1.0.0" required>
</div>
`;
// 右列 - 描述和其他信息
const rightColumn = document.createElement('div');
rightColumn.className = 'form-column';
rightColumn.innerHTML = `
<div class="form-group">
<label for="description">描述 (Description)</label>
<input type="text" id="description" name="Description" value="${this.currentVersion.Description || ''}" title="模型版本的详细描述,包括主要功能和改进">
</div>
<div class="form-group">
<label for="author">作者 (Author)*</label>
<input type="text" id="author" name="Author" value="${this.currentVersion.Author || ''}" title="模型版本的作者姓名" required>
@ -823,16 +863,6 @@ class ModelDevelopment extends HTMLElement {
</div>
`;
// 右列 - 描述和其他信息
const rightColumn = document.createElement('div');
rightColumn.className = 'form-column';
rightColumn.innerHTML = `
<div class="form-group" style="height: 100%;">
<label for="description">描述 (Description)</label>
<textarea id="description" name="Description" style="height: calc(100% - 30px);" title="模型版本的详细描述,包括主要功能和改进">${this.currentVersion.Description || ''}</textarea>
</div>
`;
basicInfoSection.appendChild(leftColumn);
basicInfoSection.appendChild(rightColumn);
@ -917,21 +947,73 @@ class ModelDevelopment extends HTMLElement {
advancedSection.appendChild(gridLayout);
advancedSection.appendChild(bottomRow);
// 添加指令列表参数表格
const cmdListSection = document.createElement('div');
cmdListSection.className = 'form-section cmd-list';
cmdListSection.style.cssText = 'border-top: 1px solid #e2e8f0; padding-top: 20px; margin-top: 20px;';
// 创建表格标题和工具栏
const cmdListHeader = document.createElement('div');
cmdListHeader.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;';
cmdListHeader.innerHTML = `
<label>指令列表 (CmdList)</label>
<button type="button" id="addCmdBtn" style="background-color: #667eea; color: white; border: none; border-radius: 4px; padding: 8px 16px; cursor: pointer;">
添加指令
</button>
`;
// 创建表格
const cmdListTable = document.createElement('table');
cmdListTable.style.cssText = 'width: 100%; border-collapse: collapse; margin-top: 10px;';
cmdListTable.innerHTML = `
<thead>
<tr style="background-color: #f8fafc;">
<th style="padding: 8px; text-align: left; border: 1px solid #e2e8f0;">名称</th>
<th style="padding: 8px; text-align: left; border: 1px solid #e2e8f0;">描述</th>
<th style="padding: 8px; text-align: left; border: 1px solid #e2e8f0;">调用函数</th>
<th style="padding: 8px; text-align: center; border: 1px solid #e2e8f0; width: 80px;">操作</th>
</tr>
</thead>
<tbody id="cmdListBody">
${this.renderCmdListRows()}
</tbody>
`;
cmdListSection.appendChild(cmdListHeader);
cmdListSection.appendChild(cmdListTable);
// 表单操作按钮
const formActions = document.createElement('div');
formActions.className = 'form-actions';
formActions.style.cssText = 'margin-top: 30px; text-align: right; border-top: 1px solid #e2e8f0; padding-top: 20px;';
formActions.innerHTML = `
<button type="submit" class="save-button">${this.isEditMode ? '保存修改' : '创建版本'}</button>
`;
// 组装表单
form.appendChild(basicInfoSection);
form.appendChild(advancedSection);
form.appendChild(cmdListSection);
form.appendChild(formActions);
formContainer.appendChild(form);
container.appendChild(formContainer);
// 为添加指令按钮添加事件监听器
setTimeout(() => {
const addCmdBtn = this.shadowRoot.querySelector('#addCmdBtn');
if (addCmdBtn) {
addCmdBtn.addEventListener('click', () => {
this.addCmdListRow();
});
}
// 为删除按钮添加事件监听器
const deleteButtons = this.shadowRoot.querySelectorAll('.delete-cmd-btn');
deleteButtons.forEach(button => {
button.addEventListener('click', (e) => {
const index = parseInt(e.target.dataset.index);
this.deleteCmdListRow(index);
});
});
}, 0);
// 为日期时间按钮添加事件监听器
setTimeout(() => {
const dateTimePickerButton = this.shadowRoot.querySelector('#dateTimePickerButton');
@ -960,11 +1042,16 @@ class ModelDevelopment extends HTMLElement {
e.preventDefault();
try {
// 显示加载提示
const saveButton = form.querySelector('.save-button');
const originalButtonText = saveButton.textContent;
saveButton.textContent = '保存中...';
saveButton.disabled = true;
const savedSelection = localStorage.getItem('xnsim-selection');
const selection = savedSelection ? JSON.parse(savedSelection) : {};
// 获取工具栏中的保存按钮
const saveButton = this.shadowRoot.querySelector('.toolbar-button:nth-child(2)');
if (saveButton) {
const originalButtonText = saveButton.textContent;
saveButton.textContent = '保存中...';
saveButton.disabled = true;
}
// 验证版本号格式
const versionInput = form.querySelector('#version');
@ -981,8 +1068,29 @@ class ModelDevelopment extends HTMLElement {
}
}
// 收集指令列表数据
const cmdList = [];
const cmdRows = this.shadowRoot.querySelectorAll('#cmdListBody tr');
cmdRows.forEach(row => {
const nameInput = row.querySelector('input[name^="cmdList"][name$=".Name"]');
const descriptionInput = row.querySelector('input[name^="cmdList"][name$=".Description"]');
const callInput = row.querySelector('input[name^="cmdList"][name$=".Call"]');
if (nameInput && descriptionInput && callInput) {
// 确保每个字段都有值,如果没有则使用空字符串
const cmd = {
"Name" : nameInput.value.trim() || "",
"Description" : descriptionInput.value.trim() || "",
"Call" : callInput.value.trim() || ""
};
cmdList.push(cmd);
}
});
// 构建版本数据
const versionData = {
PlaneName: selection.plane,
ConfID: selection.configurationId,
ClassName: form.querySelector('#className').value,
Name: form.querySelector('#name').value,
Version: form.querySelector('#version').value,
@ -997,12 +1105,13 @@ class ModelDevelopment extends HTMLElement {
DataPackageHeaderPath: form.querySelector('#dataPackageHeaderPath').value,
DataPackageEntryPoint: form.querySelector('#dataPackageEntryPoint').value,
DataPackageInterfaceName: form.querySelector('#dataPackageInterfaceName').value,
CmdList: JSON.stringify(cmdList),
isUpdate: this.isEditMode,
originalVersion: this.isEditMode ? this.currentVersion.Version : null
};
// 验证必填字段
const requiredFields = ['ClassName', 'Name', 'Version', 'Author', 'ChangeTime'];
const requiredFields = ['PlaneName', 'ConfID', 'ClassName', 'Name', 'Version', 'Author', 'ChangeTime'];
for (const field of requiredFields) {
if (!versionData[field]) {
throw new Error(`${field}是必填字段`);
@ -1021,7 +1130,7 @@ class ModelDevelopment extends HTMLElement {
alert(`保存失败: ${error.message}`);
} finally {
// 恢复按钮状态
const saveButton = form.querySelector('.save-button');
const saveButton = this.shadowRoot.querySelector('.toolbar-button:nth-child(2)');
if (saveButton) {
saveButton.textContent = this.isEditMode ? '保存修改' : '创建版本';
saveButton.disabled = false;
@ -1794,7 +1903,8 @@ class ModelDevelopment extends HTMLElement {
DataPackagePath: '',
DataPackageHeaderPath: '',
DataPackageEntryPoint: '',
DataPackageInterfaceName: ''
DataPackageInterfaceName: '',
CmdList: [] // 初始化为空数组
};
// 打开编辑界面
@ -1861,25 +1971,142 @@ class ModelDevelopment extends HTMLElement {
return `${date} ${time}`;
}
saveVersionChanges(form) {
// 收集表单数据
const formData = new FormData(form);
const updatedVersion = {};
for (const [key, value] of formData.entries()) {
updatedVersion[key] = value;
/**
* 渲染指令列表行
* @returns {string} 表格行的HTML字符串
*/
renderCmdListRows() {
if (!this.currentVersion.CmdList || !Array.isArray(this.currentVersion.CmdList) || this.currentVersion.CmdList.length === 0) {
return '<tr><td colspan="4" style="text-align: center; padding: 20px; color: #718096;">暂无指令参数</td></tr>';
}
// 确保重要字段值不变
updatedVersion.ClassName = this.currentVersion.ClassName;
return this.currentVersion.CmdList.map((cmd, index) => `
<tr>
<td style="padding: 8px; border: 1px solid #e2e8f0;">
<input type="text" class="cmd-name" value="${cmd.Name || ''}" style="width: 100%; border: none; padding: 4px;">
</td>
<td style="padding: 8px; border: 1px solid #e2e8f0;">
<input type="text" class="cmd-description" value="${cmd.Description || ''}" style="width: 100%; border: none; padding: 4px;">
</td>
<td style="padding: 8px; border: 1px solid #e2e8f0;">
<input type="text" class="cmd-call" value="${cmd.Call || ''}" style="width: 100%; border: none; padding: 4px;">
</td>
<td style="padding: 8px; border: 1px solid #e2e8f0; text-align: center;">
<button type="button" class="delete-cmd" data-index="${index}" style="background-color: #e53e3e; color: white; border: none; border-radius: 4px; padding: 4px 8px; cursor: pointer;">
删除
</button>
</td>
</tr>
`).join('');
}
/**
* 添加新的指令行
*/
addCmdListRow() {
if (!this.currentVersion.CmdList) {
this.currentVersion.CmdList = [];
}
// 在这里可以添加保存逻辑例如调用API
console.log('要保存的版本数据:', updatedVersion);
this.currentVersion.CmdList.push({
Name: '',
Description: '',
Call: ''
});
// 提示用户
alert('版本数据保存功能正在开发中...');
// 保存成功后不再自动返回版本列表,留在当前编辑页面
// 更新表格内容
const tbody = this.shadowRoot.querySelector('#cmdListBody');
if (tbody) {
// 如果当前显示的是"暂无指令参数"的提示,则清空表格
if (tbody.children.length === 1 && tbody.children[0].children.length === 1) {
tbody.innerHTML = '';
}
// 创建新的表格行
const newRow = document.createElement('tr');
// 创建指令名称输入框
const nameCell = document.createElement('td');
nameCell.style.cssText = 'padding: 8px; border: 1px solid #e2e8f0;';
const nameInput = document.createElement('input');
nameInput.type = 'text';
nameInput.className = 'cmd-name';
nameInput.style.cssText = 'width: 100%; border: none; padding: 4px;';
nameCell.appendChild(nameInput);
// 创建描述输入框
const descCell = document.createElement('td');
descCell.style.cssText = 'padding: 8px; border: 1px solid #e2e8f0;';
const descInput = document.createElement('input');
descInput.type = 'text';
descInput.className = 'cmd-description';
descInput.style.cssText = 'width: 100%; border: none; padding: 4px;';
descCell.appendChild(descInput);
// 创建调用函数输入框
const callCell = document.createElement('td');
callCell.style.cssText = 'padding: 8px; border: 1px solid #e2e8f0;';
const callInput = document.createElement('input');
callInput.type = 'text';
callInput.className = 'cmd-call';
callInput.style.cssText = 'width: 100%; border: none; padding: 4px;';
callCell.appendChild(callInput);
// 创建删除按钮
const actionCell = document.createElement('td');
actionCell.style.cssText = 'padding: 8px; border: 1px solid #e2e8f0; text-align: center;';
const deleteButton = document.createElement('button');
deleteButton.type = 'button';
deleteButton.className = 'delete-cmd';
deleteButton.dataset.index = (this.currentVersion.CmdList.length - 1).toString();
deleteButton.style.cssText = 'background-color: #e53e3e; color: white; border: none; border-radius: 4px; padding: 4px 8px; cursor: pointer;';
deleteButton.textContent = '删除';
deleteButton.addEventListener('click', (e) => {
const index = parseInt(e.target.dataset.index);
this.deleteCmdListRow(index);
});
actionCell.appendChild(deleteButton);
// 组装行
newRow.appendChild(nameCell);
newRow.appendChild(descCell);
newRow.appendChild(callCell);
newRow.appendChild(actionCell);
// 添加到表格
tbody.appendChild(newRow);
}
}
/**
* 删除指令行
* @param {number} index - 要删除的行索引
*/
deleteCmdListRow(index) {
if (this.currentVersion.CmdList && Array.isArray(this.currentVersion.CmdList)) {
this.currentVersion.CmdList.splice(index, 1);
// 更新表格内容
const tbody = this.shadowRoot.querySelector('#cmdListBody');
if (tbody) {
if (this.currentVersion.CmdList.length === 0) {
// 如果没有指令了,显示提示信息
tbody.innerHTML = '<tr><td colspan="4" style="text-align: center; padding: 20px; color: #718096;">暂无指令参数</td></tr>';
} else {
// 重新渲染所有行
tbody.innerHTML = this.renderCmdListRows();
// 重新绑定删除按钮事件
const deleteButtons = this.shadowRoot.querySelectorAll('.delete-cmd-btn');
deleteButtons.forEach(button => {
button.addEventListener('click', (e) => {
const index = parseInt(e.target.dataset.index);
this.deleteCmdListRow(index);
});
});
}
}
}
}
}

View File

@ -436,6 +436,36 @@ class ServiceDevelopment extends HTMLElement {
async saveServiceVersion(versionData) {
try {
// 确保 CmdList 和 OtherParam 是有效的 JSON 字符串
if (versionData.CmdList) {
try {
const cmdList = JSON.parse(versionData.CmdList);
if (!Array.isArray(cmdList)) {
throw new Error('CmdList 必须是数组');
}
// 验证每个命令对象的格式
cmdList.forEach(cmd => {
if (!cmd.Name || !cmd.Description || !cmd.Call) {
throw new Error('每个命令必须包含 Name、Description 和 Call 字段');
}
});
} catch (e) {
throw new Error(`CmdList 格式错误: ${e.message}`);
}
} else {
versionData.CmdList = '[]';
}
if (versionData.OtherParam) {
try {
JSON.parse(versionData.OtherParam);
} catch (e) {
throw new Error(`OtherParam 格式错误: ${e.message}`);
}
} else {
versionData.OtherParam = '{}';
}
const response = await fetch('/api/service-versions', {
method: 'POST',
headers: {
@ -725,6 +755,26 @@ class ServiceDevelopment extends HTMLElement {
showVersionEditor(versionData) {
this.currentView = 'versionEditor';
// 确保 CmdList 是有效的数组
if (versionData.CmdList) {
try {
if (typeof versionData.CmdList === 'string') {
// 如果已经是字符串,尝试解析它
const parsed = JSON.parse(versionData.CmdList);
versionData.CmdList = Array.isArray(parsed) ? parsed : [];
} else if (!Array.isArray(versionData.CmdList)) {
// 如果不是数组,初始化为空数组
versionData.CmdList = [];
}
} catch (e) {
console.error('解析 CmdList 失败:', e);
versionData.CmdList = [];
}
} else {
versionData.CmdList = [];
}
this.currentVersion = versionData;
this.isEditMode = versionData && versionData.Version ? true : false;
@ -864,6 +914,16 @@ class ServiceDevelopment extends HTMLElement {
<label for="version">版本 (Version)*</label>
<input type="text" id="version" name="Version" value="${this.currentVersion.Version || '1.0.0'}" pattern="[0-9.]+" title="版本号只能包含数字和小数点例如1.0.0" required>
</div>
`;
// 右列 - 描述和其他信息
const rightColumn = document.createElement('div');
rightColumn.className = 'form-column';
rightColumn.innerHTML = `
<div class="form-group">
<label for="description">描述 (Description)</label>
<input type="text" id="description" name="Description" value="${this.currentVersion.Description || ''}" title="服务版本的详细描述,包括主要功能和改进">
</div>
<div class="form-group">
<label for="author">作者 (Author)*</label>
<input type="text" id="author" name="Author" value="${this.currentVersion.Author || ''}" title="服务版本的作者姓名" required>
@ -884,16 +944,6 @@ class ServiceDevelopment extends HTMLElement {
</div>
`;
// 右列 - 描述和其他信息
const rightColumn = document.createElement('div');
rightColumn.className = 'form-column';
rightColumn.innerHTML = `
<div class="form-group" style="height: 100%;">
<label for="description">描述 (Description)</label>
<textarea id="description" name="Description" style="height: calc(100% - 30px);" title="服务版本的详细描述,包括主要功能和改进">${this.currentVersion.Description || ''}</textarea>
</div>
`;
basicInfoSection.appendChild(leftColumn);
basicInfoSection.appendChild(rightColumn);
@ -910,19 +960,76 @@ class ServiceDevelopment extends HTMLElement {
`;
codePathSection.appendChild(codePathGroup);
// 添加 CmdList 和 OtherParam 字段
const jsonFieldsSection = document.createElement('div');
jsonFieldsSection.className = 'form-section json-fields';
jsonFieldsSection.style.cssText = 'margin-top: 20px; border-top: 1px solid #e2e8f0; padding-top: 20px;';
// CmdList 字段
const cmdListGroup = document.createElement('div');
cmdListGroup.className = 'form-group';
// 表单操作按钮
const formActions = document.createElement('div');
formActions.className = 'form-actions';
formActions.style.cssText = 'margin-top: 30px; text-align: right; border-top: 1px solid #e2e8f0; padding-top: 20px;';
formActions.innerHTML = `
<button type="submit" class="save-button">${this.isEditMode ? '保存修改' : '创建版本'}</button>
// 确保 CmdList 是有效的 JSON 字符串
let cmdListValue = '[]';
if (this.currentVersion.CmdList) {
try {
if (typeof this.currentVersion.CmdList === 'string') {
// 如果已经是字符串,验证它是否是有效的 JSON
JSON.parse(this.currentVersion.CmdList);
cmdListValue = this.currentVersion.CmdList;
} else if (Array.isArray(this.currentVersion.CmdList)) {
// 如果是数组,转换为 JSON 字符串
cmdListValue = JSON.stringify(this.currentVersion.CmdList);
}
} catch (e) {
console.error('CmdList 格式错误:', e);
cmdListValue = '[]';
}
}
cmdListGroup.innerHTML = `
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<label>指令列表 (CmdList)</label>
<button type="button" id="addCmdBtn" style="background-color: #667eea; color: white; border: none; border-radius: 4px; padding: 8px 16px; cursor: pointer;">
添加指令
</button>
</div>
<div class="cmd-list-container">
<table id="cmdListTable" style="width: 100%; border-collapse: collapse; margin-bottom: 10px;">
<thead>
<tr style="background-color: #f8fafc;">
<th style="padding: 8px; text-align: left; border: 1px solid #e2e8f0;">名称</th>
<th style="padding: 8px; text-align: left; border: 1px solid #e2e8f0;">描述</th>
<th style="padding: 8px; text-align: left; border: 1px solid #e2e8f0;">调用函数</th>
<th style="padding: 8px; text-align: center; border: 1px solid #e2e8f0; width: 80px;">操作</th>
</tr>
</thead>
<tbody id="cmdListBody">
<tr>
<td colspan="4" style="text-align: center; padding: 20px; color: #718096;">暂无指令参数</td>
</tr>
</tbody>
</table>
</div>
<input type="hidden" id="cmdList" name="CmdList" value="${cmdListValue}">
`;
jsonFieldsSection.appendChild(cmdListGroup);
// OtherParam 字段
const otherParamGroup = document.createElement('div');
otherParamGroup.className = 'form-group';
otherParamGroup.innerHTML = `
<label for="otherParam">其他参数 (OtherParam)</label>
<textarea id="otherParam" name="OtherParam" style="height: 100px; font-family: monospace;" title="JSON字符串包含其他参数">${this.currentVersion.OtherParam || '{}'}</textarea>
<small style="display: block; margin-top: 5px; color: #718096; font-size: 12px;">请输入有效的JSON字符串例如: {"key": "value"}</small>
`;
jsonFieldsSection.appendChild(otherParamGroup);
// 组装表单
form.appendChild(basicInfoSection);
form.appendChild(codePathSection);
form.appendChild(formActions);
form.appendChild(jsonFieldsSection);
formContainer.appendChild(form);
container.appendChild(formContainer);
@ -943,17 +1050,27 @@ class ServiceDevelopment extends HTMLElement {
e.preventDefault();
try {
// 显示加载提示
const saveButton = form.querySelector('.save-button');
const originalButtonText = saveButton.textContent;
saveButton.textContent = '保存中...';
saveButton.disabled = true;
// 验证版本号格式
const versionInput = form.querySelector('#version');
if (versionInput && !/^[0-9.]+$/.test(versionInput.value)) {
throw new Error('版本号只能包含数字和小数点');
}
// 验证 CmdList 和 OtherParam 是否为有效的 JSON
const cmdListInput = form.querySelector('#cmdList');
const otherParamInput = form.querySelector('#otherParam');
try {
JSON.parse(cmdListInput.value);
} catch (e) {
throw new Error('CmdList 必须是有效的 JSON 数组字符串');
}
try {
JSON.parse(otherParamInput.value);
} catch (e) {
throw new Error('OtherParam 必须是有效的 JSON 字符串');
}
// 构建版本数据
const versionData = {
@ -964,6 +1081,8 @@ class ServiceDevelopment extends HTMLElement {
Description: form.querySelector('#description').value,
ChangeTime: form.querySelector('#changeTime').value,
CodePath: form.querySelector('#codePath').value,
CmdList: cmdListInput.value,
OtherParam: otherParamInput.value,
isUpdate: this.isEditMode,
originalVersion: this.isEditMode ? this.currentVersion.Version : null
};
@ -986,15 +1105,137 @@ class ServiceDevelopment extends HTMLElement {
this.fetchServiceVersions(this.currentService.className, this.currentService.name);
} catch (error) {
alert(`保存失败: ${error.message}`);
} finally {
// 恢复按钮状态
const saveButton = form.querySelector('.save-button');
if (saveButton) {
saveButton.textContent = this.isEditMode ? '保存修改' : '创建版本';
saveButton.disabled = false;
}
}
});
// 初始化 CmdList 表格
const cmdListBody = cmdListGroup.querySelector('#cmdListBody');
const cmdListInput = cmdListGroup.querySelector('#cmdList');
const addCmdBtn = cmdListGroup.querySelector('#addCmdBtn');
// 渲染 CmdList 表格行
const renderCmdListRows = () => {
try {
const cmdListInput = cmdListGroup.querySelector('#cmdList');
if (!cmdListInput) {
console.error('找不到 CmdList 输入元素');
return;
}
let cmdList;
try {
// 如果 currentVersion.CmdList 是数组,直接使用它
if (Array.isArray(this.currentVersion.CmdList)) {
cmdList = this.currentVersion.CmdList;
cmdListInput.value = JSON.stringify(cmdList);
} else {
// 否则尝试解析输入值
cmdList = JSON.parse(cmdListInput.value);
}
} catch (e) {
console.error('解析 CmdList 失败:', e);
cmdList = [];
cmdListInput.value = '[]';
}
if (!Array.isArray(cmdList)) {
console.error('CmdList 不是数组:', cmdList);
cmdList = [];
cmdListInput.value = '[]';
}
if (cmdList.length === 0) {
cmdListBody.innerHTML = '<tr><td colspan="4" style="text-align: center; padding: 20px; color: #718096;">暂无指令参数</td></tr>';
return;
}
cmdListBody.innerHTML = cmdList.map((cmd, index) => `
<tr>
<td style="padding: 8px; border: 1px solid #e2e8f0;">
<input type="text" class="cmd-name" value="${cmd.Name || ''}" style="width: 100%; border: none; padding: 4px;">
</td>
<td style="padding: 8px; border: 1px solid #e2e8f0;">
<input type="text" class="cmd-description" value="${cmd.Description || ''}" style="width: 100%; border: none; padding: 4px;">
</td>
<td style="padding: 8px; border: 1px solid #e2e8f0;">
<input type="text" class="cmd-call" value="${cmd.Call || ''}" style="width: 100%; border: none; padding: 4px;">
</td>
<td style="padding: 8px; border: 1px solid #e2e8f0; text-align: center;">
<button type="button" class="delete-cmd" data-index="${index}" style="background-color: #e53e3e; color: white; border: none; border-radius: 4px; padding: 4px 8px; cursor: pointer;">
删除
</button>
</td>
</tr>
`).join('');
// 添加删除按钮事件
cmdListBody.querySelectorAll('.delete-cmd').forEach(btn => {
btn.addEventListener('click', (e) => {
const index = parseInt(e.target.dataset.index);
try {
const cmdList = Array.isArray(this.currentVersion.CmdList) ?
this.currentVersion.CmdList :
JSON.parse(cmdListInput.value);
cmdList.splice(index, 1);
this.currentVersion.CmdList = cmdList;
cmdListInput.value = JSON.stringify(cmdList);
renderCmdListRows();
} catch (e) {
console.error('删除指令失败:', e);
alert('删除指令失败,请重试');
}
});
});
// 添加输入框事件
cmdListBody.querySelectorAll('input').forEach(input => {
input.addEventListener('change', () => {
try {
const cmdList = Array.isArray(this.currentVersion.CmdList) ?
this.currentVersion.CmdList :
JSON.parse(cmdListInput.value);
const row = input.closest('tr');
const index = Array.from(row.parentNode.children).indexOf(row);
const field = input.classList[0].split('-')[1];
cmdList[index][field.charAt(0).toUpperCase() + field.slice(1)] = input.value;
this.currentVersion.CmdList = cmdList;
cmdListInput.value = JSON.stringify(cmdList);
} catch (e) {
console.error('更新指令失败:', e);
alert('更新指令失败,请重试');
}
});
});
} catch (e) {
console.error('渲染指令列表失败:', e);
cmdListBody.innerHTML = '<tr><td colspan="4" style="text-align: center; padding: 20px; color: #e53e3e;">指令列表格式错误</td></tr>';
}
};
// 添加指令按钮事件
addCmdBtn.addEventListener('click', () => {
try {
let cmdList = Array.isArray(this.currentVersion.CmdList) ?
this.currentVersion.CmdList :
JSON.parse(cmdListInput.value);
// 添加新的指令
cmdList.push({ Name: '', Description: '', Call: '' });
// 更新 currentVersion 和输入框的值
this.currentVersion.CmdList = cmdList;
cmdListInput.value = JSON.stringify(cmdList);
// 重新渲染表格
renderCmdListRows();
} catch (e) {
console.error('添加指令失败:', e);
alert('添加指令失败,请检查指令列表格式');
}
});
// 初始渲染表格
renderCmdListRows();
}
/**
@ -1289,7 +1530,9 @@ class ServiceDevelopment extends HTMLElement {
Description: '',
CreatTime: this.getCurrentDateTime(),
ChangeTime: this.getCurrentDateTime(),
CodePath: ''
CodePath: '',
CmdList: [], // 初始化为空数组
OtherParam: '{}' // 初始化为空对象的 JSON 字符串
};
// 打开编辑界面

View File

@ -27,6 +27,9 @@ router.get('/chapter-models/:chapterId', (req, res) => {
if (!chapterId) {
return res.status(400).json({ error: '缺少章节ID参数' });
}
if (!planeName) {
return res.status(400).json({ error: '缺少飞机名称参数' });
}
const models = getModelsByChapterId(chapterId, planeName);
res.json(models);
@ -40,13 +43,19 @@ router.get('/chapter-models/:chapterId', (req, res) => {
router.get('/model-versions/:className', (req, res) => {
try {
const className = req.params.className;
const { planeName } = req.query;
const { planeName, confID } = req.query;
if (!className) {
return res.status(400).json({ error: '模型类名不能为空' });
}
if (!planeName) {
return res.status(400).json({ error: '飞机名称不能为空' });
}
if (!confID) {
return res.status(400).json({ error: '配置ID不能为空' });
}
const versions = getModelVersionsByClassName(className, planeName);
const versions = getModelVersionsByClassName(className, planeName, confID);
res.json(versions);
} catch (error) {
console.error(`获取模型版本失败: ${error.message}`);
@ -71,6 +80,15 @@ router.post('/model-versions', (req, res) => {
}
}
// 验证 CmdList 是否为有效的 JSON 字符串
if (versionData.CmdList !== undefined) {
try {
JSON.parse(versionData.CmdList);
} catch (e) {
return res.status(400).json({ error: 'CmdList 必须是有效的 JSON 字符串' });
}
}
const result = saveModelVersion(versionData);
res.json(result);
} catch (error) {

View File

@ -58,6 +58,23 @@ router.post('/service-versions', (req, res) => {
versionData.ServiceName = versionData.Name;
}
// 验证 CmdList 和 OtherParam 是否为有效的 JSON 字符串
if (versionData.CmdList !== undefined) {
try {
JSON.parse(versionData.CmdList);
} catch (e) {
return res.status(400).json({ error: 'CmdList 必须是有效的 JSON 字符串' });
}
}
if (versionData.OtherParam !== undefined) {
try {
JSON.parse(versionData.OtherParam);
} catch (e) {
return res.status(400).json({ error: 'OtherParam 必须是有效的 JSON 字符串' });
}
}
const result = saveServiceVersion(versionData);
res.json(result);
} catch (error) {

View File

@ -18,31 +18,24 @@ function getATAChapters() {
// 根据章节ID查询XNModels表中的模型
function getModelsByChapterId(chapterId, planeName) {
try {
// 验证必填参数
if (!chapterId) {
throw new Error('ChapterId 是必填参数');
}
if (!planeName) {
throw new Error('PlaneName 是必填参数');
}
const db = getDBConnection(true);
// 根据planeName是否为空构建不同的查询
let query;
let params;
const query = `
SELECT PlaneName, Chapters_ID, ModelName, ModelName_CN, Description, ClassName
FROM 'XNModels'
WHERE Chapters_ID = ? AND PlaneName = ?
ORDER BY ModelName
`;
if (!planeName || planeName === '' || planeName === 'undefined') {
query = `
SELECT PlaneName, Chapters_ID, ModelName, ModelName_CN, Description, ClassName
FROM 'XNModels'
WHERE Chapters_ID = ?
ORDER BY ModelName
`;
params = [chapterId];
} else {
query = `
SELECT PlaneName, Chapters_ID, ModelName, ModelName_CN, Description, ClassName
FROM 'XNModels'
WHERE Chapters_ID = ? AND PlaneName = ?
ORDER BY ModelName
`;
params = [chapterId, planeName];
}
const models = db.prepare(query).all(...params);
const models = db.prepare(query).all(chapterId, planeName);
return models;
} catch (error) {
@ -52,41 +45,33 @@ function getModelsByChapterId(chapterId, planeName) {
}
// 根据ClassName查询XNModelsVersion表中的模型版本
function getModelVersionsByClassName(className, planeName) {
function getModelVersionsByClassName(className, planeName, confID) {
try {
// 验证必填参数
if (!className) {
throw new Error('ClassName 是必填参数');
}
if (!planeName) {
throw new Error('PlaneName 是必填参数');
}
if (!confID) {
throw new Error('ConfID 是必填参数');
}
const db = getDBConnection(true);
// 根据planeName是否为空构建不同的查询
let query;
let params;
const query = `
SELECT
PlaneName, ClassName, Name, Version, CodePath, Author, Description,
CreatTime, ChangeTime, RunFreqGroup, RunNode, Priority,
DataPackagePath, DataPackageHeaderPath, DataPackageEntryPoint, DataPackageInterfaceName,
ConfID, CmdList
FROM 'XNModelsVersion'
WHERE ClassName = ? AND PlaneName = ? AND ConfID = ?
ORDER BY Version DESC
`;
if (!planeName || planeName === '') {
query = `
SELECT
PlaneName, ClassName, Name, Version, CodePath, Author, Description,
CreatTime, ChangeTime, RunFreqGroup, RunNode, Priority,
DataPackagePath, DataPackageHeaderPath, DataPackageEntryPoint, DataPackageInterfaceName,
ConfID
FROM 'XNModelsVersion'
WHERE ClassName = ?
ORDER BY Version DESC
`;
params = [className];
} else {
query = `
SELECT
PlaneName, ClassName, Name, Version, CodePath, Author, Description,
CreatTime, ChangeTime, RunFreqGroup, RunNode, Priority,
DataPackagePath, DataPackageHeaderPath, DataPackageEntryPoint, DataPackageInterfaceName,
ConfID
FROM 'XNModelsVersion'
WHERE ClassName = ? AND PlaneName = ?
ORDER BY Version DESC
`;
params = [className, planeName];
}
const versions = db.prepare(query).all(...params);
const versions = db.prepare(query).all(className, planeName, confID);
return versions;
} catch (error) {
@ -155,7 +140,8 @@ function saveModelVersion(versionData) {
DataPackageHeaderPath = ?,
DataPackageEntryPoint = ?,
DataPackageInterfaceName = ?,
ConfID = ?
ConfID = ?,
CmdList = ?
WHERE ClassName = ? AND Version = ? AND PlaneName = ?
`).run(
versionData.PlaneName,
@ -175,6 +161,7 @@ function saveModelVersion(versionData) {
versionData.DataPackageEntryPoint || '',
versionData.DataPackageInterfaceName || '',
versionData.ConfID,
versionData.CmdList || '[]',
versionData.ClassName,
versionData.originalVersion || versionData.Version,
versionData.PlaneName
@ -229,8 +216,8 @@ function saveNewVersion(db, versionData) {
PlaneName, ClassName, Name, Version, CodePath, Author, Description,
CreatTime, ChangeTime, RunFreqGroup, RunNode, Priority,
DataPackagePath, DataPackageHeaderPath, DataPackageEntryPoint, DataPackageInterfaceName,
ConfID
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ConfID, CmdList
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
versionData.PlaneName,
versionData.ClassName,
@ -248,7 +235,11 @@ function saveNewVersion(db, versionData) {
versionData.DataPackageHeaderPath || '',
versionData.DataPackageEntryPoint || '',
versionData.DataPackageInterfaceName || '',
versionData.ConfID
versionData.ConfID,
versionData.CmdList || '[]',
versionData.ClassName,
versionData.originalVersion || versionData.Version,
versionData.PlaneName
);
return {

View File

@ -27,7 +27,7 @@ function getServiceVersionsByClassName(className) {
// 查询该类名下的所有版本
const versions = db.prepare(`
SELECT ClassName, Name, Version, CodePath, Author, Description,
CreatTime, ChangeTime
CreatTime, ChangeTime, CmdList, OtherParam
FROM 'XNServiceVersion'
WHERE ClassName = ?
ORDER BY Version DESC
@ -89,7 +89,9 @@ function saveServiceVersion(versionData) {
Author = ?,
Description = ?,
CodePath = ?,
ChangeTime = ?
ChangeTime = ?,
CmdList = ?,
OtherParam = ?
WHERE ClassName = ? AND Version = ?
`).run(
versionData.Name,
@ -98,6 +100,8 @@ function saveServiceVersion(versionData) {
versionData.Description || '',
versionData.CodePath || '',
changeTime, // 使用前端传来的时间或生成的当前时间
versionData.CmdList || '[]',
versionData.OtherParam || '{}',
versionData.ClassName,
versionData.originalVersion || versionData.Version
);
@ -149,8 +153,8 @@ function saveNewServiceVersion(db, versionData) {
const insertResult = db.prepare(`
INSERT INTO 'XNServiceVersion' (
ClassName, Name, Version, CodePath, Author, Description,
CreatTime, ChangeTime
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
CreatTime, ChangeTime, CmdList, OtherParam
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
versionData.ClassName,
versionData.Name,
@ -159,7 +163,9 @@ function saveNewServiceVersion(db, versionData) {
versionData.Author,
versionData.Description || '',
createTime, // 使用前端传来的创建时间或生成的当前时间
changeTime // 使用前端传来的修改时间或生成的当前时间
changeTime, // 使用前端传来的修改时间或生成的当前时间
versionData.CmdList || '[]',
versionData.OtherParam || '{}'
);
return {