跳到主要内容

批量操作

状态

本文说明当前代码实现的接入规则,不代表各环境已发布或可用。批量导入、批量删除接口是否已在目标环境启用,以 MCP 元工具 search_apis / 管理员控制台为准。

一次要新建或删除几十上百条数据时,不要循环调用单条的 create / delete: 每次调用都要走一遍鉴权、权限与转发,单条失败也不好汇总;循环写入时一旦某次超时, 还会陷入「这一条到底写没写进去」的不确定状态。

开放平台为批量场景提供两类专用接口:

场景接口执行方式
批量新建各服务的 data-task-center.import-rows + import-result异步:提交后生成导入任务,轮询取结果
批量删除各实体的 .batch-delete同步:一次返回成功 / 失败条数与原因

本文面向 MCP agent 与 API 集成方,示例均按统一直通入口 POST /v1/api/invoke 书写; MCP 下把同样的 apiCode / query / body 交给 call_api 即可。

批量新建:JSON 行导入​

接口​

每个带导入能力的业务服务都有一组同形接口,与主站「云任务中心」的 Excel 导入共用同一条任务链路—— 业务校验、按行报错与页面上传完全一致,只是把 Excel 换成了 JSON 行:

接口编码后端接口所需范围
<服务>.data-task-center.import-rowsPOST /v1/data-task-center/import-rows<服务>:write
<服务>.data-task-center.import-resultGET /v1/data-task-center/import-result<服务>:read

<服务> 取 srm / sales / finance / project。导入类型属于哪个服务,就必须调哪个服务的接口, 调错服务会返回「不支持的导入任务编码」。

仅系统管理员可用

该入口绕过了各业务页面上的按钮权限,因此收紧为仅本租户系统管理员可调用, 其他身份返回 403「仅系统管理员可通过接口批量导入数据」。

常用导入类型(taskCode)​

服务taskCode导入内容额外参数
srmSRM_PRODUCT物料—
srmSRM_SUPPLIER供应商—
srmSRM_PRICE_BOOK供应商价格本明细params.priceBookId 必填
srmSUBCONTRACT_ORDER委外订单—
srmSRM_INSPECTION_ITEM质检项目—
srmSRM_BRAND品牌—
salesCUSTOMER_DATA_TASK客户 / 联系人params.importCategory:CUSTOMER 或 CONTACT
salesSALES_LEAD_DATA_TASK线索—
salesSALES_OPPORTUNITY_DATA_TASK商机—
financeFIN_OPENING_AR_IMPORT期初应收—
financeFIN_OPENING_AP_IMPORT期初应付—
projectPROJECT_DATA_TASK项目—
projectPROJECT_DRAWING_ARCHIVE_DATA_TASK图纸归档—

以下导入类型依赖多个工作表或专用模板格式,不支持 import-rows,请在主站页面上传 Excel: SRM_BOM(BOM)、SRM_PRD_GROUP(物料分组)、FIN_BANK_TXN_IMPORT(银行流水)。

请求体​

字段必填说明
taskCode是导入类型,见上表
columns是有序列定义 [{field, header}]。field 是系统字段标识;header 是表头文字,可省略(省略时用 field)。最多 200 列
rows是数据行,每行是 {<field>: 值},值只能是文本、数字或布尔值。可带保留键 rowKey(调用方自己的行标识,≤128 字符,同一任务内不可重复),用于回查结果
params否该导入类型的业务参数(如 importCategory、priceBookId)。未提供 columnMappings 时服务端按 columns 顺序自动生成
requestId强烈建议幂等键:同一用户 + 导入类型 + requestId 在 24 小时内重复提交,直接返回首次结果(deduplicated: true),不会重复建任务
sessionId分批时必填分批上传会话标识。不传表示本次请求即全部数据
chunkIndex分批时必填批次序号,从 0 开始连续递增
finalChunk分批时必填最后一批传 true,服务端此时合并已暂存的全部行并创建任务

requestId 与 sessionId 只能包含字母、数字、下划线、中划线、点或冒号,且不超过 64 个字符。

字段标识从哪里来:columns[].field 与主站该业务导入模板的列一一对应。先用 describe_api 查看 import-rows 的参数说明;自定义字段标识可用 system.field.list 查询,见字段清单与自定义字段。

容量上限​

维度上限
单次请求500 行
单个导入任务(含全部分批)5000 行
单个导入任务的单元格数(行数 × 列数)200,000
单个导入任务的数据总量约 10MB 文本

