geopro/docs/superpowers/specs/2026-06-13-batch2-object-da...

16 KiB
Raw Permalink Blame History

Batch 2 实施依据:对象/数据集对话框(新建/编辑/导入/导出/插件)

实地研究原系统 http://tenant.geomative.cn(项目「香港威立雅」projectId=1439735554211840 projectTypeId 1445121423155200所得。API 经页面 token replay + 真实 DOM 操作 + fetch 录制捕获。

口径:成功码 code==200;列表载荷在 data(非对象时包成 data.value)。 token 头 geomativeauthorizationbase http://tenant.geomative.cn/pop-api


更新2026-06-15权威来源已厘清前述"⚠️未捕获"壁垒解除

三个来源各司其职,别再混用:

  • xlsx「客户端」页签 = 客户端菜单/交互规格(权威)
  • 原 web 压缩 bundle = 提交体的"地面真相"(首要权威):线上正在跑、能成功建对象的真实前端代码,它发什么服务端就收什么。 bundle 抓 http://tenant.geomative.cn/static/js/ 各路由 chunk 后 grep 还原: GsForm-*.js(GS表单) / tmForm-D7d9h9Nb.js(TM表单,数据管理页) / ImportForm-*.js(导入) / projectStructure-*.js
  • docs/apis OpenAPI = 交叉校验(次级):自动生成、已知有缺漏/错标(如 GS 名称字段标成 projectName)。与 bundle 冲突时以 bundle 为准,并在 §B 并列标注、留一次真实请求验证。
  • 原型 prototype.geomative.cn = 粗略视觉 mockup菜单画不全不作为菜单删减依据

A. xlsx 规定的菜单(= 现有实现已对齐,勿按原型删减)

区域 菜单/动作xlsx 原文) 对话框来源xlsx 标注)
对象-添加+ 新建GS当前为TM时无效、新建TM GS→项目配置\项目结构\添加TM→数据管理\新增方法对象
对象-右键 显示/隐藏、定位、属性、异常详情、编辑、新建GS、新建TM、导入DS(1..n)、删除 编辑→数据管理\编辑;导入→数据管理\导入
数据集-添加+ 新建/导入一个数据集 数据管理\可新建数据类型\导入
数据集-右键 数据集详情、属性、插件1/2/3…、导出、删除 导出→批量导出\文件导出

xlsx 第32行"显示项目(也是一个GS"——项目根本身就是 GS 节点。最强证据是真实数据:queryProjectStruct 返回的结构里确有 TM(type=2) 直接挂在项目根(type=1) 下(如 NERT1、"123")——若根不允许建 TM该数据无从产生。故项目根(作为 GS允许新建 TM

B. 提交体(bundle 为准OpenAPI 并列校验,替换下文旧"⚠️未捕获"

bundle 还原(= 客户端应照此发送):

POST /business/gsObject  { gsTypeId, parentId, projectId, name, responsiblePersonName, properties }
PUT  /business/gsObject  { gsTypeId, id, projectId, name, responsiblePersonName, properties }   // 编辑无 parentId
   · gsTypeId(测试对象类型)、responsiblePersonName(负责人)、name 为顶层固定字段;动态字段在 properties
   · parentId 仅 POST 用 = 右键所在节点 id含项目根

POST /business/tmObject  { tmTypeId, name, properties, projectId, parentId, parentType:"1" }
PUT  /business/tmObject  { tmTypeId, id, name, properties, projectId, parentId, parentType:"1" }
   · bundle 中 create/edit 用同一 spread故 PUT 也带 parentId/parentType
   · parentId = 右键所在节点 idGS 或项目根parentType 恒字符串 "1"

POST /business/dsObject/import  (参数走 query stringfile 为 multipart 上传项)
   { file*, dsTypeId*, projectId*, structParentConfType*(int), structParentId*, scriptCode?, scriptParamListJsonStr?, aliasName? }
   · 选脚本先 getDynamicForm(typeId=scriptId, type=6) 取脚本参数checkImport 校验坐标

getDynamicForm 的 type1=GS对象 / 2=TM对象 / 6=导入脚本参数(已确认)。

线上实测已确认intercept-abort未写库动态字段嵌套在 properties.<fieldCode> 下。 证据:编辑弹窗真实字段 DOM id —— GS properties_topography/geotechnical/climate/hydrology、TM properties_supervisor/notes顶层固定字段gsTypeId/responsiblePersonName/name、tmTypeId/name与 properties 分开渲染。

bundle ↔ OpenAPI 冲突(已由压缩源码分析确证,以 bundle 为准OpenAPI 为文档生成误差): 下表结论来自 GsForm/tmForm 压缩源码还原(= 线上前端真实请求构造)。线上 app 正是发这些 body 且能成功建/改对象故服务端接受度亦由线上运行佐证。OpenAPI 的 projectName/整数等是自动生成的文档误差,不采信。

字段 bundle线上真实代码 OpenAPI生成文档 取舍 实测状态(含源码分析)
GS 名称 顶层 name POST 标 projectName、PUT 无 nameprojectName 系 DTO 误标) 源码已证
TM 名称 顶层 name name nameOpenAPI 漏列) 源码已证
parentType 字符串 "1" integer 发字符串 "1" 源码已证
PUT tmObject 的 parentId/parentType create/edit 同一 spread 带(匹配线上) 源码已证
动态字段位置 properties.<code> —— 随 bundle 源码 + 运行时双证

