1. 计划库宿主
插件化手册
  • FH2 插件开发手册
    • 产品简介
    • 典型场景
    • 发版说明
    • 快速开始
      • 快速开始总览
      • 第一个插件
      • 后端插件
      • 全栈闭环
    • AI辅助开发
      • AI 开发 Skill
      • 安装与复验
      • 第一个工程
      • 真实需求示例:现场问题上报
      • 改造已有工程
      • 调试与交付
    • 开发指南
      • 开发指南
      • 基础概念
        • 基础概念总览
        • 什么是插件开发
        • 平台架构
        • 前端宿主、扩展点与能力
        • 后端运行时、入口与权限
        • 开发流程
        • 安全与隔离
        • 支持范围与问题反馈
      • 开发指南
        • 开发指南总览
        • 前端插件
          • 前端插件深度指南
          • 前端工程结构
          • 插件清单(fh2-plugin.json)
          • 入口与生命周期
          • 界面与状态
          • 多宿主插件
          • 跨宿主通信服务
          • HTTP、WebSocket 与事件
          • 存储、Blob 与定时器
          • 工具链与本地调试页面
        • 后端插件
          • 后端开发深度指南
          • 后端插件的结构
          • 后端源清单 fh2-plugin.json
          • HTTP 接口处理函数
          • 消息订阅与事件处理函数
          • ctx 与能力注入
          • 数据存储与缓存
          • 流程编排
          • 触发方式
          • 连接外部系统
          • 流程编排练习(DAG)
        • 前后端协作
          • 前后端协作总览
          • 前后端共享契约
          • 端到端幂等
          • 事件、通知与状态
          • 统一错误模型
          • 链路标识与诊断日志
        • 完整练习
          • 环境准备
          • 第一个前端插件
          • 第一个后端插件
          • 第一个全栈插件
      • 能力总览
        • 能力地图
        • 能力可用性矩阵
        • 前端能力
          • 平台通用能力
            • 平台通用能力总览
            • 基础运行时:HTTP、事件、WebSocket 与存储
            • 导航、位置与通知
            • 弹窗、音频与剪贴板
            • 地图能力
            • 项目设备能力
            • WPMZ 与航线预览
            • 受控对象上传
          • 项目宿主
            • 项目宿主总览
            • 项目上下文
            • 项目侧边栏入口
            • 项目插件路由
            • 项目工作区
          • 消息宿主
            • 消息宿主总览
            • 消息告警弹层
            • 消息导航与通知
          • 计划库宿主
            • 计划库宿主总览
            • 计划库表单上下文
            • 计划库表单扩展
            • 校验、提交与 `biz_ext`
          • 驾驶舱
            • 驾驶舱插件能力总览
            • 驾驶舱扩展点
            • 上下文与遥测
            • 相机、检测与 AI
            • 场景几何与直播指针
            • 飞控、云台与任务
            • 驾驶舱平台事件
        • 后端能力
          • 后端能力地图
          • 后端能力总览
          • 配置、受管出网与集成连接
          • 事件与流程
          • 飞行任务与违停巡逻
          • 数据存储
          • 媒体与前端通知
          • 资源租约
          • 作业、目标轨迹与视频处理
      • 调试与测试
        • 调试与测试总览
        • 快速入门排错
        • 本地开发
        • Web IDE:打开工程与保存改动
        • 工作流编辑器:节点、接线与交付
        • 知识与 MCP:先判断需要哪一层事实
        • 前端本地调试
        • 后端运行时与流程调试
        • 模拟数据与测试数据
        • 集成测试与 E2E
        • 日志与链路追踪
        • 常见问题排查
      • 完整示例
        • 示例与案例总览
        • 项目侧边栏与工作区
        • 消息告警卡片
        • 计划表单任务清单
        • 驾驶舱动作与左侧面板
        • 最小后端插件
        • 最小全栈插件
        • 多宿主插件实战
        • 事故快处
        • 交通抓拍
        • 违停巡逻完整案例
      • 构建发布与安全
        • 构建、发布与安全
        • 质量门禁
        • 行业包构建与打包
        • 能力版本发布
        • 安装、升级与回滚
        • 安全基线
      • API参考
        • API 参考总览
        • 前端
          • 前端 API 参考
          • 前端插件清单结构
          • 前端 SDK API
          • 前端扩展点目录
          • 前端能力目录
          • 前端平台事件目录
          • 跨宿主通信服务 API
          • 工具链命令行参考(`fh2-plugin`)
        • 后端
          • 后端 API 参考
          • 后端插件源清单
          • 后端 HTTP 接口参考
          • 后端事件消费参考
          • 后端脚本上下文(`ctx`)
          • 后端数据存储
          • 流程编排语言
          • 流程触发器参考
          • 后端能力目录
          • 后端 HTTP API
        • 共享契约
          • 共享契约参考
          • 类型与契约目录
          • 错误模型
          • 版本兼容性
      • 附录
        • 错误码
        • 术语表
        • 常见问题
  1. 计划库宿主

