fix(startup): 样本/PROJ 数据随包+相对定位+启动防护,修复他机登录后无界面崩溃

登录成功后 buildWorkbench 同步调 repo.loadGrid("grid1") 构建世界系,而
LocalSampleRepository 指向写死的开发机绝对路径 docs/剖面网格数据...;该路径
在他机不存在,readFile 打开失败抛 runtime_error,沿未加保护的调用链冒泡出
main 触发 std::terminate,进程在 window->show() 前消失——表现为登录框关闭
后既无主界面也无进程。本机因该路径存在而正常。

- main.cpp 改为运行时定位样本目录:优先 exe 旁 sampledata/,回退源码树开发
  路径;PROJ_DATA 候选已含 exe 旁 proj/。均不依赖写死绝对路径。
- main.cpp 给 buildWorkbench 包 try/catch:启动期同步加载失败弹可见错误而非
  静默退出(防护 PROJ/数据缺失等任意启动异常)。
- build_installer.ps1 随包 sampledata/(样本演示数据)与 proj/(PROJ 数据)到
  exe 旁,使他机 2D 演示视图与 3D CRS 配准可用。
This commit is contained in:
gaozheng 2026-06-19 17:55:05 +08:00
parent 5beb13c5e2
commit b3b030767d
2 changed files with 63 additions and 7 deletions

View File

@ -126,6 +126,22 @@ if (-not $SkipDeploy) {
} }
} }
# --- 5.5 随包数据:本地样本演示数据 + PROJ 数据exe 旁布局,运行时相对定位)-------
# 客户端启动会同步加载本地样本数据构建工作台PROJ 数据供 3D 体素 CRS 配准。
# 二者缺失会导致登录后无界面/3D 退化,故随包到 exe 旁sampledata\ 与 proj\)。
Info '随包数据:复制样本演示数据 + PROJ 数据到 staging...'
# 用目录内 ASCII 标志文件 dem.tif 定位样本目录,避免在脚本里写中文路径(编码风险)。
$sampleSrc = Get-ChildItem (Join-Path $RepoRoot 'docs') -Directory -ErrorAction SilentlyContinue |
Where-Object { Test-Path (Join-Path $_.FullName 'dem.tif') } | Select-Object -First 1
if (-not $sampleSrc) { Die '未找到本地样本数据目录docs 下含 dem.tif 的目录)' }
robocopy $sampleSrc.FullName (Join-Path $StageDir 'sampledata') /E /NFL /NDL /NJH /NJS /MT:8 | Out-Null
if ($LASTEXITCODE -ge 8) { Die "robocopy 样本数据失败 (exit $LASTEXITCODE)" }
$projSrc = Join-Path $RepoRoot 'build\release\vcpkg_installed\x64-windows\share\proj'
if (-not (Test-Path (Join-Path $projSrc 'proj.db'))) { Die "未找到 PROJ 数据: $projSrc\proj.db" }
robocopy $projSrc (Join-Path $StageDir 'proj') /E /NFL /NDL /NJH /NJS /MT:8 | Out-Null
if ($LASTEXITCODE -ge 8) { Die "robocopy PROJ 数据失败 (exit $LASTEXITCODE)" }
# --- 6. VC++ 运行时安装器就位 ----------------------------------------------- # --- 6. VC++ 运行时安装器就位 -----------------------------------------------
New-Item -ItemType Directory -Force $RedistDir | Out-Null New-Item -ItemType Directory -Force $RedistDir | Out-Null
$VcRedist = Join-Path $RedistDir 'vc_redist.x64.exe' $VcRedist = Join-Path $RedistDir 'vc_redist.x64.exe'

View File

