V0.28.0.250618_alpha:接口配置页面增加了代码生成功能

This commit is contained in:
jinchao 2025-06-18 16:01:06 +08:00
parent b0c49a7d8c
commit b5d163be94
12 changed files with 691 additions and 159 deletions

Binary file not shown.

View File

@ -84,7 +84,8 @@ std::string GenIDL::generateIDLContent(const AllInterfaceData &interfaceData)
bool GenIDL::generateIDL(const AllInterfaceData &interfaceData)
{
if (GenIDL::idlFilePath.empty()) {
if (GenIDL::idlFilePath.empty() || interfaceData.systemName.empty()
|| interfaceData.planeName.empty() || interfaceData.ataInterfaceData.empty()) {
return false;
}

View File

@ -27,6 +27,11 @@ public:
*/
static bool createConfigDirectory(const std::string &configName);
/**
* @brief IDL文件路径
*/
static void clearIDLFilePath() { idlFilePath = ""; }
private:
/**
* @brief IDL文件内容

View File

@ -18,104 +18,12 @@ static int safe_stoi(const std::string &str, int defaultValue = 0)
}
}
/**
* @brief
* @param data
* @param argc
* @param argv
* @param azColName
* @return 0
*/
static int callback(void *data, int argc, char **argv, char **azColName)
{
if (!data || !argv || !azColName) {
return 0;
}
auto *allData = static_cast<AllInterfaceData *>(data);
static bool isFirstRecord = true;
std::string currentSystemName;
std::string currentPlaneName;
std::string currentATAName;
std::string currentModelStructName;
InterfaceData currentInterfaceData;
//先把数据都读出来
for (int i = 0; i < argc; i++) {
std::string colName = azColName[i];
std::string value = argv[i] ? argv[i] : "";
if (colName == "SystemName") {
currentSystemName = value;
} else if (colName == "PlaneName") {
currentPlaneName = value;
} else if (colName == "ATAName") {
currentATAName = value;
} else if (colName == "ModelStructName") {
currentModelStructName = value;
} else if (colName == "InterfaceName") {
currentInterfaceData.interfaceName = value;
} else if (colName == "InterfaceType") {
currentInterfaceData.interfaceType = value;
} else if (colName == "InterfaceIsArray") {
currentInterfaceData.interfaceIsArray = safe_stoi(value);
} else if (colName == "InterfaceArraySize_1") {
currentInterfaceData.interfaceArraySize_1 = safe_stoi(value);
} else if (colName == "InterfaceArraySize_2") {
currentInterfaceData.interfaceArraySize_2 = safe_stoi(value);
} else if (colName == "InterfaceNotes") {
currentInterfaceData.interfaceNotes = value;
}
}
// 如果是第一条记录,初始化系统名称和飞机名称
if (isFirstRecord) {
allData->systemName = currentSystemName;
allData->planeName = currentPlaneName;
isFirstRecord = false;
}
// 检查系统名称和飞机名称是否匹配
if (currentSystemName != allData->systemName || currentPlaneName != allData->planeName) {
return 0;
}
//检查ATA是否已存在
for (auto &ata : allData->ataInterfaceData) {
if (ata.ataName == currentATAName) {
for (auto &structData : ata.structInterfaceData) {
if (structData.modelStructName == currentModelStructName) {
for (auto &interfaceData : structData.interfaceData) {
if (interfaceData.interfaceName == currentInterfaceData.interfaceName) {
return 0;
}
}
structData.interfaceData.push_back(currentInterfaceData);
return 0;
}
}
StructInterfaceData structData;
structData.modelStructName = currentModelStructName;
structData.interfaceData.push_back(currentInterfaceData);
ata.structInterfaceData.push_back(structData);
return 0;
}
}
ATAInterfaceData ataData;
ataData.ataName = currentATAName;
StructInterfaceData structData;
structData.modelStructName = currentModelStructName;
structData.interfaceData.push_back(currentInterfaceData);
ataData.structInterfaceData.push_back(structData);
allData->ataInterfaceData.push_back(ataData);
return 0;
}
/**
* @brief
* @param tableName
* @return
*/
AllInterfaceData GetInterfaceData::getInterfaceData(const std::string &tableName,
std::string &errorMsg)
AllInterfaceData GetInterfaceData::getInterfaceData(int configrationID, std::string &errorMsg)
{
AllInterfaceData allData;
std::string dbPath = GetXNCoreEnv() + "/database/XNSim.db";
@ -126,19 +34,144 @@ AllInterfaceData GetInterfaceData::getInterfaceData(const std::string &tableName
return allData;
}
char *errMsg = nullptr;
std::string tableName = "DataInterface_" + std::to_string(configrationID);
std::string sql = "SELECT * FROM " + tableName;
std::string sql = "SELECT * FROM " + tableName;
rc = sqlite3_exec(db, sql.c_str(), callback, &allData, &errMsg);
sqlite3_stmt *stmt = nullptr;
rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
std::string error = errMsg;
sqlite3_free(errMsg);
errorMsg = "SQL错误: " + error;
errorMsg = "SQL预处理失败: " + std::string(sqlite3_errmsg(db));
sqlite3_close(db);
return allData;
}
while (sqlite3_step(stmt) == SQLITE_ROW) {
std::string currentSystemName;
std::string currentPlaneName;
std::string currentATAName;
std::string currentModelStructName;
InterfaceData currentInterfaceData;
int colCount = sqlite3_column_count(stmt);
for (int i = 0; i < colCount; ++i) {
const char *colName = sqlite3_column_name(stmt, i);
if (!colName)
continue;
std::string value = (const char *)sqlite3_column_text(stmt, i);
if (strcmp(colName, "SystemName") == 0) {
currentSystemName = value;
} else if (strcmp(colName, "PlaneName") == 0) {
currentPlaneName = value;
} else if (strcmp(colName, "ATAName") == 0) {
currentATAName = value;
} else if (strcmp(colName, "ModelStructName") == 0) {
currentModelStructName = value;
} else if (strcmp(colName, "InterfaceName") == 0) {
currentInterfaceData.interfaceName = value;
} else if (strcmp(colName, "InterfaceType") == 0) {
currentInterfaceData.interfaceType = value;
} else if (strcmp(colName, "InterfaceIsArray") == 0) {
currentInterfaceData.interfaceIsArray = safe_stoi(value);
} else if (strcmp(colName, "InterfaceArraySize_1") == 0) {
currentInterfaceData.interfaceArraySize_1 = safe_stoi(value);
} else if (strcmp(colName, "InterfaceArraySize_2") == 0) {
currentInterfaceData.interfaceArraySize_2 = safe_stoi(value);
} else if (strcmp(colName, "InterfaceNotes") == 0) {
currentInterfaceData.interfaceNotes = value;
}
}
// 初始化systemName和planeName
if (allData.systemName.empty()) {
allData.systemName = currentSystemName;
allData.planeName = currentPlaneName;
}
// 检查systemName和planeName是否匹配
if (currentSystemName != allData.systemName || currentPlaneName != allData.planeName) {
continue;
}
// 检查ATA是否已存在
bool ataFound = false;
for (auto &ata : allData.ataInterfaceData) {
if (ata.ataName == currentATAName) {
bool structFound = false;
for (auto &structData : ata.structInterfaceData) {
if (structData.modelStructName == currentModelStructName) {
bool interfaceFound = false;
for (auto &interfaceData : structData.interfaceData) {
if (interfaceData.interfaceName == currentInterfaceData.interfaceName) {
interfaceFound = true;
break;
}
}
if (!interfaceFound) {
structData.interfaceData.push_back(currentInterfaceData);
}
structFound = true;
break;
}
}
if (!structFound) {
StructInterfaceData structData;
structData.modelStructName = currentModelStructName;
structData.interfaceData.push_back(currentInterfaceData);
ata.structInterfaceData.push_back(structData);
}
ataFound = true;
break;
}
}
if (!ataFound) {
ATAInterfaceData ataData;
ataData.ataName = currentATAName;
StructInterfaceData structData;
structData.modelStructName = currentModelStructName;
structData.interfaceData.push_back(currentInterfaceData);
ataData.structInterfaceData.push_back(structData);
allData.ataInterfaceData.push_back(ataData);
}
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return allData;
}
std::string GetInterfaceData::getConfigName(int configrationID, std::string &errorMsg)
{
std::string dbPath = GetXNCoreEnv() + "/database/XNSim.db";
sqlite3 *db = nullptr;
std::string confName;
int rc = sqlite3_open(dbPath.c_str(), &db);
if (rc != SQLITE_OK) {
errorMsg = "无法打开数据库: " + std::string(sqlite3_errmsg(db));
return "";
}
std::string sql = "SELECT ConfName FROM Configuration WHERE ConfID = ?";
sqlite3_stmt *stmt = nullptr;
rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
errorMsg = "SQL预处理失败: " + std::string(sqlite3_errmsg(db));
sqlite3_close(db);
return "";
}
sqlite3_bind_int(stmt, 1, configrationID);
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) {
const unsigned char *text = sqlite3_column_text(stmt, 0);
if (text) {
confName = reinterpret_cast<const char *>(text);
}
} else if (rc != SQLITE_DONE) {
errorMsg = "SQL执行失败: " + std::string(sqlite3_errmsg(db));
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return confName;
}

View File

@ -13,5 +13,12 @@ public:
* @param tableName
* @return
*/
static AllInterfaceData getInterfaceData(const std::string &tableName, std::string &errorMsg);
static AllInterfaceData getInterfaceData(int configrationID, std::string &errorMsg);
/**
* @brief
* @param configrationID ID
* @return
*/
static std::string getConfigName(int configrationID, std::string &errorMsg);
};