注:拦截-阻断的运行时抓包在本数据集走不通变更表单必填项多、arco 校验拦截、且不写生产库),但源码分析已足以确证 body,无需真实写入。

C. 客户端待改项(对照现有实现)

  1. ObjectFormDialog 提交体字段错误(最关键):
    • 现:{typeId, type, projectId, id?, properties} + extraBody {structParentId, structParentConfType}
    • 应(按 bundleGS→{gsTypeId, parentId(仅新建), name, responsiblePersonName, properties} TM→{tmTypeId, parentId, parentType:"1", name, properties}+ 编辑加 id
    • structParentId/structParentConfType导入的字段被误用于新建对象OpenAPI 证实这两字段只在 dsObject/import 出现)。
  2. 项目根节点:现为"非交互无菜单",应按 GS 处理(提供 新建GS/新建TM/属性,依 xlsx 第32行 + 真实数据"TM 挂根")。
  3. 新建TM 方法类型来源(决策):queryTmType?projectId=&gsId=——带 gsId 能按所选 GS 过滤方法类型,比 web 全局 tmMethodList 更准。
  4. 父对象确定逻辑(决策):客户端不复刻 web 数据管理页"先选左树"的选择器;父对象 = 右键所在节点GS 或项目根),parentId 直接取该节点 id。
  5. DynamicFormEditor 顶层固定字段GS 须含 gsTypeId 下拉 + responsiblePersonName + nameTM 新建须含 tmTypeId 下拉 + name。
  6. displayComponentType 全集映射 —— 已由源码确证,见 §E.1。

D. 状态(原"待确认"已全部由源码分析落地)

  • displayComponentType 完整映射 → §E.1
  • 导出 body → §E.2
  • 插件机制 → §E.3结论web 无"ds→插件"菜单,客户端此项为原创设计,需产品决策)
  • §B 字段已由源码确证,不再需要真实写入回证
  • PUT /dsObject/updateDsObject body OpenAPI 已定义 {dsObjectId, description, attachedParameters, ...},见下文第六节。)

E. 源码补全FieldItem / 导出 / 插件,均来自压缩源码)

E.1 displayComponentType → 控件FieldItem index-1LyDq-Qg.js,权威全集)

控件 备注
1 a-input 单行文本
2 a-input 禁用 只读文本
3 a-checkbox label=item.name
4 a-select 下拉 options=optionsObject
5 a-input 单行文本 同 1
6 a-date-picker 日期
7 a-time-picker 时间
8 a-date-picker show-time 日期时间 YYYY-MM-DD HH:mm:ss
9 a-textarea 多行文本
10 a-input-number 数字
11 a-tree-select 树选择 data=optionsObject, fieldNames{key:value,title:label,children:childList}
其他 a-input-number mode=button 步进数字
  • 字段路径 ${fieldPrefix=properties}.${fieldCode} → 确认动态值在 properties.<fieldCode>
  • requiredType 语义纠正1=必填可编辑2=只读禁用(disabled: isDisabled||requiredType===2required 仅 ===1其他=可选可编辑。
  • comp 类型由后端按类型配置(如"测区"把地形地貌配成 6=日期选择器),客户端按本表渲染即可。

E.2 导出 bodyExportModal ExportModal-DWdo-HxP.js,两套)

