# 智能体物料导入 - 前端联调方案 ## 涉及页面 - 物料管理 - 物料列表(入口与结果确认) - 物料管理 - 智能体导入(上传、审核、提交、回执) ## 业务定位 智能体导入是独立于 Excel 批量导入的新入口:用户上传物料清单,智能体解析并调用 Java 主数据预检,用户核对后提交。**本阶段只新建物料**;编码已存在时跳过,不更新原物料,不触发 MES 同步。 ## 业务流程与数据带入 1. 进入导入页 → 前端创建补录会话,拿到 `sessionId`。 2. 选择 Excel/CSV → 走既有文件上传,拿到 `blobId`。 3. 将 `blobId` 绑定到会话 → 拿到 `attachmentId`。附件归属、大小与格式由后端校验。 4. 用 `attachmentId` 创建智能体任务 → 返回任务 ID、候选行、Java 预检结果(分类、单位、编码状态)与人审中断信息。 5. 用户在审核页修订字段并重新检查 → 每次修订后 `revision` 加 1,并重新预检。 6. 用户确认 → 提交;成功后展示逐行回执。 7. 结果页可再次查询回执;任务 ID 可回查任务状态。 关键带入关系: | 来源 | 带入目标 | 字段 | |---|---|---| | 文件上传 | 会话绑定 | `blobId` | | 会话绑定 | 创建任务 | `attachmentId`(不是 blobId) | | 创建任务响应 | 审核页 | `task_id`、`state.revision`、`state.preflight`、`interrupts` | | 预检结果 | 确认请求 | `state.preflight_hash` | | 审核修订 | 下一次预检 | 修订后的字段值,`revision` 自增 | | 提交响应 | 回执页 | `receipt.rows[].targetItemId`、`status` | ## API ### Java 管理端(`/admin-api`,携带用户 Bearer token) | 方法 | 路径 | 说明 | |---|---|---| | POST | `/agent/bridge/import-sessions` | 创建补录会话,返回 `sessionId` | | POST | `/agent/bridge/import-sessions/{sessionId}/attachments` | 绑定附件,返回 `attachmentId` | **绑定请求参数:** | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `blobId` | Long | 是 | 既有上传接口返回的 blob ID | **限制:** - 同一会话重复绑定会替换旧附件,旧 `attachmentId` 随后不可用。 - 文件上限 8 MiB,仅允许 CSV/XLSX。 - 用户需具备 `mdm:item:import` 权限,否则返回 403 `FORBIDDEN`。 ### Python 智能体服务(默认 `http://127.0.0.1:8091`,携带同一用户 Bearer token) > Python 服务不在 `/admin-api` 下,需由网关或前端代理转发;服务口令 `X-Agent-Service-Token` 由 Python 服务内部使用,**前端不得携带或下发**。 | 方法 | 路径 | 说明 | |---|---|---| | POST | `/v1/material-imports` | 创建任务并触发预检,返回任务与审核中断 | | GET | `/v1/material-imports/{task_id}` | 读取任务当前状态 | | POST | `/v1/material-imports/{task_id}/review` | 修订或确认 | | GET | `/v1/material-imports/{task_id}/receipt` | 查询提交回执 | **创建任务请求参数:** | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `attachment_id` | String | 是 | Java 返回的附件 ID | | `filename` | String | 否 | 兼容字段,解析以 Java 返回的文件名为准 | **创建任务响应:** | 字段 | 类型 | 说明 | |---|---|---| | `task_id` | String | 任务 ID,后续读取/审核/回执均使用 | | `state.revision` | Integer | 方案版本,确认时必须回传当前值 | | `state.candidates` | Array | 解析后的候选行及单元格来源 | | `state.issues` | Array | 字段缺失、重复编码等本地校验问题 | | `state.preflight` | Object | Java 预检结果:`can_commit`、`summary`、`rows[]` 等 | | `state.preflight_hash` | String | 预检计划摘要 | | `interrupts` | Array | 人审中断信息,`type=material_review` | **审核请求参数:** | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `expected_revision` | Integer | 是 | 当前 `state.revision` | | `action` | String | 是 | `revise` / `confirm` / `cancel` | | `corrections` | Array | 修订时必填 | 每项含 `candidate_id`、`field`、`value`、`reason` | | `expected_preflight_hash` | String | 确认时建议填写 | 当前 `state.preflight_hash` | | `expected_proposal_hash` | String | 否 | 二次确认时校验方案未变化 | **回执响应关键字段:** | 字段 | 说明 | |---|---| | `status` | `SUCCEEDED` / `PARTIAL_FAILED` / `FAILED` / `UNKNOWN` | | `summary` | `total/success/failed/skipped/unknown` | | `rows[].action` | `CREATE` / `SKIP` | | `rows[].status` | `SUCCESS` / `SKIPPED` / `FAILED` / `UNKNOWN` | | `rows[].targetItemId` | 新建物料 ID;`SKIP` 行为已有物料 ID | | `rows[].errorCode` / `errorMessage` | 行级失败原因 | | `rows[].retryable` | 是否建议重试 | ## 字段展示规则 | 字段 | 展示位置 | 说明 | |---|---|---| | 物料编码 | 审核列表、回执 | 文件内重复时整批阻断 | | 物料名称 | 审核列表、回执 | 为空时阻断该行 | | 规格型号 | 审核列表 | 可选 | | 分类编码 | 审核列表 | 预检解析为 `resolved.categoryName` 后优先显示名称 | | 计量单位编码 | 审核列表 | 预检解析为 `resolved.unitMeasureName` 后优先显示名称 | | 行动作 | 审核列表 | `CREATE` 新建、`SKIP` 已存在将跳过、`BLOCKED` 阻断 | | 阻断/警告 | 审核列表行内 | 展示 `blockers[]`、`warnings[]` 的 `message`,并高亮该行 | | 预检汇总 | 审核页顶部 | 总数、新建、跳过、阻断 | | 是否可提交 | 审核页底部 | 由 `preflight.can_commit` 与 `state.issues` 共同决定 | | 目标物料 ID | 回执页 | `rows[].targetItemId`,可跳转物料详情 | | 回执汇总 | 回执页顶部 | 成功、跳过、失败、未知数量 | ## 业务规则说明 | 场景 | 规则 | |---|---| | 编码已存在 | 预检 `SKIP`,不阻断整批;提交时跳过,不更新原物料 | | 分类/单位不存在 | 该行 `BLOCKED`,整批不可提交;提示用户修正编码 | | 文件内编码重复 | 所有重复行均 `BLOCKED` | | 请求同步 MES | 返回阻断项 `MES_SYNC_DISABLED`;本阶段不支持 | | 超过 5000 行 | 整批阻断 `ROW_LIMIT_EXCEEDED` | | 方案被修订 | `revision` 自增,必须用新版本重新确认 | | 确认后数据变化 | 提交时重新预检;计划变化返回 409 `PLAN_STALE`,需重新读取并确认 | | 重复点击提交 | 服务端幂等,返回原回执,不重复建物料 | | 提交超时 | 前端应查询回执,不要重新发起确认 | | 写开关关闭 | Python 返回 409 `COMMIT_DISABLED`;Java 返回 503 `WRITE_DISABLED` | ## 注意事项 - 前端只携带用户登录 token;服务口令、附件下载接口仅限 Python 服务内网访问。 - `attachmentId` 不是 `blobId`,绑定接口返回的才是任务入参。 - 确认前必须重新读取任务,使用最新的 `revision` 与 `preflight_hash`;禁止缓存旧值直接确认。 - 409 `PLAN_STALE` 与 409 `COMMIT_DISABLED` 语义不同:前者需重新预检,后者需联系管理员打开写开关。 - `SKIP` 行也会出现在回执中,展示为“已存在,已跳过”,不是失败。 - 任务按租户 + 用户隔离,换账号或跨租户访问返回 404。 - 本阶段不提供进度推送;提交为同步请求,前端需设置足够长的超时(建议 120 秒),超时后查询回执。 - 不支持更新已有物料;如业务需要修改物料,仍走既有物料编辑流程。 ## AI 总开关 - 开关项:`VITE_APP_AI_ENABLE`(默认 `true`,设为 `false` 即关闭)。 - 关闭后:不注册 `/ai` 模块路由;物料列表「智能体导入」、发票/报价「识别录入」、工单 AI 预测、质检 AI 判定与质检助手全部隐藏;已打开的页面刷新后生效。 - 开关只影响前端入口,不改变后端接口与权限;后端仍按各自业务/写开关独立控制。 - 前端通过 `@vben/hooks` 的 `isAiEnable()` 读取,业务页面自定义按钮需同样用该方法包裹显示条件。