View File

@ -4,6 +4,5 @@
std::string GetXNCoreEnv()
{
const char *env_value = std::getenv("XNCore");
std::cout << "XNCore: " << env_value << std::endl;
return env_value ? env_value : "";
}

View File

@ -6,95 +6,121 @@
#include "CMakeListsGen.h"
// 全局变量定义
std::string g_tableName;
int g_configrationID;
std::string g_configName;
char *g_errorMsg;
int g_errorMsgSize;
AllInterfaceData g_interfaceData;
bool XNInterfaceGen_Step1_InitParams(const char *tableName, const int tableNameSize,
const char *configName, const int configNameSize,
const char *errorMsg, const int errorMsgSize)
int XNInterfaceGen_Step1_InitParams(int configrationID, const char *errorMsg,
const int errorMsgSize)
{
g_tableName = std::string(tableName, tableNameSize);
g_configName = std::string(configName, configNameSize);
g_errorMsg = const_cast<char *>(errorMsg);
g_errorMsgSize = errorMsgSize;
return true;
g_configrationID = 0;
g_configName = "";
g_interfaceData.systemName = "";
g_interfaceData.planeName = "";
g_interfaceData.ataInterfaceData.clear();
GenIDL::clearIDLFilePath();
if (configrationID <= 0) {
memcpy((void *)errorMsg, "Invalid configrationID", errorMsgSize);
return -1;
}
g_configrationID = configrationID;
memcpy((void *)errorMsg, "Init params success", errorMsgSize);
return 0;
}
bool XNInterfaceGen_Step2_GetInterfaceData()
int XNInterfaceGen_Step2_GetInterfaceData(const char *errorMsg, const int errorMsgSize)
{
std::string errorMsgStr;
g_interfaceData = GetInterfaceData::getInterfaceData(g_tableName, errorMsgStr);
g_interfaceData = GetInterfaceData::getInterfaceData(g_configrationID, errorMsgStr);
g_configName = GetInterfaceData::getConfigName(g_configrationID, errorMsgStr);
if (!errorMsgStr.empty()) {
memcpy(g_errorMsg, errorMsgStr.c_str(), g_errorMsgSize);
return false;
std::cout << "errorMsgStr: " << errorMsgStr << std::endl;
memcpy((void *)errorMsg, errorMsgStr.c_str(), errorMsgSize);
return -1;
}
return true;
return 0;
}
bool XNInterfaceGen_Step3_CreateConfigDir()
int XNInterfaceGen_Step3_CreateConfigDir(const char *errorMsg, const int errorMsgSize)
{
bool ret = GenIDL::createConfigDirectory(g_configName);
if (!ret) {
memcpy(g_errorMsg, "Create config directory failed", g_errorMsgSize);
return false;
std::cout << "Create config directory failed" << std::endl;
memcpy((void *)errorMsg, "Create config directory failed", errorMsgSize);
return -1;
}
return true;
return 0;
}
bool XNInterfaceGen_Step4_GenerateIDL()
int XNInterfaceGen_Step4_GenerateIDL(const char *errorMsg, const int errorMsgSize)
{
bool ret = GenIDL::generateIDL(g_interfaceData);
if (!ret) {
memcpy(g_errorMsg, "Generate IDL failed", g_errorMsgSize);
return false;
std::cout << "Generate IDL failed" << std::endl;
memcpy((void *)errorMsg, "Generate IDL failed", errorMsgSize);
return -1;
}
return true;
return 0;
}
bool XNInterfaceGen_Step5_GenerateFastDDS()
int XNInterfaceGen_Step5_GenerateFastDDS(const char *errorMsg, const int errorMsgSize)
{
bool ret = FastDDSGen::generateFastDDSCode(GenIDL::getIDLFilePath());
if (!ret) {
memcpy(g_errorMsg, "Generate FastDDS code failed", g_errorMsgSize);
return false;
std::cout << "Generate FastDDS code failed" << std::endl;
memcpy((void *)errorMsg, "Generate FastDDS code failed", errorMsgSize);
return -1;
}
return true;
return 0;
}
bool XNInterfaceGen_Step6_GenerateDDSInterface()
int XNInterfaceGen_Step6_GenerateDDSInterface(const char *errorMsg, const int errorMsgSize)
{
DDSInterfaceGen ddsInterfaceGen(GenIDL::getIDLFilePath());
bool ret = ddsInterfaceGen.generateDDSInterface(g_interfaceData);
if (!ret) {
memcpy(g_errorMsg, "Generate DDS interface failed", g_errorMsgSize);
return false;
std::cout << "Generate DDS interface failed" << std::endl;
memcpy((void *)errorMsg, "Generate DDS interface failed", errorMsgSize);
return -1;
}
return true;
return 0;
}
bool XNInterfaceGen_Step7_GenerateCMakeLists()
int XNInterfaceGen_Step7_GenerateCMakeLists(const char *errorMsg, const int errorMsgSize)
{
bool ret =
CMakeListsGen::generateCMakeLists(g_interfaceData, GenIDL::getIDLFilePath(), g_configName);
if (!ret) {
memcpy(g_errorMsg, "Generate CMakeLists.txt failed", g_errorMsgSize);
return false;
std::cout << "Generate CMakeLists.txt failed" << std::endl;
memcpy((void *)errorMsg, "Generate CMakeLists.txt failed", errorMsgSize);
return -1;
}
return true;
return 0;
}
bool XNInterfaceGen_Step8_BuildAndInstall()
int XNInterfaceGen_Step8_BuildAndInstall(const char *errorMsg, const int errorMsgSize)
{
std::string idlDirPath = fs::path(GenIDL::getIDLFilePath()).parent_path().string();
std::string buildCmd =
"cd " + idlDirPath + " && mkdir -p build && cd build && cmake .. && make && make install";
int buildRet = system(buildCmd.c_str());
if (buildRet != 0) {
memcpy(g_errorMsg, "CMake build or install failed", g_errorMsgSize);
return false;
std::cout << "CMake build or install failed" << std::endl;
memcpy((void *)errorMsg, "CMake build or install failed", errorMsgSize);
return -1;
}
return true;
return 0;
}
int XNInterfaceGen_Step9_SudoLdconfig(const char *errorMsg, const int errorMsgSize)
{
std::string ldconfigCmd = "sudo ldconfig";
int ldconfigRet = system(ldconfigCmd.c_str());
if (ldconfigRet != 0) {
std::cout << "Sudo ldconfig failed" << std::endl;
memcpy((void *)errorMsg, "Sudo ldconfig failed", errorMsgSize);
return -1;
}
return 0;
}