模板导出  POST /business/templateExport/export   { dsObjectIdList:[ds ids], templateId }
文件导出  POST /business/dataFileExport/export    { idList:[ds ids], fileType [, startTime, endTime] }
                                                  // startTime/endTime 仅 fileType==5(时序数据)
文件下载  POST /business/dataFileExport/download  (responseType=blob)
  • selectType(checked/currentPage) 仅决定取哪些 id不进 body。
  • 批量导出页流程:选数据类型/时间范围 → 勾选文件(ds ids) → 「导出」开 ExportModal(选模板) → 提交。
  • 客户端数据集右键「导出」(单 ds, 按模板) → templateExport/export { dsObjectIdList:[该ds], templateId };模板来自 localStorage template.fileTemplateList 或 dataFileExport/queryFileType

E.3 插件机制结论web 无对应交互,客户端为原创设计)

  • web 中没有"数据集右键→插件"菜单。模型从模型管理页按类型用专用 Modal 调起resipy=ERT反演、gprpy=GPR处理 等,见 resipyModel-*.js/gprpyModel-*.js/modelManage-*.js)。
  • 关联方向是模型→可用数据集GET /business/model/{scriptType}/dsObjectList/{projectId}(如 model/resipy/dsObjectList/{projectId}),即每个模型声明它能跑哪些 ds。
  • 全局模型目录:GET /business/model/list;任务分页:POST /business/model/task/page
  • xlsx 的"插件1/2/3 = 列出与当前 ds 关联的插件"是客户端原创ds→模型 的反向。web 无单一直达接口,需:用 model/list + 各模型 dsObjectList 反查匹配,或后端新增"按 ds 列模型"接口。此项需产品/后端决策,非源码可定。

一、项目结构(已用于现有功能)

GET /business/projectStruct/queryProjectStruct/{projectId} → 扁平节点 [{id,parentId,name,type(1=GS,2=TM),typeName,typeId,confCode,collectTime}],根 parentId="0"。

二、编辑 / 新建对象 —— 动态表单(核心,最大工作量)

表单 schema 来源(统一端点,编辑弹窗打开时调用)

POST /business/project/getDynamicForm body {"typeId": <类型id>, "id": <对象id>, "type": <1=GS|2=TM>, "projectId": <projectId>} → 返回结构同 getDetail

{
  typeId, confCode, name(类型名), description,
  formList: [ { groupName, values: [ FieldDef... ] } ],   // 可多组(对应弹窗内分页签:基本信息/测线布设/数据质量检查...)
  properties: { <fieldCode>: <当前值> }                    // 编辑预填;新建时为空
}

getGsObjectDetail / tmObject/getDetail 返回同样的 formList/properties可互为参考。 TM 的 getDetail 还含 dsList / dsClassifyTypeList / gridFieldList。

FieldDef 字段定义

confFieldId, fieldUseType(1=核心字段,2=普通),
fieldCode(键), fieldName(标签),
displayComponentType(控件类型), requiredType(1/2 必填标志——待核实方向),
displaySort, fieldDataType(4=字符串,5=日期,6=日期时间...),
fieldConfigJsonObject:{fieldChnFormat,fieldRemark,fieldEngFormat},
optionsObject(下拉项;普通字段为 null)

displayComponentType 已观察样例(需补全映射)