超过 5000 行请拆成多个导入任务(多个 sessionId),而不是加大单批。

超过 500 行:分批上传​

同一 sessionId 的各批按顺序串行提交——等上一批返回后再发下一批,不要并发:

  1. 第一批 chunkIndex: 0,带上完整的 params;
  2. 后续批次 chunkIndex 依次加 1,省略 params(若携带,必须与第一批完全相同);
  3. 每批的 columns 必须与第一批完全一致(字段与顺序);
  4. 最后一批 finalChunk: true,此时才返回 taskId;中间批次只返回 sessionId 与已暂存行数 stagedRows。

每批使用各自的 requestId。某一批超时或结果不明时,用同一个 requestId 原样重发这一批: 已成功的会直接返回首次结果,不会重复暂存;换一个 requestId 重发则可能写入两次。

会话 30 分钟未完成即失效,返回「导入会话已失效」时,请换一个新的 sessionId 从 chunkIndex: 0 重新提交。

示例:分两批导入客户​

第一批(chunkIndex: 0,带 params):

{
"apiCode": "sales.data-task-center.import-rows",
"body": {
"taskCode": "CUSTOMER_DATA_TASK",
"requestId": "crm-sync-20260929-c0",
"sessionId": "crm-sync-20260929",
"chunkIndex": 0,
"finalChunk": false,
"params": { "importCategory": "CUSTOMER" },
"columns": [
{ "field": "name", "header": "客户名称" },
{ "field": "categoryId", "header": "客户分类" },
{ "field": "ownerId", "header": "负责人" },
{ "field": "primaryContact", "header": "首要联系人" },
{ "field": "primaryPhone", "header": "联系电话" }
],
"rows": [
{ "rowKey": "ext-1001", "name": "示例科技有限公司", "categoryId": "重点客户", "ownerId": "张三", "primaryContact": "李四", "primaryPhone": "13800000001" },
{ "rowKey": "ext-1002", "name": "示例贸易有限公司", "categoryId": "普通客户", "ownerId": "张三", "primaryContact": "王五", "primaryPhone": "13800000002" }
]
}
}

返回(中间批次,只暂存不建任务):

{ "code": 200, "message": "success", "data": { "taskCode": "CUSTOMER_DATA_TASK", "sessionId": "crm-sync-20260929", "stagedRows": 2 } }

第二批(最后一批,省略 params,columns 与第一批一致):

{
"apiCode": "sales.data-task-center.import-rows",
"body": {
"taskCode": "CUSTOMER_DATA_TASK",
"requestId": "crm-sync-20260929-c1",
"sessionId": "crm-sync-20260929",
"chunkIndex": 1,
"finalChunk": true,
"columns": [
{ "field": "name", "header": "客户名称" },
{ "field": "categoryId", "header": "客户分类" },
{ "field": "ownerId", "header": "负责人" },
{ "field": "primaryContact", "header": "首要联系人" },
{ "field": "primaryPhone", "header": "联系电话" }
],
"rows": [
{ "rowKey": "ext-1003", "name": "示例制造有限公司", "categoryId": "重点客户", "ownerId": "赵六", "primaryContact": "孙七", "primaryPhone": "13800000003" }
]
}
}

返回(已建任务):

{ "code": 200, "message": "success", "data": { "taskId": "2104000000000000001", "taskCode": "CUSTOMER_DATA_TASK", "rowCount": 3, "sessionId": "crm-sync-20260929" } }

示例中的字段标识与取值仅演示结构;客户分类、负责人等引用型字段按名称填写,见下文注意事项。 数据量不超过 500 行时,省略 sessionId / chunkIndex / finalChunk,一次提交即返回 taskId。

轮询结果​

{
"apiCode": "sales.data-task-center.import-result",
"query": { "taskId": "2104000000000000001", "pageNum": 1, "pageSize": 50 }
}

pageNum / pageSize 用于翻阅行级错误,pageSize 默认 20、最大 200。返回示例:

{
"code": 200,
"message": "success",
"data": {
"taskId": "2104000000000000001",
"taskCode": "CUSTOMER_DATA_TASK",
"status": 3,
"statusText": "部分成功",
"finished": true,
"progress": 100,
"totalCount": 3,
"successCount": 2,
"failCount": 1,
"errors": {
"total": 1,
"pageNum": 1,
"pageSize": 50,
"records": [
{ "rowNum": 3, "rowIndex": 1, "rowKey": "ext-1002", "field": "categoryId", "value": "普通客户", "message": "客户分类不存在" }
]
}
}
}
字段说明
status / statusText0 排队中、1 执行中、2 成功、3 部分成功、4 失败、5 已取消
finished任务是否已结束;为 false 时间隔几秒再查,不要紧密轮询
totalCount / successCount / failCount行数统计
errorMessage任务级失败原因(如数据无法解析),此时可能没有行级错误
errors.records[]行级错误:rowNum 为 Excel 行号(表头为第 1 行)、rowIndex 为提交数据的下标(从 0 起)、rowKey 为你提交的行标识,field / value 仅在错误可定位到单个字段时返回

只重新提交失败的行:按 rowKey(或 rowIndex)找出失败行,修正后作为一个新的导入任务提交, 使用新的 requestId。不要把整批重发——成功的行已经写入,重发会产生重复数据。

只能查询自己创建的任务;系统管理员可查询本租户全部任务。任务同样出现在主站「云任务中心」。

注意事项​

  • 引用型字段按名称解析:客户负责人、所属客户、供应商等字段填写的是名称,服务端按名称匹配。 租户内存在同名数据时可能匹配到非预期的记录,导入前先确认名称唯一。
  • 很多导入只新增、不去重:同一份数据提交两次就会生成两份记录。每次提交都带 requestId, 重试同一批时复用它。
  • 单据类导入只生成草稿:导入的单据不会自动提交审批或过账,后续流程仍需在主站或经对应接口处理。
  • 行级校验复用主站页面导入的同一套逻辑,报错提示与页面导入一致。

批量删除​

接口与请求体​

批量删除接口的编码形如 <域>.<实体>.batch-delete(如 sales.customer.batch-delete), 可用 search_apis 按「批量删除」检索。它们都是高危接口:MCP 调用须先向用户逐项复述将要删除的对象, 获得明确同意后携 confirm: true 调用。删除不可逆,不能由 agent 自行决定。

请求体是裸 JSON 数组,元素为待删除记录的 id(不是 { "ids": [...] } 对象):

{
"apiCode": "sales.customer.batch-delete",
"body": ["2104000000000000011", "2104000000000000012", "2104000000000000013"]
}

上限与返回​

范围单次上限
默认200 条
销售订单、发货单50 条

超过上限直接拒绝并提示分批提交。本次新增的批量删除逐条独立处理, 不满足删除条件(状态不允许、无权限、已被下游单据引用等)的记录跳过,其余照常删除,返回:

{
"code": 200,
"message": "success",
"data": {
"totalCount": 3,
"successCount": 2,
"failCount": 1,
"failReasons": ["示例贸易有限公司:存在关联单据,不允许删除"]
}
}

totalCount 为去重后的条数。failCount > 0 时把 failReasons 原样转告用户,不要自动重试失败项—— 它们多半需要先处理业务状态。

既有的批量删除保持整批语义

物料、供应商、BOM、供应商价格本等此前已开放的 srm 批量删除保持原有的「全部成功或全部失败」语义: 任一条不满足条件即整批不删。其返回结构以 describe_api 为准。

超时与重试​

直通转发对下游的读超时为 30 秒。批量写入更容易触及这个上限,超时后的处理方式取决于接口类型:

情况返回含义正确做法
写接口等待下游响应超时92205 写操作处理超时,结果未知请求已送达,下游可能仍在执行先查询业务数据(或 import-result)确认结果,再决定是否补做
超时后立即重发同一写请求92302 该请求正在处理中结果未知时防重锁续持 120 秒不要重发;先查询
读接口超时 / 连接失败92203 上游服务调用失败请求未完成读操作可重试

禁止盲目重试写操作。对 import-rows 而言,结果不明时用同一个 requestId 重发是安全的; 对其他写接口,先查询再决定。完整错误码见错误码。

给 agent 的建议流程​

  1. search_apis 找到对应服务的 import-rows / batch-delete,describe_api 看参数说明;
  2. 向用户复述:导入类型、行数、关键字段取值(删除则逐项列出对象),获得明确同意;
  3. 按 500 行一批串行提交,每批一个 requestId;
  4. 轮询 import-result 直到 finished: true,向用户汇报成功 / 失败条数;
  5. 只把失败行修正后作为新任务提交;遇到 92205 / 92302 先查询,不自动重发。