校验、提交与 `biz_ext`

提交顺序#

plan.form-extensions 在原生表单与设备业务校验通过后运行:
1.
生成可以用 JSON 表达的 PlanFormDraft。
2.
对所有匹配贡献按 PluginPlan 顺序执行 validate(input)。
3.
任一返回 invalid 或抛错,立即阻断,不执行任何 onSubmit。
4.
全部通过后,再按相同顺序执行所有 onSubmit(input)。
5.
校验每个 patch 的 biz_ext 形状和任务归属互斥。
6.
检查 patch 是否与原生 body 或其他插件字段冲突。
7.
将 patch 合并到原生任务请求体,调用原生 POST/PUT。
anchor 不改变该顺序。validate 必须无副作用;需要 WPMZ 改写、临时资源或后端准备时放在 onSubmit,并保证幂等。

字段冲突规则#

onSubmit 返回 Record<string, PluginValue>,但不是任意覆盖接口:
patch key 已存在于原生任务 body:整体阻断,提示与任务原有字段冲突。
两个插件返回相同 patch key:整体阻断。
多个插件各自返回非空 biz_ext:整体阻断,提示“多个插件任务开关不能同时开启”。
{ biz_ext: {} } 视为未声明归属,不进入最终提交体。
抛错或冲突后不发送原生任务请求。create/copy 会调用现有航线副本清理与 UUID 恢复;edit 不删除当前 TaskWayline。
插件通常不应返回原生字段。即使 PlanFormDraft 有开放索引,覆盖 name、task_type、wayline_uuid 等原生字段也会被宿主拒绝。

biz_ext 精确限制#

计划库总体约束是:整体不超过 4 KB、顶层 key 不超过 8 个、每个 key 不超过 64 字符。插件提交管线进一步收紧为:
规则当前实现
形状非 null 普通对象,不能是数组
单插件 key 数最多 1 个;0 个表示未声明归属
同任务业务插件数最多 1 个非空 owner
key 长度JavaScript key.length <= 64
大小当前代码检查 JSON.stringify(bizExt).length <= 4096
value类型上必须满足 PluginValue;实际提交应进一步限制为可以用 JSON 表达的小型、可演进对象
注意:实现的错误文案写“4 KB”,但当前比较的是 JSON 字符串长度,不是 TextEncoder 的 UTF-8 字节数。包含大量中文时不要贴边,建议远小于 4096;后端仍可能按真实字节限制拒绝。虽然 TypeScript 的 PluginValue 还允许 BigInt、Blob、Map 等结构化克隆值,当前大小检查会对 biz_ext 调用 JSON.stringify,这些值会抛错或丢失语义,因此 biz_ext 只能使用 JSON 可表达的数据。
推荐 key 使用稳定业务标识,例如:
{
  "biz_ext": {
    "parking-patrol": {
      "schemaVersion": 1
    }
  }
}
不要用插件显示名、版本号或用户输入作为顶层 key。

复制与编辑#

复制:sourceBizExt 只供插件恢复开关。插件必须在 onSubmit 重新贡献 biz_ext;宿主不自动复制。若源任务有非空 biz_ext,但没有匹配的表单扩展,宿主阻断复制并提示源任务依赖的业务插件不可用。
编辑:扩展 UI 不渲染。宿主把源任务 biz_ext 原样放回 PUT,避免普通编辑清空归属;所有实现 onEditSubmit 的插件都会被调用,所以每个插件先检查 form.biz_ext 是否包含自己的 key。onEditSubmit 返回 void,不能返回字段 patch。

