feat(3d): 异常样式接平台 legend(与平台一致,不依赖 mock 保存)

修正前一轮误判:异常样式("与平台一致")不依赖真后端保存链——getDetail/{id} 端点存在且返回 legend。
- 新增 getExceptionTypeDetail(typeId) → GET /business/exceptionType/getDetail/{id}(wireObject 取 data)
- AnomalySaveDialog 选中类型变化时拉其 legend,按形态(1点 pointColor / 2线·3面 polylineColor+Width+
  Shape→dashed)派生样式;首项自动预取
- main accept 后用 dlg.styleColor/Width/Dashed 覆盖默认(#ff3030/2/实线)→异常按平台类型样式渲染

注:真保存(newException)仍卡——实测真后端无任何登记三维体/切片为 dsObject 的端点(voxel/slice
generate 无、通用 dsObject create 也无),异常 remarkSourceId 无真实实体可指,是后端缺端点的硬依赖。

测试:通过
This commit is contained in:
gaozheng 2026-06-26 11:00:34 +08:00
parent 58544ffb3c
commit 3ed1ea75ac
6 changed files with 61 additions and 1 deletions

View File

@ -22,7 +22,7 @@ AnomalySaveDialog::AnomalySaveDialog(const QString& screenshotPath, int shotW, i
geopro::data::IDatasetCommandRepository* cmdRepo, geopro::data::IDatasetCommandRepository* cmdRepo,
const QString& projectId, int remarkSourceType, const QString& projectId, int remarkSourceType,
QWidget* parent) QWidget* parent)
: QDialog(parent) { : QDialog(parent), cmdRepo_(cmdRepo), remarkSourceType_(remarkSourceType) {
setWindowTitle(QStringLiteral("保存异常")); setWindowTitle(QStringLiteral("保存异常"));
setModal(true); setModal(true);
@ -39,6 +39,9 @@ AnomalySaveDialog::AnomalySaveDialog(const QString& screenshotPath, int shotW, i
type_ = new EmptyAwareComboBox(); type_ = new EmptyAwareComboBox();
formkit::capField(type_); formkit::capField(type_);
form->addRow(formkit::editLabel(QStringLiteral("异常类型")), type_); form->addRow(formkit::editLabel(QStringLiteral("异常类型")), type_);
// 选中类型变化 → 拉其平台样式(legend),使保存的异常按平台类型样式渲染。
connect(type_, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this](int) { loadStyleForCurrent(); });
loadTypes(cmdRepo, projectId, remarkSourceType); // 异步拉平台异常类型填充(与平台一致) loadTypes(cmdRepo, projectId, remarkSourceType); // 异步拉平台异常类型填充(与平台一致)
remark_ = new QPlainTextEdit(); remark_ = new QPlainTextEdit();
@ -77,6 +80,27 @@ void AnomalySaveDialog::loadTypes(geopro::data::IDatasetCommandRepository* cmdRe
self->type_->addItem(o.value(QStringLiteral("label")).toString(), self->type_->addItem(o.value(QStringLiteral("label")).toString(),
o.value(QStringLiteral("value")).toString()); o.value(QStringLiteral("value")).toString());
} }
self->loadStyleForCurrent(); // 首项自动选中 → 预取其样式
});
}
void AnomalySaveDialog::loadStyleForCurrent() {
if (cmdRepo_ == nullptr) return;
const QString typeId = type_->currentData().toString();
if (typeId.isEmpty()) return;
QPointer<AnomalySaveDialog> self(this);
cmdRepo_->getExceptionTypeDetail(typeId, [self](bool ok, QJsonObject data, const QString&) {
if (!self || !ok) return;
const QJsonObject lg = data.value(QStringLiteral("legend")).toObject();
// 按形态(1点/2线/3面)从 legend 派生样式:点用 pointColor线/面用 polyline*。
if (self->remarkSourceType_ == 1) {
self->styleColor_ = lg.value(QStringLiteral("pointColor")).toString();
} else {
self->styleColor_ = lg.value(QStringLiteral("polylineColor")).toString();
self->styleWidth_ = lg.value(QStringLiteral("polylineWidth")).toDouble();
self->styleDashed_ =
lg.value(QStringLiteral("polylineShape")).toString().contains(QStringLiteral("dash"));
}
}); });
} }

View File