View File

@ -5,23 +5,27 @@
#include "PublicDefine.h"
// 全局变量声明
extern std::string g_tableName;
extern int g_configrationID;
extern std::string g_configName;
extern char *g_errorMsg;
extern int g_errorMsgSize;
extern AllInterfaceData g_interfaceData;
// 步骤函数声明
extern "C" XNIGS_EXPORT bool
XNInterfaceGen_Step1_InitParams(const char *tableName, const int tableNameSize,
const char *configName, const int configNameSize,
const char *errorMsg, const int errorMsgSize);
extern "C" XNIGS_EXPORT bool XNInterfaceGen_Step2_GetInterfaceData();
extern "C" XNIGS_EXPORT bool XNInterfaceGen_Step3_CreateConfigDir();
extern "C" XNIGS_EXPORT bool XNInterfaceGen_Step4_GenerateIDL();
extern "C" XNIGS_EXPORT bool XNInterfaceGen_Step5_GenerateFastDDS();
extern "C" XNIGS_EXPORT bool XNInterfaceGen_Step6_GenerateDDSInterface();
extern "C" XNIGS_EXPORT bool XNInterfaceGen_Step7_GenerateCMakeLists();
extern "C" XNIGS_EXPORT bool XNInterfaceGen_Step8_BuildAndInstall();
extern "C" XNIGS_EXPORT int
XNInterfaceGen_Step1_InitParams(int configrationID, const char *errorMsg, const int errorMsgSize);
extern "C" XNIGS_EXPORT int XNInterfaceGen_Step2_GetInterfaceData(const char *errorMsg,
const int errorMsgSize);
extern "C" XNIGS_EXPORT int XNInterfaceGen_Step3_CreateConfigDir(const char *errorMsg,
const int errorMsgSize);
extern "C" XNIGS_EXPORT int XNInterfaceGen_Step4_GenerateIDL(const char *errorMsg,
const int errorMsgSize);
extern "C" XNIGS_EXPORT int XNInterfaceGen_Step5_GenerateFastDDS(const char *errorMsg,
const int errorMsgSize);
extern "C" XNIGS_EXPORT int XNInterfaceGen_Step6_GenerateDDSInterface(const char *errorMsg,
const int errorMsgSize);
extern "C" XNIGS_EXPORT int XNInterfaceGen_Step7_GenerateCMakeLists(const char *errorMsg,
const int errorMsgSize);
extern "C" XNIGS_EXPORT int XNInterfaceGen_Step8_BuildAndInstall(const char *errorMsg,
const int errorMsgSize);
extern "C" XNIGS_EXPORT int XNInterfaceGen_Step9_SudoLdconfig(const char *errorMsg,
const int errorMsgSize);
#endif // XN_INTERFACE_GEN_SERVER_H