完整真实场景:提交前改写任务航线#

清单:
{
  "permissions": ["platform:wpmz", "plan:form-context"],
  "extensions": [
    {
      "id": "patrol-form",
      "point": "plan.form-extensions",
      "planType": "normal",
      "anchor": "task-strategy:after"
    }
  ]
}
插件入口核心实现:
const BIZ_KEY = 'parking-patrol'
const CONTINUOUS_TASK = 5

export async function contributePatrolForm (
  ctx: AppPlanContext,
  enabled: () => boolean,
) {
  async function rewrite (projectId: string, waylineId: unknown) {
    if (typeof waylineId !== 'string' || waylineId.length === 0) {
      throw new Error('巡逻任务需要已生成的任务航线')
    }
    const wpmz = await ctx.capabilities.get('platform:wpmz')
    if (!wpmz) throw new Error('平台航线改写能力不可用')
    await wpmz.rewrite({
      target: { projectId, waylineId },
      changes: { missionConfig: { finishAction: 'no-action' } },
    })
  }

  return ctx.extensions.contribute('patrol-form', {
    render: () => patrolFormView.get(ctx),
    validate: async ({ context, form }) => {
      if (!enabled()) return { valid: true }
      if (context.isMultiWayline) {
        return { valid: false, message: '多航线任务暂不支持巡逻' }
      }
      if (form.vlm_enabled === true) {
        return { valid: false, message: '多模态识别任务暂不支持巡逻' }
      }
      if (form.task_type === CONTINUOUS_TASK) {
        return { valid: false, message: '连续执行任务暂不支持巡逻' }
      }
      if (!form.wayline_uuid) {
        return { valid: false, message: '请先选择航线' }
      }
      return { valid: true }
    },
    onSubmit: async (input) => {
      if (!enabled()) return {}
      await rewrite(input.context.projectId, input.form.wayline_uuid)
      return {
        biz_ext: {
          [BIZ_KEY]: { schemaVersion: 1 },
        },
      }
    },
    onEditSubmit: async (input) => {
      if (!input.form.biz_ext || !(BIZ_KEY in input.form.biz_ext)) return
      await rewrite(input.context.projectId, input.form.wayline_uuid)
    },
  })
}
该模式把纯业务检查放在 validate,把受控 WPMZ 副作用放在全部插件校验通过后的 onSubmit。create/copy 后续失败时计划宿主会清理本轮任务航线副本;插件自己创建的后端资源仍需幂等键和补偿策略。

已知限制#

create/copy 中若原生草稿构建抛错或返回 null,当前实现允许原生流程继续且插件不参与;不要把扩展校验当作原生必填校验替代品。
validate 全通过后,前一个插件的 onSubmit 可能已产生副作用,而后一个插件失败。宿主只能清理它掌握的任务航线副本,不能回滚任意插件后端。
workflow create/edit 在插件管线前返回,当前不支持该扩展点的提交扩展。
edit 调用所有 onEditSubmit 实现而不按 planType 过滤,归属判断不可省略。
多插件 patch 合并没有“后写覆盖”,任何冲突都是硬错误。

验证清单#

两个贡献时确认所有 validate 先于任一 onSubmit,顺序稳定。
invalid、throw、原生字段冲突、插件字段冲突和两个 biz_ext owner 都阻断请求。
覆盖 biz_ext 为 null、数组、两个 key、超长 key、接近大小上限和空对象。
复制时验证源归属恢复、重新贡献和业务插件缺失时阻断。
编辑时验证不渲染 UI、非本插件任务直接返回、原 biz_ext 原样进入 PUT。
WPMZ 或原生 POST 失败后确认航线副本清理,并验证插件后端幂等/补偿。

API 参考#

扩展点字段与提交入参:前端扩展点目录。
WPMZ 改写契约:前端能力目录。
修改于 2026-10-22 07:06:55
上一页
计划库表单扩展
下一页
驾驶舱插件能力总览
Built with