@ -30,10 +30,23 @@ public:
QString typeId() const; QString typeId() const;
QString remark() const; QString remark() const;
// 选中类型的平台样式(从 legend 按形态派生与平台一致。styleColor 空 = 未取到,调用方用默认样式。
QString styleColor() const { return styleColor_; }
double styleWidth() const { return styleWidth_; }
bool styleDashed() const { return styleDashed_; }
private: private:
// 异步拉平台异常类型(label→显示, value→id)填充下拉;空/失败时下拉留空EmptyAwareComboBox 提示)。 // 异步拉平台异常类型(label→显示, value→id)填充下拉;空/失败时下拉留空EmptyAwareComboBox 提示)。
void loadTypes(geopro::data::IDatasetCommandRepository* cmdRepo, const QString& projectId, void loadTypes(geopro::data::IDatasetCommandRepository* cmdRepo, const QString& projectId,
int remarkSourceType); int remarkSourceType);
// 拉当前选中类型的详情 legend → 按形态(点/线/面)派生 styleColor/Width/Dashed。
void loadStyleForCurrent();
geopro::data::IDatasetCommandRepository* cmdRepo_ = nullptr;
int remarkSourceType_ = 3;
QString styleColor_; // legend 派生线/点色(空=未取到)
double styleWidth_ = 0.0; // legend.polylineWidth
bool styleDashed_ = false; // legend.polylineShape 含 "dash"
QLineEdit* name_ = nullptr; QLineEdit* name_ = nullptr;
QComboBox* type_ = nullptr; QComboBox* type_ = nullptr;

View File

@ -597,6 +597,12 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
a.typeName = dlg.typeName().toStdString(); a.typeName = dlg.typeName().toStdString();
a.exceptionTypeId = dlg.typeId().toStdString(); a.exceptionTypeId = dlg.typeId().toStdString();
a.remark = dlg.remark().toStdString(); a.remark = dlg.remark().toStdString();
// 平台样式:选中异常类型的 legend 派生(与平台一致);未取到则保留上面的默认样式。
if (!dlg.styleColor().isEmpty()) {
a.lineColor = dlg.styleColor().toStdString();
if (dlg.styleWidth() > 0.0) a.lineWidth = dlg.styleWidth();
a.dashed = dlg.styleDashed();
}
scene3dRepo->saveAnomaly( scene3dRepo->saveAnomaly(
a, shot.toStdString(), a, shot.toStdString(),
[sceneView, renderWindowPtr, refreshAnomalies, refreshAnalysis, [sceneView, renderWindowPtr, refreshAnomalies, refreshAnalysis,

View File

@ -387,6 +387,13 @@ void ApiDatasetCommandRepository::listExceptionTypes(
std::move(cb)); std::move(cb));
} }
void ApiDatasetCommandRepository::getExceptionTypeDetail(
const QString& exceptionTypeId, std::function<void(bool, QJsonObject, QString)> cb) {
wireObject(api_.getAsync(QStringLiteral("/business/exceptionType/getDetail/%1")
.arg(enc(exceptionTypeId))),
std::move(cb));
}
void ApiDatasetCommandRepository::listArrayTypes( void ApiDatasetCommandRepository::listArrayTypes(
std::function<void(bool, QJsonArray, QString)> cb) { std::function<void(bool, QJsonArray, QString)> cb) {
wireArray(api_.getAsync(QStringLiteral("/business/script/arrayTypeList")), std::move(cb)); wireArray(api_.getAsync(QStringLiteral("/business/script/arrayTypeList")), std::move(cb));

View File

@ -81,6 +81,9 @@ public:
void listExceptionTypes( void listExceptionTypes(
const QString& projectId, const QString& remarkSourceType, const QString& projectId, const QString& remarkSourceType,
std::function<void(bool ok, QJsonArray list, QString msg)> cb) override; std::function<void(bool ok, QJsonArray list, QString msg)> cb) override;
void getExceptionTypeDetail(
const QString& exceptionTypeId,
std::function<void(bool ok, QJsonObject data, QString msg)> cb) override;
void listArrayTypes(std::function<void(bool ok, QJsonArray list, QString msg)> cb) override; void listArrayTypes(std::function<void(bool ok, QJsonArray list, QString msg)> cb) override;
void getExceptionName( void getExceptionName(
const QString& exceptionTypeId, const QString& remarkSourceId, const QString& exceptionTypeId, const QString& remarkSourceId,

View File

@ -167,6 +167,13 @@ public:
const QString& projectId, const QString& remarkSourceType, const QString& projectId, const QString& remarkSourceType,
std::function<void(bool ok, QJsonArray list, QString msg)> cb) = 0; std::function<void(bool ok, QJsonArray list, QString msg)> cb) = 0;
// 异常类型详情GET /business/exceptionType/getDetail/{id} → data{...legend...}。
// data.legend = {polylineColor/Width/Shape, pointColor/Size/Shape, polygonFillColor,...}
// 供创建异常时按平台类型样式渲染(与平台一致)。回调 data = 整个 data 对象。
virtual void getExceptionTypeDetail(
const QString& exceptionTypeId,
std::function<void(bool ok, QJsonObject data, QString msg)> cb) = 0;
// 装置类型枚举GET /business/script/arrayTypeList → [{itemValue,name}](电阻率/视电阻率段装置筛选用)。 // 装置类型枚举GET /business/script/arrayTypeList → [{itemValue,name}](电阻率/视电阻率段装置筛选用)。
virtual void listArrayTypes(std::function<void(bool ok, QJsonArray list, QString msg)> cb) = 0; virtual void listArrayTypes(std::function<void(bool ok, QJsonArray list, QString msg)> cb) = 0;