TM「常规高密度电阻率法」编辑弹窗实测控件

  • 方法名称(只读文本)
  • 基本信息组:名称/电极数/电极间距/测线长 = 只读文本(核心字段 fieldUseType=1编辑时禁用
  • 设备 = 下拉(必填) ; 布设日期 = 日期选择(必填) ; 天气 = 下拉(必填)
  • 布设人/审核人 = 文本(必填) ; 备注 = 文本 GS「测区」formList 含:创建人/创建日期(comp6)/名称(comp1)/创建时间(comp7)/地形地貌(comp8)/岩土性质... → 推测 comp1=单行文本, 6=日期, 7=日期时间, 8=多行文本;落地前需逐一在原版核实

新建 TM 的类型选择

GET /business/tmObject/queryTmType?projectId=..&gsId=..[{label:"瞬变电磁方法", value:<tmTypeId>, code:"TEM01"}] 新建流程:选 GS → queryTmType 选方法类型 → getDynamicForm(typeId,type=2,无id) 取空表单 → 填 → POST。

⚠️ 未捕获(真实壁垒,不可猜) → 已解除,见上「更新 §B」

下列 body 当时认为不可得;实为 OpenAPI requestBody + bundle 已给出,参见文首「更新 §B」。

  • POST /business/gsObject → 见 §B
  • POST /business/tmObject → 见 §B
  • PUT /business/gsObject / PUT /business/tmObject → 见 §B
  • PUT /business/dsObject/updateDsObject更新DS body仍待确认

三、删除(已实现 Batch1

DELETE /business/gsObject/{id} DELETE /business/tmObject/{id} DELETE /business/dsObject/{id}

四、导入 DS

TM 的 getDetail.dsList = 该 TM 可承载的 ds 类型 [{dsTypeId,nameChn,nameEng,canImport,canExport,...}]canImport=true 的可导入)。 GET /business/dsObject/query/script?dsTypeId=..&tmTypeBaseConfId=.. → 该类型可用导入脚本。 POST /business/dsObject/checkImport → 校验脚本所需轨迹/坐标文件是否存在。 POST /business/dsObject/importquery 参数已知aliasName, dsTypeId*, file*, projectId*, scriptCode, scriptParamListJsonStr, structParentConfType*, structParentId* ⚠️ file 为上传项multipartscriptParamListJsonStr 结构未捕获。

五、导出

POST /business/templateExport/queryExportObject body {projectId} → 可选导出对象树 [{id,parentId,name,check}]GET /business/templateExport/queryDataType/{tmTypeBaseConfId} → 按方法查数据类型。 POST /business/templateExport/exportbody 未捕获)。 模板列表见 localStorage templatetemplateTypeList[数据管理-数据报告/异常体报告], fileTypeList[WORD/EXCEL], fileTemplateList。 另:数据集详情页「导出」按钮点击未发请求/未弹窗(可能直接下载或需先配模板)——待核实。

六、插件(数据集右键)

GET /business/model/list → 全局模型目录 [{id,scriptCode,scriptName,scriptOperationType,formItemList}]script_ert_inner_inversion「ert反演默认」、script_radar_resultant_data_processing「雷达数据处理默认」。 ⚠️ "与当前 ds 关联"的过滤逻辑未捕获model/list 不含 ds 类型关联;各模型用 dsObjectList/{projectId} 声明可接受的数据源)。 POST /business/model/task/page → 模型任务分页(用于"数据集任务"面板)。

实施建议顺序

body 已由「更新 §B」给出下列"先捕获"前置多数已不需要;仅 §D 三项仍待确认。

  1. 动态表单引擎 DynamicFormEditorQt按 formList 渲染 comp1/6/7/8 + 下拉(optionsObject) + 必填校验 + 只读核心字段;编辑用 properties 预填GS/TM 顶层固定字段§C-5gsTypeId/responsiblePersonName/name、tmTypeId/namedisplayComponentType 全集映射仍需核实。
  2. 修编辑/新建提交体字段§C-1GS→gsTypeId+parentId(仅新建)+name+responsiblePersonNameTM→tmTypeId+parentId+parentType:"1"+name。
  3. 项目根菜单按 GS 处理§C-2新建TM 类型用 queryTmType§C-3父对象=右键节点§C-4
  4. 导入 DSdsList 选类型 → query/script → 文件 → checkImport → importbody 见 §B
  5. 导出queryExportObject 选对象 + 模板 → exportexport body 待确认§D
  6. 插件子菜单model/list 列出;调用/关联逻辑待定§D

捕获提交载荷的方法(已在原版页面注入录制器 window.__rec

在 Playwright 浏览器对原系统执行一次「编辑保存/新建保存/导入/导出」(填完必填项), 即可从 window.__rec 读到真实 method+url+body。 注:编辑/新建/导入的 body 已由 bundle 还原§B此法现仅用于验证 §B 冲突表 4 项捕获导出 export body(会改数据,谨慎)。