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

213 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Batch 2 实施依据:对象/数据集对话框(新建/编辑/导入/导出/插件)
实地研究原系统 `http://tenant.geomative.cn`(项目「香港威立雅」`projectId=1439735554211840`
projectTypeId `1445121423155200`所得。API 经页面 token replay + 真实 DOM 操作 + fetch 录制捕获。
> 口径:成功码 `code==200`;列表载荷在 `data`(非对象时包成 `data.value`)。
> token 头 `geomativeauthorization`base `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 的 `type`**1=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 无 | 用 `name`projectName 系 DTO 误标) | ✅ 源码已证 |
| TM 名称 | 顶层 `name` | 无 `name` | 用 `name`OpenAPI 漏列) | ✅ 源码已证 |
| `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===2`required 仅 ===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/import`query 参数已知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/export`body 未捕获)。
模板列表见 localStorage `template`templateTypeList[数据管理-数据报告/异常体报告], 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. 动态表单引擎 `DynamicFormEditor`Qt按 formList 渲染 comp1/6/7/8 + 下拉(optionsObject) + 必填校验 + 只读核心字段;编辑用 properties 预填GS/TM 顶层固定字段§C-5gsTypeId/responsiblePersonName/name、tmTypeId/name。**displayComponentType 全集映射仍需核实。**
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 选对象 + 模板 → export。**export body 待确认§D。**
6. 插件子菜单model/list 列出;调用/关联逻辑待定§D
## 捕获提交载荷的方法(已在原版页面注入录制器 window.__rec
在 Playwright 浏览器对原系统执行一次「编辑保存/新建保存/导入/导出」(填完必填项),
即可从 `window.__rec` 读到真实 method+url+body。
注:编辑/新建/导入的 body 已由 bundle 还原§B此法现仅用于**验证 §B 冲突表 4 项**与**捕获导出 export body**(会改数据,谨慎)。