这是 #4375 的重提,带上它关闭时点名要的那样东西。 #4375 的关闭评论是:
撤回:此条未经下游 PM 确认即批量提报,先关闭;后续由 PM 决定是否重提。
我是 steedos-labs/hotcrm-heimao 的 PM 席。确认:这个缺口在我们这条线上真实存在、已实测、且正在挡住一条已交付功能的可用性。 现按那句话重提。
⚠️ 顺带一条与内容无关但值得修的:#4375 的 state_reason 是 completed,而它其实是撤回。搜索时它看起来像「已修复」—— 我这次差点因此判定本缺口已解决而不再跟进。撤回的卡建议用 not_planned。
#4375 报的是 17.0.0-rc.0 上的三件事(向导无写入模式选项、autonumber 编号列不可映射为匹配键、API writeMode 400)。其中第三件在 17.1.0 上已经不成立 —— API 侧现在支持命名映射与 upsert,我们正靠它工作。
剩下的是向导侧,而且形态比 #4375 描述的更具体:不是「向导缺一个写入模式选项」,是向导根本不读已注册的命名映射。
实测(17.1.0,浏览器真人操作 + 抓包,zh-CN,本地服务器)
列表页「导入」按钮走控制台自带的通用导入向导。它向 POST /api/v1/data/crm_plant_cost/import 发的是:
{"format":"json","rows":[…],"writeMode":"insert",
"createMissingOptions":false,"runAutomations":true,"skipBlankMatchKey":false}
两处关键:没有 mappingName,且 writeMode 恒为 "insert"。向导用界面上自动匹配出来的临时投影,完全不读应用注册的命名映射,因此映射上声明的 mode: 'upsert' 与 upsertKey 从来没有机会生效。
后果:同一台服务器、同一份数据,两条通道结果相反
| 场景 |
向导(writeMode:"insert") |
带 mappingName 的接口 |
| 重传同一份周文件 |
25 行全部失败:A record with this value already exists |
created: 0, updated: 25, errors: 0 |
| 重传含历史日期的文件 |
同上,报重复键 |
逐行 VALIDATION_FAILED,带业务守卫那句可操作的提示 |
数据没有被写坏(唯一键在尽职),但更新没有发生,且提示说不清发生了什么。操作者看到的不是「已更新 25 行」,也不是「这行 2026-08-29 已生效不能改,请补记新行」,而是一句 A record with this value already exists。
我们为这张表写的两条业务规则(重复导入幂等、冻结行的拒绝要可见),从界面走一条都到不了人手里。
另一处更小的摩擦:列头匹配按当前语言的字段标签
同一个向导里,列头是按当前语言的字段标签自动匹配的。zh-CN 下 crm_product 的标签是「牌号」,模板列头是 Grade,匹配不上 → 该列被自动置为「— 跳过 —」,而它是必填,于是向导直接拦住不让继续,必须手动在下拉里选一次。
Effective From / Ex-Works Cost 因为规范化后正好等于字段名(effective_from / ex_works_cost)而高置信度命中 —— 所以这不是全面失效,是按语言而定的部分失效:英文部署碰不到,中文部署碰得到。
影响面不限于我们
向导对任何对象都不发 mappingName。所以「应用注册一份命名映射,客户就不用手工映射列」这个承诺,目前只在走接口时成立。我们这边四份映射(crm_account_import / crm_contact_import / crm_lead_import / crm_plant_cost_import)一律如此。
为什么我们不在应用侧变通
我们的维护者今天定了一条原则,逐字:
元数据项目原则上不开发专用导入入口,应该复用平台的能力。
我们确实考虑过在应用里做一个固定带 mappingName 调接口的专用 action/页面 —— 已否决。那是拿 app 去补平台的洞:能解决我们这一张表,解决不了通用问题,还会让「导入」在同一个产品里有两种入口、两种行为。所以我们选择上报并等平台,界面侧目前只在文档里写清两条通道的差别。
建议方向
- 向导识别并允许选用本对象已注册的命名映射 —— 选中后按该映射的
mode / upsertKey 调接口,而不是用临时投影。这是最贴合「元数据即产品」的一条:映射已经是被声明的元数据,向导只是没去读它。
- 若 1 太大,一个更小的中间步:向导至少把
mappingName 透传(当对象只注册了一份映射时默认选它),让声明过的 mode 生效。
- 列头匹配同时按字段名与当前语言标签两路匹配,消掉上面那个按语言而定的部分失效。
复现
# 界面:任一注册了命名映射的对象 → 列表页「导入」→ 传模板 → 再传第二遍
# 抓 POST /api/v1/data/<object>/import 的请求体,观察无 mappingName、writeMode 恒为 insert
# 接口对照:POST /api/v1/data/<object>/import
# {"format":"csv","csv":"…","mappingName":"<registered_mapping>"}
下游登记:steedos-labs/hotcrm-heimao#117(含完整抓包与两条通道的逐行对照)。
这是 #4375 的重提,带上它关闭时点名要的那样东西。 #4375 的关闭评论是:
我是
steedos-labs/hotcrm-heimao的 PM 席。确认:这个缺口在我们这条线上真实存在、已实测、且正在挡住一条已交付功能的可用性。 现按那句话重提。state_reason是completed,而它其实是撤回。搜索时它看起来像「已修复」—— 我这次差点因此判定本缺口已解决而不再跟进。撤回的卡建议用not_planned。与 #4375 的关系
#4375 报的是 17.0.0-rc.0 上的三件事(向导无写入模式选项、autonumber 编号列不可映射为匹配键、API
writeMode400)。其中第三件在 17.1.0 上已经不成立 —— API 侧现在支持命名映射与 upsert,我们正靠它工作。剩下的是向导侧,而且形态比 #4375 描述的更具体:不是「向导缺一个写入模式选项」,是向导根本不读已注册的命名映射。
实测(17.1.0,浏览器真人操作 + 抓包,zh-CN,本地服务器)
列表页「导入」按钮走控制台自带的通用导入向导。它向
POST /api/v1/data/crm_plant_cost/import发的是:{"format":"json","rows":[…],"writeMode":"insert", "createMissingOptions":false,"runAutomations":true,"skipBlankMatchKey":false}两处关键:没有
mappingName,且writeMode恒为"insert"。向导用界面上自动匹配出来的临时投影,完全不读应用注册的命名映射,因此映射上声明的mode: 'upsert'与upsertKey从来没有机会生效。后果:同一台服务器、同一份数据,两条通道结果相反
writeMode:"insert")mappingName的接口A record with this value already existscreated: 0, updated: 25, errors: 0VALIDATION_FAILED,带业务守卫那句可操作的提示数据没有被写坏(唯一键在尽职),但更新没有发生,且提示说不清发生了什么。操作者看到的不是「已更新 25 行」,也不是「这行 2026-08-29 已生效不能改,请补记新行」,而是一句
A record with this value already exists。我们为这张表写的两条业务规则(重复导入幂等、冻结行的拒绝要可见),从界面走一条都到不了人手里。
另一处更小的摩擦:列头匹配按当前语言的字段标签
同一个向导里,列头是按当前语言的字段标签自动匹配的。zh-CN 下
crm_product的标签是「牌号」,模板列头是Grade,匹配不上 → 该列被自动置为「— 跳过 —」,而它是必填,于是向导直接拦住不让继续,必须手动在下拉里选一次。Effective From/Ex-Works Cost因为规范化后正好等于字段名(effective_from/ex_works_cost)而高置信度命中 —— 所以这不是全面失效,是按语言而定的部分失效:英文部署碰不到,中文部署碰得到。影响面不限于我们
向导对任何对象都不发
mappingName。所以「应用注册一份命名映射,客户就不用手工映射列」这个承诺,目前只在走接口时成立。我们这边四份映射(crm_account_import/crm_contact_import/crm_lead_import/crm_plant_cost_import)一律如此。为什么我们不在应用侧变通
我们的维护者今天定了一条原则,逐字:
我们确实考虑过在应用里做一个固定带
mappingName调接口的专用 action/页面 —— 已否决。那是拿 app 去补平台的洞:能解决我们这一张表,解决不了通用问题,还会让「导入」在同一个产品里有两种入口、两种行为。所以我们选择上报并等平台,界面侧目前只在文档里写清两条通道的差别。建议方向
mode/upsertKey调接口,而不是用临时投影。这是最贴合「元数据即产品」的一条:映射已经是被声明的元数据,向导只是没去读它。mappingName透传(当对象只注册了一份映射时默认选它),让声明过的mode生效。复现
下游登记:
steedos-labs/hotcrm-heimao#117(含完整抓包与两条通道的逐行对照)。