View File

@ -63,6 +63,7 @@ class InterfaceToolbar extends HTMLElement {
const addBtn = this.shadowRoot.querySelector('.add-btn');
const deleteBtn = this.shadowRoot.querySelector('.delete-btn');
const importBtn = this.shadowRoot.querySelector('.import-btn');
const codegenBtn = this.shadowRoot.querySelector('.codegen-btn');
const searchInput = this.shadowRoot.querySelector('.search-input');
const searchBtn = this.shadowRoot.querySelector('.search-btn');
const resetBtn = this.shadowRoot.querySelector('.reset-btn');
@ -87,6 +88,85 @@ class InterfaceToolbar extends HTMLElement {
importModal.style.display = 'block';
});
codegenBtn.addEventListener('click', async () => {
// 获取当前构型ID和构型名称
const savedSelection = localStorage.getItem('xnsim-selection');
if (!savedSelection) {
alert('请先选择构型');
return;
}
let selection;
try {
selection = JSON.parse(savedSelection);
} catch (e) {
alert('构型信息解析失败');
return;
}
const configurationId = selection.configurationId;
if (!configurationId) {
alert('请先选择构型');
return;
}
this.showCodegenMask('准备生成代码...', 0);
// 步骤配置
const steps = [
{ url: '/api/interface-gen/step1', msg: '初始化接口生成参数...', body: { configID: configurationId } },
{ url: '/api/interface-gen/step2', msg: '获取接口数据...' },
{ url: '/api/interface-gen/step3', msg: '创建构型接口目录...' },
{ url: '/api/interface-gen/step4', msg: '生成IDL文件...' },
{ url: '/api/interface-gen/step5', msg: '生成FastDDS接口代码...' },
{ url: '/api/interface-gen/step6', msg: '生成DDS接口代码...' },
{ url: '/api/interface-gen/step7', msg: '生成CMakeLists文件...' },
{ url: '/api/interface-gen/step8', msg: 'CMake构建并安装...' },
{ url: '/api/interface-gen/step9', msg: '执行sudo ldconfig...' }
];
let success = true;
for (let i = 0; i < steps.length; i++) {
const step = steps[i];
const percent = Math.round((i / steps.length) * 100);
this.updateCodegenProgress(step.msg, percent);
try {
let response;
if (step.body) {
response = await fetch(step.url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(step.body)
});
} else {
response = await fetch(step.url, { method: 'POST' });
}
const result = await response.json();
if (!result.success) {
this.updateCodegenProgress(`${step.msg} 失败:${result.message}`, percent);
success = false;
break;
} else {
this.updateCodegenProgress(`${step.msg} 完成`, percent + 1);
}
} catch (err) {
this.updateCodegenProgress(`${step.msg} 异常:${err.message}`, percent);
success = false;
break;
}
await new Promise(r => setTimeout(r, 400));
}
if (success) {
this.updateCodegenProgress('🎉 代码生成全部完成!', 100);
await new Promise(r => setTimeout(r, 400));
}
setTimeout(() => {
this.hideCodegenMask();
if (success) {
alert('代码生成全部完成!');
} else {
alert('代码生成失败,请检查进度提示!');
}
}, 800);
});
importExcelBtn.addEventListener('click', () => {
const input = document.createElement('input');
input.type = 'file';
@ -260,6 +340,15 @@ class InterfaceToolbar extends HTMLElement {
background-color: #1976D2;
}
.codegen-btn {
background-color: #2196F3;
color: white;
}
.codegen-btn:hover {
background-color: #1976D2;
}
.icon-btn {
padding: 6px;
border: none;
@ -400,6 +489,71 @@ class InterfaceToolbar extends HTMLElement {
.cancel-btn:hover {
background-color: #e0e0e0;
}
.codegen-mask {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(80,80,80,0.3);
z-index: 9999;
justify-content: center;
align-items: center;
flex-direction: column;
font-size: 22px;
color: #333;
user-select: none;
}
.codegen-mask.show {
display: flex;
}
.codegen-progress {
background: #fff;
border-radius: 8px;
padding: 32px 48px;
box-shadow: 0 2px 16px rgba(0,0,0,0.08);
font-size: 20px;
color: #333;
min-width: 300px;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
}
.progress-bar-container {
width: 320px;
margin-top: 32px;
display: flex;
flex-direction: column;
align-items: center;
}
.progress-bar-bg {
width: 100%;
height: 18px;
background: #eee;
border-radius: 9px;
overflow: hidden;
margin-bottom: 8px;
}
.progress-bar-fill {
height: 100%;
background: linear-gradient(90deg, #2196F3 0%, #4CAF50 100%);
border-radius: 9px 0 0 9px;
transition: width 0.3s;
}
.progress-bar-text {
font-size: 16px;
color: #2196F3;
font-weight: bold;
}
</style>
<div class="toolbar">
<div class="toolbar-group left">
@ -417,6 +571,10 @@ class InterfaceToolbar extends HTMLElement {
<img src="assets/icons/png/upload.png" alt="导入">
导入数据
</button>
<button class="btn codegen-btn">
<img src="assets/icons/png/code.png" alt="代码生成">
代码生成
</button>
</div>
<div class="toolbar-group right">
<div class="search-group">
@ -431,6 +589,17 @@ class InterfaceToolbar extends HTMLElement {
</div>
</div>
</div>
<div class="codegen-mask" id="codegenMask">
<div class="codegen-progress" id="codegenProgress">
<div id="codegenMsg">代码生成中请稍候...</div>
<div class="progress-bar-container">
<div class="progress-bar-bg">
<div class="progress-bar-fill" id="codegenProgressBar" style="width:0%"></div>
</div>
<div class="progress-bar-text" id="codegenProgressText">0%</div>
</div>
</div>
</div>
<div class="advanced-search-panel">
<select id="filterAta">
<option value="">选择ATA章节</option>
@ -490,6 +659,39 @@ class InterfaceToolbar extends HTMLElement {
structSelect.innerHTML = '<option value="">选择接口结构体</option>' +
options.structs.map(struct => `<option value="${struct}">${struct}</option>`).join('');
}
showCodegenMask(msg = '代码生成中,请稍候...', percent = 0) {
const mask = this.shadowRoot.getElementById('codegenMask');
const msgDiv = this.shadowRoot.getElementById('codegenMsg');
const bar = this.shadowRoot.getElementById('codegenProgressBar');
const text = this.shadowRoot.getElementById('codegenProgressText');
if (mask && msgDiv && bar && text) {
msgDiv.textContent = msg;
bar.style.width = `${percent}%`;
text.textContent = `${percent}%`;
mask.classList.add('show');
}
}
updateCodegenProgress(msg, percent) {
const msgDiv = this.shadowRoot.getElementById('codegenMsg');
const bar = this.shadowRoot.getElementById('codegenProgressBar');
const text = this.shadowRoot.getElementById('codegenProgressText');
if (msgDiv && bar && text) {
if (msg !== undefined) msgDiv.textContent = msg;
if (percent !== undefined) {
bar.style.width = `${percent}%`;
text.textContent = `${percent}%`;
}
}
}
hideCodegenMask() {
const mask = this.shadowRoot.getElementById('codegenMask');
if (mask) {
mask.classList.remove('show');
}
}
}
customElements.define('interface-toolbar', InterfaceToolbar);

View File

@ -0,0 +1,73 @@
const express = require('express');
const router = express.Router();
const {
interfaceGenStep1InitParams,
interfaceGenStep2GetInterfaceData,
interfaceGenStep3CreateConfigDir,
interfaceGenStep4GenerateIDL,
interfaceGenStep5GenerateFastDDS,
interfaceGenStep6GenerateDDSInterface,
interfaceGenStep7GenerateCMakeLists,
interfaceGenStep8BuildAndInstall,
interfaceGenStep9SudoLdconfig
} = require('../utils/xnCoreService');
// Step1: 初始化接口生成参数
router.post('/step1', (req, res) => {
const { configID } = req.body;
if (!configID) {
return res.status(400).json({ success: false, message: '缺少configID参数' });
}
const result = interfaceGenStep1InitParams(configID);
res.json({ success: result.includes('成功'), message: result });
});
// Step2: 获取接口数据
router.post('/step2', (req, res) => {
const result = interfaceGenStep2GetInterfaceData();
res.json({ success: result.includes('成功'), message: result });
});
// Step3: 创建构型接口目录
router.post('/step3', (req, res) => {
const result = interfaceGenStep3CreateConfigDir();
res.json({ success: result.includes('成功'), message: result });
});
// Step4: 生成IDL文件
router.post('/step4', (req, res) => {
const result = interfaceGenStep4GenerateIDL();
res.json({ success: result.includes('成功'), message: result });
});
// Step5: 生成FastDDS接口代码
router.post('/step5', (req, res) => {
const result = interfaceGenStep5GenerateFastDDS();
res.json({ success: result.includes('成功'), message: result });
});
// Step6: 生成DDS接口代码
router.post('/step6', (req, res) => {
const result = interfaceGenStep6GenerateDDSInterface();
res.json({ success: result.includes('成功'), message: result });
});
// Step7: 生成CMakeLists文件
router.post('/step7', (req, res) => {
const result = interfaceGenStep7GenerateCMakeLists();
res.json({ success: result.includes('成功'), message: result });
});
// Step8: CMake构建并安装
router.post('/step8', (req, res) => {
const result = interfaceGenStep8BuildAndInstall();
res.json({ success: result.includes('成功'), message: result });
});
// Step9: 执行sudo ldconfig
router.post('/step9', (req, res) => {
const result = interfaceGenStep9SudoLdconfig();
res.json({ success: result.includes('成功'), message: result });
});
module.exports = router;

View File

@ -29,6 +29,7 @@ const modelMonitorRoutes = require('./routes/ModelMonitor');
const systemControlRoutes = require('./routes/SystemControl');
const dataMonitorRoutes = require('./routes/DataMonitor');
const dataCollectRoutes = require('./routes/DataCollect');
const interfaceGenRoutes = require('./routes/InterfaceGen');
const app = express();
const PORT = process.env.PORT || 3000;
@ -109,6 +110,7 @@ app.use('/api/model-monitor', modelMonitorRoutes);
app.use('/api/system-control', systemControlRoutes);
app.use('/api/data-monitor', dataMonitorRoutes);
app.use('/api/data-collect', dataCollectRoutes);
app.use('/api/interface-gen', interfaceGenRoutes);
// 接口配置页面路由
app.get('/interface-config', (req, res) => {

View File

@ -19,6 +19,10 @@ const loginLibPath = path.join(xnCorePath, 'lib', loginLibName);
const monitorLibName = `${libPrefix}XNMonitorServer${libExtension}`;
const monitorLibPath = path.join(xnCorePath, 'lib', monitorLibName);
// InterfaceGenServer库配置
const interfaceGenLibName = `${libPrefix}XNInterfaceGenServer${libExtension}`;
const interfaceGenLibPath = path.join(xnCorePath, 'lib', interfaceGenLibName);
// 定义Buffer类型
const BufferType = ref.refType(ref.types.void);
const StringType = ref.types.CString;
@ -27,6 +31,7 @@ const IntType = ref.types.int;
// 定义动态库函数接口
let loginLib;
let monitorLib;
let interfaceGenLib;
try {
loginLib = ffi.Library(loginLibPath, {
@ -78,6 +83,22 @@ try {
console.error(`加载 ${monitorLibName} 失败:`, error);
}
try {
interfaceGenLib = ffi.Library(interfaceGenLibPath, {
'XNInterfaceGen_Step1_InitParams': ['int', ['int', StringType, 'int']],
'XNInterfaceGen_Step2_GetInterfaceData': ['int', [StringType, 'int']],
'XNInterfaceGen_Step3_CreateConfigDir': ['int', [StringType, 'int']],
'XNInterfaceGen_Step4_GenerateIDL': ['int', [StringType, 'int']],
'XNInterfaceGen_Step5_GenerateFastDDS': ['int', [StringType, 'int']],
'XNInterfaceGen_Step6_GenerateDDSInterface': ['int', [StringType, 'int']],
'XNInterfaceGen_Step7_GenerateCMakeLists': ['int', [StringType, 'int']],
'XNInterfaceGen_Step8_BuildAndInstall': ['int', [StringType, 'int']],
'XNInterfaceGen_Step9_SudoLdconfig': ['int', [StringType, 'int']]
});
} catch (error) {
console.error(`加载 ${interfaceGenLibName} 失败:`, error);
}
// 注册进程退出时的清理函数
function performCleanup() {
console.log('正在执行清理操作...');
@ -621,9 +642,159 @@ function updateUserIcon(userId, iconBase64) {
}
}
// ========== XNInterfaceGenServer 封装函数 ==========
function interfaceGenStep1InitParams(configID) {
if (!interfaceGenLib) {
return '接口库未加载';
}
try {
const errorMsg = Buffer.alloc(1024);
const result = interfaceGenLib.XNInterfaceGen_Step1_InitParams(
configID,
errorMsg, errorMsg.length
);
if (result !== 0) {
return `Step1: 初始化接口生成参数失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
}
return 'Step1: 初始化接口生成参数成功';
} catch (error) {
return `Step1: 初始化接口生成参数失败: ${error.message}`;
}
}
function interfaceGenStep2GetInterfaceData() {
if (!interfaceGenLib) {
return '接口库未加载';
}
try {
const errorMsg = Buffer.alloc(1024);
const result = interfaceGenLib.XNInterfaceGen_Step2_GetInterfaceData(errorMsg, errorMsg.length);
if (result !== 0) {
return `Step2: 获取接口数据失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
}
return 'Step2: 获取接口数据成功';
} catch (error) {
return `Step2: 获取接口数据失败: ${error.message}`;
}
}
function interfaceGenStep3CreateConfigDir() {
if (!interfaceGenLib) {
return '接口库未加载';
}
try {
const errorMsg = Buffer.alloc(1024);
const result = interfaceGenLib.XNInterfaceGen_Step3_CreateConfigDir(errorMsg, errorMsg.length);
if (result !== 0) {
return `Step3: 创建构型接口目录失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
}
return 'Step3: 创建构型接口目录成功';
} catch (error) {
return `Step3: 创建构型接口目录失败: ${error.message}`;
}
}
function interfaceGenStep4GenerateIDL() {
if (!interfaceGenLib) {
return '接口库未加载';
}
try {
const errorMsg = Buffer.alloc(1024);
const result = interfaceGenLib.XNInterfaceGen_Step4_GenerateIDL(errorMsg, errorMsg.length);
if (result !== 0) {
return `Step4: 生成IDL文件失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
}
return 'Step4: 生成IDL文件成功';
} catch (error) {
return `Step4: 生成IDL文件失败: ${error.message}`;
}
}
function interfaceGenStep5GenerateFastDDS() {
if (!interfaceGenLib) {
return '接口库未加载';
}
try {
const errorMsg = Buffer.alloc(1024);
const result = interfaceGenLib.XNInterfaceGen_Step5_GenerateFastDDS(errorMsg, errorMsg.length);
if (result !== 0) {
return `Step5: 生成FastDDS接口代码失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
}
return 'Step5: 生成FastDDS接口代码成功';
} catch (error) {
return `Step5: 生成FastDDS接口代码失败: ${error.message}`;
}
}
function interfaceGenStep6GenerateDDSInterface() {
if (!interfaceGenLib) {
return '接口库未加载';
}
try {
const errorMsg = Buffer.alloc(1024);
const result = interfaceGenLib.XNInterfaceGen_Step6_GenerateDDSInterface(errorMsg, errorMsg.length);
if (result !== 0) {
return `Step6: 生成DDS接口代码失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
}
return 'Step6: 生成DDS接口代码成功';
} catch (error) {
return `Step6: 生成DDS接口代码失败: ${error.message}`;
}
}
function interfaceGenStep7GenerateCMakeLists() {
if (!interfaceGenLib) {
return '接口库未加载';
}
try {
const errorMsg = Buffer.alloc(1024);
const result = interfaceGenLib.XNInterfaceGen_Step7_GenerateCMakeLists(errorMsg, errorMsg.length);
if (result !== 0) {
return `Step7: 生成CMakeLists文件失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
}
return 'Step7: 生成CMakeLists文件成功';
} catch (error) {
return `Step7: 生成CMakeLists文件失败: ${error.message}`;
}
}
function interfaceGenStep8BuildAndInstall() {
if (!interfaceGenLib) {
return '接口库未加载';
}
try {
const errorMsg = Buffer.alloc(1024);
const result = interfaceGenLib.XNInterfaceGen_Step8_BuildAndInstall(errorMsg, errorMsg.length);
if (result !== 0) {
return `Step8: CMake构建并安装失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
}
return 'Step8: CMake构建并安装成功';
} catch (error) {
return `Step8: CMake构建并安装失败: ${error.message}`;
}
}
function interfaceGenStep9SudoLdconfig() {
if (!interfaceGenLib) {
return '接口库未加载';
}
try {
const errorMsg = Buffer.alloc(1024);
const result = interfaceGenLib.XNInterfaceGen_Step9_SudoLdconfig(errorMsg, errorMsg.length);
if (result !== 0) {
return `Step9: 执行sudo ldconfig失败: ${errorMsg.toString('utf8').replace(/\0/g, '')}`;
}
return 'Step9: 执行sudo ldconfig成功';
} catch (error) {
return `Step9: 执行sudo ldconfig失败: ${error.message}`;
}
}
module.exports = {
loginLib,
monitorLib,
interfaceGenLib,
performCleanup,
stringToBuffer,
initializeMonitor,
@ -653,5 +824,14 @@ module.exports = {
stopCollectData,
resetPassword,
deleteUser,
updateUserIcon
updateUserIcon,
interfaceGenStep1InitParams,
interfaceGenStep2GetInterfaceData,
interfaceGenStep3CreateConfigDir,
interfaceGenStep4GenerateIDL,
interfaceGenStep5GenerateFastDDS,
interfaceGenStep6GenerateDDSInterface,
interfaceGenStep7GenerateCMakeLists,
interfaceGenStep8BuildAndInstall,
interfaceGenStep9SudoLdconfig
};