V0.32.2.250620_alpha:模型开发页面添加了结构体的对应功能
This commit is contained in:
parent
129e1459ca
commit
ba9b024cd9
Binary file not shown.
@ -310,7 +310,7 @@ class InterfaceConfig extends HTMLElement {
|
|||||||
throw new Error('请先选择构型');
|
throw new Error('请先选择构型');
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(`/api/interface/list?systemName=XNSim&confID=${selection.configurationId}`);
|
const response = await fetch(`/api/interface/list?confID=${selection.configurationId}`);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('获取数据失败');
|
throw new Error('获取数据失败');
|
||||||
}
|
}
|
||||||
|
@ -962,25 +962,56 @@ class ModelDevelopment extends HTMLElement {
|
|||||||
// 创建结构体参数标题
|
// 创建结构体参数标题
|
||||||
const structHeader = document.createElement('div');
|
const structHeader = document.createElement('div');
|
||||||
structHeader.style.cssText = 'margin-bottom: 15px;';
|
structHeader.style.cssText = 'margin-bottom: 15px;';
|
||||||
structHeader.innerHTML = '<label style="font-weight: 500; color: #333;">结构体参数</label>';
|
structHeader.innerHTML = '<label style="font-weight: 500; color: #333;">结构体对应关系</label>';
|
||||||
|
|
||||||
// 创建结构体参数网格布局
|
// 创建结构体参数网格布局
|
||||||
const structGrid = document.createElement('div');
|
const structGrid = document.createElement('div');
|
||||||
structGrid.style.cssText = 'display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;';
|
structGrid.style.cssText = 'display: grid; grid-template-columns: auto repeat(3, 1fr); gap: 20px;';
|
||||||
|
|
||||||
// 添加三个结构体输入框
|
// 添加六个下拉框,按类型分组
|
||||||
structGrid.innerHTML = `
|
structGrid.innerHTML = `
|
||||||
<div class="form-group">
|
<div class="label-column" style="display: flex; flex-direction: column; justify-content: flex-start; gap: 30px; padding-top: 30px;">
|
||||||
<label for="inputStruct">输入结构体 (InputStruct)</label>
|
<div style="font-size: 16px; color: #333; white-space: nowrap;">数据库中:</div>
|
||||||
<textarea id="inputStruct" name="InputStruct" placeholder="输入结构体JSON格式" title="模型的输入参数结构体,JSON格式" style="min-height: 80px; resize: vertical;">${this.currentVersion.InputStruct || ''}</textarea>
|
<div style="font-size: 16px; color: #333; white-space: nowrap;">头文件中:</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="struct-column">
|
||||||
<label for="outputStruct">输出结构体 (OutputStruct)</label>
|
<div class="struct-type-header" style="font-weight: 600; color: #333; margin-bottom: 10px; text-align: center;">输入</div>
|
||||||
<textarea id="outputStruct" name="OutputStruct" placeholder="输出结构体JSON格式" title="模型的输出参数结构体,JSON格式" style="min-height: 80px; resize: vertical;">${this.currentVersion.OutputStruct || ''}</textarea>
|
<div class="form-group">
|
||||||
|
<select id="inputStructMapping1" name="InputStructMapping1" title="选择输入结构体对应关系1" style="width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||||
|
<option value="">请选择...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<select id="inputStructMapping2" name="InputStructMapping2" title="选择输入结构体对应关系2" style="width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||||
|
<option value="">请选择...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="struct-column">
|
||||||
<label for="heartStruct">心跳结构体 (HeartStruct)</label>
|
<div class="struct-type-header" style="font-weight: 600; color: #333; margin-bottom: 10px; text-align: center;">输出</div>
|
||||||
<textarea id="heartStruct" name="HeartStruct" placeholder="心跳结构体JSON格式" title="模型的心跳参数结构体,JSON格式" style="min-height: 80px; resize: vertical;">${this.currentVersion.HeartStruct || ''}</textarea>
|
<div class="form-group">
|
||||||
|
<select id="outputStructMapping1" name="OutputStructMapping1" title="选择输出结构体对应关系1" style="width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||||
|
<option value="">请选择...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<select id="outputStructMapping2" name="OutputStructMapping2" title="选择输出结构体对应关系2" style="width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||||
|
<option value="">请选择...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="struct-column">
|
||||||
|
<div class="struct-type-header" style="font-weight: 600; color: #333; margin-bottom: 10px; text-align: center;">心跳</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<select id="heartStructMapping1" name="HeartStructMapping1" title="选择心跳结构体对应关系1" style="width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||||
|
<option value="">请选择...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<select id="heartStructMapping2" name="HeartStructMapping2" title="选择心跳结构体对应关系2" style="width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
||||||
|
<option value="">请选择...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -1025,8 +1056,8 @@ class ModelDevelopment extends HTMLElement {
|
|||||||
// 组装表单
|
// 组装表单
|
||||||
form.appendChild(basicInfoSection);
|
form.appendChild(basicInfoSection);
|
||||||
form.appendChild(advancedSection);
|
form.appendChild(advancedSection);
|
||||||
form.appendChild(cmdListSection);
|
|
||||||
form.appendChild(structSection);
|
form.appendChild(structSection);
|
||||||
|
form.appendChild(cmdListSection);
|
||||||
form.appendChild(formActions);
|
form.appendChild(formActions);
|
||||||
formContainer.appendChild(form);
|
formContainer.appendChild(form);
|
||||||
container.appendChild(formContainer);
|
container.appendChild(formContainer);
|
||||||
@ -1071,6 +1102,9 @@ class ModelDevelopment extends HTMLElement {
|
|||||||
this.updateRunNodeOptions();
|
this.updateRunNodeOptions();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 填充数据库中结构体下拉框
|
||||||
|
this.populateDatabaseStructDropdowns();
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// 添加表单提交事件
|
// 添加表单提交事件
|
||||||
@ -1151,6 +1185,17 @@ class ModelDevelopment extends HTMLElement {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 构建结构体映射JSON字符串
|
||||||
|
const buildStructMapping = (select1, select2) => {
|
||||||
|
const selectedOption1 = select1.selectedOptions[0];
|
||||||
|
const value2 = select2.value;
|
||||||
|
|
||||||
|
if (selectedOption1 && selectedOption1.dataset.fullname && value2) {
|
||||||
|
return JSON.stringify({ [selectedOption1.dataset.fullname]: value2 });
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
// 构建版本数据
|
// 构建版本数据
|
||||||
const versionData = {
|
const versionData = {
|
||||||
PlaneName: selection.plane,
|
PlaneName: selection.plane,
|
||||||
@ -1169,9 +1214,18 @@ class ModelDevelopment extends HTMLElement {
|
|||||||
DataPackageHeaderName: form.querySelector('#dataPackageHeaderName').value,
|
DataPackageHeaderName: form.querySelector('#dataPackageHeaderName').value,
|
||||||
DataPackageEntryPoint: form.querySelector('#dataPackageEntryPoint').value,
|
DataPackageEntryPoint: form.querySelector('#dataPackageEntryPoint').value,
|
||||||
DataPackageInterfaceName: form.querySelector('#dataPackageInterfaceName').value,
|
DataPackageInterfaceName: form.querySelector('#dataPackageInterfaceName').value,
|
||||||
InputStruct: form.querySelector('#inputStruct').value,
|
InputStruct: buildStructMapping(
|
||||||
OutputStruct: form.querySelector('#outputStruct').value,
|
form.querySelector('#inputStructMapping1'),
|
||||||
HeartStruct: form.querySelector('#heartStruct').value,
|
form.querySelector('#inputStructMapping2')
|
||||||
|
),
|
||||||
|
OutputStruct: buildStructMapping(
|
||||||
|
form.querySelector('#outputStructMapping1'),
|
||||||
|
form.querySelector('#outputStructMapping2')
|
||||||
|
),
|
||||||
|
HeartStruct: buildStructMapping(
|
||||||
|
form.querySelector('#heartStructMapping1'),
|
||||||
|
form.querySelector('#heartStructMapping2')
|
||||||
|
),
|
||||||
CmdList: JSON.stringify(cmdList),
|
CmdList: JSON.stringify(cmdList),
|
||||||
isUpdate: this.isEditMode,
|
isUpdate: this.isEditMode,
|
||||||
originalVersion: this.isEditMode ? this.currentVersion.Version : null
|
originalVersion: this.isEditMode ? this.currentVersion.Version : null
|
||||||
@ -2223,6 +2277,197 @@ class ModelDevelopment extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 填充数据库中结构体下拉框
|
||||||
|
*/
|
||||||
|
async populateDatabaseStructDropdowns() {
|
||||||
|
try {
|
||||||
|
const savedSelection = localStorage.getItem('xnsim-selection');
|
||||||
|
const selection = savedSelection ? JSON.parse(savedSelection) : {};
|
||||||
|
|
||||||
|
if (!selection.configurationId) {
|
||||||
|
console.warn('未找到构型ID,无法获取结构体列表');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const structResponse = await fetch(`/api/interface/list?confID=${selection.configurationId}`);
|
||||||
|
if (structResponse.ok) {
|
||||||
|
const structData = await structResponse.json();
|
||||||
|
|
||||||
|
// 以ModelStructName为key去重,只保留第一个全称
|
||||||
|
const uniqueMap = {};
|
||||||
|
structData.forEach(item => {
|
||||||
|
if (!uniqueMap[item.ModelStructName]) {
|
||||||
|
uniqueMap[item.ModelStructName] = `${item.SystemName}::${item.PlaneName}::${item.ATAName}::${item.ModelStructName}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const structNames = Object.keys(uniqueMap);
|
||||||
|
|
||||||
|
// 获取下拉框元素
|
||||||
|
const inputStructMapping1 = this.shadowRoot.querySelector('#inputStructMapping1');
|
||||||
|
const outputStructMapping1 = this.shadowRoot.querySelector('#outputStructMapping1');
|
||||||
|
const heartStructMapping1 = this.shadowRoot.querySelector('#heartStructMapping1');
|
||||||
|
|
||||||
|
// 填充数据库中结构体下拉框
|
||||||
|
if (inputStructMapping1) {
|
||||||
|
inputStructMapping1.innerHTML = '<option value="">请选择...</option>' +
|
||||||
|
structNames.map(name => `<option value="${name}" data-fullname="${uniqueMap[name]}">${name}</option>`).join('');
|
||||||
|
}
|
||||||
|
if (outputStructMapping1) {
|
||||||
|
outputStructMapping1.innerHTML = '<option value="">请选择...</option>' +
|
||||||
|
structNames.map(name => `<option value="${name}" data-fullname="${uniqueMap[name]}">${name}</option>`).join('');
|
||||||
|
}
|
||||||
|
if (heartStructMapping1) {
|
||||||
|
heartStructMapping1.innerHTML = '<option value="">请选择...</option>' +
|
||||||
|
structNames.map(name => `<option value="${name}" data-fullname="${uniqueMap[name]}">${name}</option>`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析数据库中存储的JSON字符串并自动选择正确的选项
|
||||||
|
this.selectStructMappingOptions();
|
||||||
|
|
||||||
|
// 检查数据包相关字段是否有值,如果有则获取结构体成员信息
|
||||||
|
const dataPackagePathInput = this.shadowRoot.querySelector('#dataPackagePath');
|
||||||
|
const dataPackageHeaderNameInput = this.shadowRoot.querySelector('#dataPackageHeaderName');
|
||||||
|
const dataPackageInterfaceNameInput = this.shadowRoot.querySelector('#dataPackageInterfaceName');
|
||||||
|
if (dataPackagePathInput && dataPackageHeaderNameInput && dataPackageInterfaceNameInput) {
|
||||||
|
|
||||||
|
const packagePath = dataPackagePathInput.value.trim();
|
||||||
|
const hearderName = dataPackageHeaderNameInput.value.trim();
|
||||||
|
const interfaceName = dataPackageInterfaceNameInput.value.trim();
|
||||||
|
|
||||||
|
if (packagePath && hearderName && interfaceName) {
|
||||||
|
const headerFilePath = packagePath + '/' + hearderName;
|
||||||
|
try {
|
||||||
|
const memberResponse = await fetch('/api/filesystem/get-struct-members', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
confName: selection.configurationName,
|
||||||
|
headerFilePath: headerFilePath,
|
||||||
|
structName: interfaceName
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (memberResponse.ok) {
|
||||||
|
const memberData = await memberResponse.json();
|
||||||
|
|
||||||
|
if (memberData.success && memberData.memberNames) {
|
||||||
|
// 获取头文件结构体下拉框
|
||||||
|
const inputStructMapping2 = this.shadowRoot.querySelector('#inputStructMapping2');
|
||||||
|
const outputStructMapping2 = this.shadowRoot.querySelector('#outputStructMapping2');
|
||||||
|
const heartStructMapping2 = this.shadowRoot.querySelector('#heartStructMapping2');
|
||||||
|
|
||||||
|
// 填充头文件中结构体下拉框
|
||||||
|
if (inputStructMapping2 && outputStructMapping2 && heartStructMapping2) {
|
||||||
|
const memberOptions = '<option value="">请选择...</option>' +
|
||||||
|
memberData.memberNames.map(member => `<option value="${member}">${member}</option>`).join('');
|
||||||
|
|
||||||
|
inputStructMapping2.innerHTML = memberOptions;
|
||||||
|
outputStructMapping2.innerHTML = memberOptions;
|
||||||
|
heartStructMapping2.innerHTML = memberOptions;
|
||||||
|
|
||||||
|
// 在填充头文件结构体下拉框后,再次解析JSON并选择选项
|
||||||
|
this.selectStructMappingOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('获取结构体成员信息失败:', memberResponse.status);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('获取结构体成员信息失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('获取接口结构体列表失败:', structResponse.status);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('填充数据库结构体下拉框失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析数据库中存储的JSON字符串并自动选择正确的选项
|
||||||
|
*/
|
||||||
|
selectStructMappingOptions() {
|
||||||
|
if (!this.currentVersion) return;
|
||||||
|
|
||||||
|
// 解析InputStruct
|
||||||
|
if (this.currentVersion.InputStruct) {
|
||||||
|
try {
|
||||||
|
const inputStructData = JSON.parse(this.currentVersion.InputStruct);
|
||||||
|
const inputStructKey = Object.keys(inputStructData)[0]; // 获取JSON对象的key
|
||||||
|
const inputStructValue = inputStructData[inputStructKey]; // 获取JSON对象的value
|
||||||
|
|
||||||
|
// 选择数据库结构体下拉框
|
||||||
|
const inputStructMapping1 = this.shadowRoot.querySelector('#inputStructMapping1');
|
||||||
|
if (inputStructMapping1) {
|
||||||
|
// 从全称中提取结构体名
|
||||||
|
const structName = inputStructKey.split('::').pop();
|
||||||
|
inputStructMapping1.value = structName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择头文件结构体下拉框
|
||||||
|
const inputStructMapping2 = this.shadowRoot.querySelector('#inputStructMapping2');
|
||||||
|
if (inputStructMapping2) {
|
||||||
|
inputStructMapping2.value = inputStructValue;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('解析InputStruct失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析OutputStruct
|
||||||
|
if (this.currentVersion.OutputStruct) {
|
||||||
|
try {
|
||||||
|
const outputStructData = JSON.parse(this.currentVersion.OutputStruct);
|
||||||
|
const outputStructKey = Object.keys(outputStructData)[0];
|
||||||
|
const outputStructValue = outputStructData[outputStructKey];
|
||||||
|
|
||||||
|
// 选择数据库结构体下拉框
|
||||||
|
const outputStructMapping1 = this.shadowRoot.querySelector('#outputStructMapping1');
|
||||||
|
if (outputStructMapping1) {
|
||||||
|
const structName = outputStructKey.split('::').pop();
|
||||||
|
outputStructMapping1.value = structName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择头文件结构体下拉框
|
||||||
|
const outputStructMapping2 = this.shadowRoot.querySelector('#outputStructMapping2');
|
||||||
|
if (outputStructMapping2) {
|
||||||
|
outputStructMapping2.value = outputStructValue;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('解析OutputStruct失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析HeartStruct
|
||||||
|
if (this.currentVersion.HeartStruct) {
|
||||||
|
try {
|
||||||
|
const heartStructData = JSON.parse(this.currentVersion.HeartStruct);
|
||||||
|
const heartStructKey = Object.keys(heartStructData)[0];
|
||||||
|
const heartStructValue = heartStructData[heartStructKey];
|
||||||
|
|
||||||
|
// 选择数据库结构体下拉框
|
||||||
|
const heartStructMapping1 = this.shadowRoot.querySelector('#heartStructMapping1');
|
||||||
|
if (heartStructMapping1) {
|
||||||
|
const structName = heartStructKey.split('::').pop();
|
||||||
|
heartStructMapping1.value = structName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择头文件结构体下拉框
|
||||||
|
const heartStructMapping2 = this.shadowRoot.querySelector('#heartStructMapping2');
|
||||||
|
if (heartStructMapping2) {
|
||||||
|
heartStructMapping2.value = heartStructValue;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('解析HeartStruct失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传数据包模型
|
* 上传数据包模型
|
||||||
*/
|
*/
|
||||||
@ -2350,6 +2595,18 @@ class ModelDevelopment extends HTMLElement {
|
|||||||
dataPackageInterfaceNameInput.value = result.paramType;
|
dataPackageInterfaceNameInput.value = result.paramType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//将结构体名称填入对应下拉框的候选列表
|
||||||
|
const inputStructMapping2 = this.shadowRoot.querySelector('#inputStructMapping2');
|
||||||
|
const outputStructMapping2 = this.shadowRoot.querySelector('#outputStructMapping2');
|
||||||
|
const heartStructMapping2 = this.shadowRoot.querySelector('#heartStructMapping2');
|
||||||
|
|
||||||
|
// 填充头文件中结构体下拉框
|
||||||
|
if (inputStructMapping2 && outputStructMapping2 && heartStructMapping2) {
|
||||||
|
inputStructMapping2.innerHTML = '<option value="">请选择...</option>' + result.memberNames.map(name => `<option value="${name}">${name}</option>`).join('');
|
||||||
|
outputStructMapping2.innerHTML = '<option value="">请选择...</option>' + result.memberNames.map(name => `<option value="${name}">${name}</option>`).join('');
|
||||||
|
heartStructMapping2.innerHTML = '<option value="">请选择...</option>' + result.memberNames.map(name => `<option value="${name}">${name}</option>`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
alert(`数据包上传成功!\n数据包路径: ${result.packagePath}\n头文件: ${result.headerFile}\n动态库文件: ${result.libraryFile}\n入口点: ${result.entryPoint}\n参数类型: ${result.paramType}`);
|
alert(`数据包上传成功!\n数据包路径: ${result.packagePath}\n头文件: ${result.headerFile}\n动态库文件: ${result.libraryFile}\n入口点: ${result.entryPoint}\n参数类型: ${result.paramType}`);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(result.message || '上传失败');
|
throw new Error(result.message || '上传失败');
|
||||||
|
@ -488,14 +488,6 @@ router.get('/download', async (req, res) => {
|
|||||||
// 上传数据包文件夹
|
// 上传数据包文件夹
|
||||||
router.post('/upload-package', packageUpload.array('files'), async (req, res) => {
|
router.post('/upload-package', packageUpload.array('files'), async (req, res) => {
|
||||||
try {
|
try {
|
||||||
console.log('接收到的请求体:', req.body);
|
|
||||||
console.log('接收到的文件:', req.files ? req.files.map(f => f.originalname) : '无文件');
|
|
||||||
console.log('文件详细信息:', req.files ? req.files.map(f => ({
|
|
||||||
originalname: f.originalname,
|
|
||||||
webkitRelativePath: f.webkitRelativePath,
|
|
||||||
fieldname: f.fieldname
|
|
||||||
})) : '无文件');
|
|
||||||
|
|
||||||
const { confName } = req.body;
|
const { confName } = req.body;
|
||||||
const { folderName } = req.body; // 从前端获取文件夹名称
|
const { folderName } = req.body; // 从前端获取文件夹名称
|
||||||
|
|
||||||
@ -697,6 +689,23 @@ router.post('/upload-package', packageUpload.array('files'), async (req, res) =>
|
|||||||
// 不阻止上传流程,只记录警告
|
// 不阻止上传流程,只记录警告
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let memberNames = [];
|
||||||
|
// 如果获取到了入口点函数信息,尝试从头文件中查找对应的结构体定义
|
||||||
|
if (entryPointInfo && entryPointInfo.paramType) {
|
||||||
|
try {
|
||||||
|
const headerFile = uploadedFiles.find(file => file.type === 'header');
|
||||||
|
if (headerFile) {
|
||||||
|
const headerFilePath = path.join(targetPackagePath, headerFile.path);
|
||||||
|
const structMemberNames = await findStructDefinition(headerFilePath, entryPointInfo.paramType);
|
||||||
|
if (structMemberNames) {
|
||||||
|
memberNames = structMemberNames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('查找结构体定义失败:', error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 返回上传结果
|
// 返回上传结果
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
@ -705,7 +714,8 @@ router.post('/upload-package', packageUpload.array('files'), async (req, res) =>
|
|||||||
headerFile: path.basename(fileTypes.headerFiles[0].originalname),
|
headerFile: path.basename(fileTypes.headerFiles[0].originalname),
|
||||||
libraryFile: path.basename(fileTypes.libraryFiles[0].originalname),
|
libraryFile: path.basename(fileTypes.libraryFiles[0].originalname),
|
||||||
entryPoint: entryPointInfo ? entryPointInfo.symbolName : null,
|
entryPoint: entryPointInfo ? entryPointInfo.symbolName : null,
|
||||||
paramType: entryPointInfo ? entryPointInfo.paramType : null
|
paramType: entryPointInfo ? entryPointInfo.paramType : null,
|
||||||
|
memberNames: memberNames
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -765,7 +775,6 @@ async function getEntryPointInfo(libraryPath) {
|
|||||||
paramType: paramType
|
paramType: paramType
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('动态库入口点信息:', entryPoint);
|
|
||||||
return entryPoint;
|
return entryPoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -778,4 +787,157 @@ async function getEntryPointInfo(libraryPath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找指定结构体的定义并返回其成员信息
|
||||||
|
* @param {string} headerFilePath - 头文件路径
|
||||||
|
* @param {string} structName - 要查找的结构体名称
|
||||||
|
* @returns {Promise<Array<string>>} 结构体成员信息数组,格式为"type memberName"
|
||||||
|
*/
|
||||||
|
async function findStructDefinition(headerFilePath, structName) {
|
||||||
|
try {
|
||||||
|
// 检查文件是否存在
|
||||||
|
await fsPromises.access(headerFilePath);
|
||||||
|
|
||||||
|
// 读取头文件内容
|
||||||
|
const content = await fsPromises.readFile(headerFilePath, 'utf8');
|
||||||
|
|
||||||
|
// 移除注释,避免干扰解析
|
||||||
|
const contentWithoutComments = content
|
||||||
|
// 移除单行注释
|
||||||
|
.replace(/\/\/.*$/gm, '')
|
||||||
|
// 移除多行注释
|
||||||
|
.replace(/\/\*[\s\S]*?\*\//g, '');
|
||||||
|
|
||||||
|
// 构建查找结构体定义的正则表达式
|
||||||
|
// 匹配以下格式:
|
||||||
|
// struct StructName {
|
||||||
|
// struct StructName{
|
||||||
|
// typedef struct StructName {
|
||||||
|
// typedef struct StructName{
|
||||||
|
const structPattern = new RegExp(
|
||||||
|
`(?:typedef\\s+)?struct\\s+${structName}\\s*\\{([\\s\\S]*?)\\}\\s*;?`,
|
||||||
|
'g'
|
||||||
|
);
|
||||||
|
|
||||||
|
const memberNames = [];
|
||||||
|
let match;
|
||||||
|
|
||||||
|
while ((match = structPattern.exec(contentWithoutComments)) !== null) {
|
||||||
|
const structBody = match[1];
|
||||||
|
// 按行分割结构体内容
|
||||||
|
const lines = structBody.split('\n');
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const trimmedLine = line.trim();
|
||||||
|
|
||||||
|
// 跳过空行和只包含分号的行
|
||||||
|
if (!trimmedLine || trimmedLine === ';') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配成员声明
|
||||||
|
// 基础类型: int, double, float, char, short, long, unsigned, etc.
|
||||||
|
// 结构体指针: struct xxx_S*
|
||||||
|
// 结构体: struct xxx_S
|
||||||
|
const memberRegex = /^(?:const\s+)?(?:struct\s+([A-Za-z_][A-Za-z0-9_]*)\s*)?(?:unsigned\s+)?(?:long\s+)?(?:int\s+)?(?:char\s+)?(?:short\s+)?(?:float\s+)?(?:double\s+)?(?:void\s*)?(?:[A-Za-z_][A-Za-z0-9_]*\s*)?(\*?)\s*([A-Za-z_][A-Za-z0-9_]*)\s*(?:\[[^\]]*\])?\s*;?\s*$/;
|
||||||
|
|
||||||
|
const memberMatch = trimmedLine.match(memberRegex);
|
||||||
|
if (memberMatch) {
|
||||||
|
const structType = memberMatch[1]; // 结构体类型名
|
||||||
|
const isPointer = memberMatch[2]; // 是否为指针
|
||||||
|
const memberName = memberMatch[3]; // 成员名
|
||||||
|
|
||||||
|
// 构建类型信息
|
||||||
|
let type = '';
|
||||||
|
if (structType) {
|
||||||
|
// 结构体类型
|
||||||
|
type = `struct ${structType}${isPointer ? '*' : ''}`;
|
||||||
|
} else {
|
||||||
|
// 基础类型,需要从原始行中提取
|
||||||
|
const typeMatch = trimmedLine.match(/^(?:const\s+)?(?:unsigned\s+)?(?:long\s+)?(?:int\s+)?(?:char\s+)?(?:short\s+)?(?:float\s+)?(?:double\s+)?(?:void\s*)?(?:[A-Za-z_][A-Za-z0-9_]*\s*)?/);
|
||||||
|
if (typeMatch) {
|
||||||
|
type = typeMatch[0].trim() + (isPointer ? '*' : '');
|
||||||
|
} else {
|
||||||
|
type = 'unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拼接类型和成员名
|
||||||
|
const memberString = `${type} ${memberName}`;
|
||||||
|
memberNames.push(memberString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return memberNames;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`查找结构体 ${structName} 定义失败:`, error.message);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据构型名、头文件路径和结构体名获取结构体成员信息
|
||||||
|
*/
|
||||||
|
router.post('/get-struct-members', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { confName, headerFilePath, structName } = req.body;
|
||||||
|
|
||||||
|
if (!confName) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: '未提供构型名称'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!headerFilePath) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: '未提供头文件路径'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!structName) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: '未提供结构体名称'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取数据包路径
|
||||||
|
const { getPackagesPath } = require('../utils/file-utils');
|
||||||
|
const packagesPath = getPackagesPath(confName);
|
||||||
|
|
||||||
|
if (!packagesPath) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: '无法获取数据包路径'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装完整的头文件路径
|
||||||
|
const fullHeaderFilePath = path.join(packagesPath, headerFilePath);
|
||||||
|
|
||||||
|
// 调用findStructDefinition函数获取结构体成员信息
|
||||||
|
const memberNames = await findStructDefinition(fullHeaderFilePath, structName);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
confName: confName,
|
||||||
|
structName: structName,
|
||||||
|
headerFilePath: headerFilePath,
|
||||||
|
fullHeaderFilePath: fullHeaderFilePath,
|
||||||
|
memberNames: memberNames,
|
||||||
|
count: memberNames.length
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取结构体成员信息失败:', error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: '获取结构体成员信息失败: ' + error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
@ -30,11 +30,11 @@ async function ensureDataDirectory() {
|
|||||||
// 获取接口列表
|
// 获取接口列表
|
||||||
router.get('/list', async (req, res) => {
|
router.get('/list', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { systemName, confID } = req.query;
|
const { confID } = req.query;
|
||||||
if (!confID) {
|
if (!confID) {
|
||||||
return res.status(400).json({ error: 'ConfID 是必填字段' });
|
return res.status(400).json({ error: 'ConfID 是必填字段' });
|
||||||
}
|
}
|
||||||
const interfaces = await getDataInterfaces(systemName, confID);
|
const interfaces = await getDataInterfaces(confID);
|
||||||
res.json(interfaces);
|
res.json(interfaces);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取接口列表失败:', error);
|
console.error('获取接口列表失败:', error);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const { getDBConnection } = require('./file-utils');
|
const { getDBConnection } = require('./file-utils');
|
||||||
|
|
||||||
// 获取接口列表
|
// 获取接口列表
|
||||||
function getDataInterfaces(systemName = 'XNSim', confID) {
|
function getDataInterfaces(confID) {
|
||||||
try {
|
try {
|
||||||
if (!confID) {
|
if (!confID) {
|
||||||
throw new Error('ConfID 是必填字段');
|
throw new Error('ConfID 是必填字段');
|
||||||
@ -11,6 +11,8 @@ function getDataInterfaces(systemName = 'XNSim', confID) {
|
|||||||
|
|
||||||
const tableName = `DataInterface_${confID}`;
|
const tableName = `DataInterface_${confID}`;
|
||||||
|
|
||||||
|
const systemName = 'XNSim'
|
||||||
|
|
||||||
// 查询所有接口
|
// 查询所有接口
|
||||||
const query = `
|
const query = `
|
||||||
SELECT SystemName, PlaneName, ATAName, ModelStructName, InterfaceName,
|
SELECT SystemName, PlaneName, ATAName, ModelStructName, InterfaceName,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user