@ -97,6 +97,7 @@
#include "Theme.hpp" #include "Theme.hpp"
#include "AnomalySaveDialog.hpp" #include "AnomalySaveDialog.hpp"
#include "AnomalyPropertiesDialog.hpp" #include "AnomalyPropertiesDialog.hpp"
#include "ColorScaleConfigDialog.hpp"
#include "SettingsDialog.hpp" #include "SettingsDialog.hpp"
#include "SlicePropertiesDialog.hpp" #include "SlicePropertiesDialog.hpp"
#include "SliceExport.hpp" #include "SliceExport.hpp"
@ -769,11 +770,22 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
QMessageBox::warning(&window, QStringLiteral("导出"), QMessageBox::warning(&window, QStringLiteral("导出"),
QStringLiteral("导出失败。")); QStringLiteral("导出失败。"));
}); });
// 色阶(三维体/切片):本期占位。 // 色阶(三维体/切片):复刻原版「色阶配置」对话框,确定后体素 + 其切片随新色阶重渲染。
// 仅对当前已渲染的三维体生效(切片色阶继承体色阶,经 InteractionManager 重建)。
QObject::connect(ca, &geopro::app::Column3DAnalysis::colorScaleRequested, &window, QObject::connect(ca, &geopro::app::Column3DAnalysis::colorScaleRequested, &window,
[&window](const QString&) { [&window, sceneCtrl, sceneView](const QString& qid) {
QMessageBox::information(&window, QStringLiteral("色阶"), const std::string dsId = qid.toStdString();
QStringLiteral("色阶设置开发中。")); if (sceneView->currentVolumeDsId() != dsId || !sceneView->hasVolume()) {
QMessageBox::information(
&window, QStringLiteral("色阶"),
QStringLiteral("请先勾选该三维体使其渲染后再编辑色阶。"));
return;
}
geopro::app::ColorScaleConfigDialog dlg(
sceneView->currentColorScale(), sceneView->currentVmin(),
sceneView->currentVmax(), &window);
if (dlg.exec() == QDialog::Accepted)
sceneCtrl->setVolumeColorScale(dsId, dlg.colorScale());
}); });
// ── 3D 异常控制(#4c显示过滤 / 单条显隐 / 删除 → 驱动 VTK 异常渲染 ────────── // ── 3D 异常控制(#4c显示过滤 / 单条显隐 / 删除 → 驱动 VTK 异常渲染 ──────────
@ -1772,9 +1784,27 @@ int main(int argc, char* argv[])
api.setToken(token); // 注入 token 供后续 API 使用 api.setToken(token); // 注入 token 供后续 API 使用
// 本地样本演示数据目录优先随安装包目录exe 旁 sampledata/),回退源码树开发路径。
// 不依赖写死的开发机绝对路径——部署到任意机器均可用。
const std::string sampleDir = []() -> std::string {
const QString appDir = QCoreApplication::applicationDirPath();
const QStringList candidates = {
appDir + QStringLiteral("/sampledata"),
QStringLiteral("D:/Git/lanbingtech/geopro/docs/剖面网格数据的色阶数据2等文件"),
};
for (const auto& c : candidates) {
if (QDir(c).exists()) {
const QByteArray u8 = (c + QStringLiteral("/")).toUtf8();
return std::string(u8.constData(), static_cast<size_t>(u8.size()));
}
}
// 都不存在:返回首选路径,交由下游报错并被启动防护捕获(提示安装不完整)。
const QByteArray u8 = (candidates.front() + QStringLiteral("/")).toUtf8();
return std::string(u8.constData(), static_cast<size_t>(u8.size()));
}();
// 登录成功 → 构建并显示工作台。 // 登录成功 → 构建并显示工作台。
geopro::data::LocalSampleRepository repo( geopro::data::LocalSampleRepository repo(sampleDir);
"D:/Git/lanbingtech/geopro/docs/剖面网格数据的色阶数据2等文件/");
// 导航仓储 + 控制器(接口/逻辑层):用同一共享会话 ApiClient。 // 导航仓储 + 控制器(接口/逻辑层):用同一共享会话 ApiClient。
geopro::data::ApiProjectRepository projectRepo(api); geopro::data::ApiProjectRepository projectRepo(api);
@ -1798,7 +1828,17 @@ int main(int argc, char* argv[])
window->setWindowTitle(kTitle); window->setWindowTitle(kTitle);
window->resize(1280, 800); window->resize(1280, 800);
window->setMinimumSize(1024, 680); window->setMinimumSize(1024, 680);
buildWorkbench(*window, repo, projectRepo, datasetRepo, nav, detailCtrl); // 启动防护:工作台构建期间任何同步加载失败(如样本数据缺失)都不应让进程静默退出,
// 而是给出可见错误提示。否则登录后窗口未显示、进程消失,用户无从排查。
try {
buildWorkbench(*window, repo, projectRepo, datasetRepo, nav, detailCtrl);
} catch (const std::exception& e) {
QMessageBox::critical(
nullptr, QStringLiteral("启动失败"),
QStringLiteral("工作台初始化失败:\n%1\n\n请确认安装完整(样本数据 / 运行库未缺失)。")
.arg(QString::fromUtf8(e.what())));
return 1;
}
// 主题桥ThemeManager 明/暗切换 → 重应用全局 QSS+调色板(标准控件 + ADS内联 chrome 经各自连接)。 // 主题桥ThemeManager 明/暗切换 → 重应用全局 QSS+调色板(标准控件 + ADS内联 chrome 经各自连接)。
QObject::connect(&geopro::app::ThemeManager::instance(), &geopro::app::ThemeManager::changed, QObject::connect(&geopro::app::ThemeManager::instance(), &geopro::app::ThemeManager::changed,