Files
iot-device-management-frontend/apps/web-antd/src/views/iot/rule/chain/api/node-metadata.ts
lzh 7b1a0132d0 [F3] DAG 画布属性面板 + 动态表单机制
主会话(Opus)自做,覆盖任务卡 §2 全部文件。

核心文件:
- apps/web-antd/src/views/iot/rule/chain/api/node-metadata.ts
  - GET /iot/rule/provider/metadata API 封装
  - ProviderMetadata/FormCreateSchema/FormCreateRuleItem 类型定义
- apps/web-antd/src/views/iot/rule/chain/stores/selected-node.ts
  - Pinia store: current 节点 + dirty 标记 + metadata 缓存
  - metadataByType O(1) 索引 + getSchemaByType/getMetadataByType 查表
  - loadMetadata fetcher 可注入(测试 + 后端未就绪 fallback 到 mock)
- apps/web-antd/src/views/iot/rule/chain/components/node-schema/index.ts
  - 7 种节点 mock schema (device_state/device_property/timer/expression/
    property_set/alarm_trigger/notify)
  - buildMockMetadata() 供 fallback 使用
- apps/web-antd/src/views/iot/rule/chain/components/DynamicNodeForm.vue
  - @form-create/ant-design-vue 封装,schema 切换自动 resetFields
  - "i18n:" 前缀约定递归解析 title/placeholder/options.label/validate.message
  - 过滤 undefined 避免 configuration 写入噪声
- apps/web-antd/src/views/iot/rule/chain/components/DagPropertyPanel.vue
  - 面板容器:节点名称输入 + DynamicNodeForm
  - onMounted 加载 metadata,后端失败 fallback 到 mock(node-schema)

测试:
- selected-node-store.spec.ts 13 用例(store actions / loadMetadata /
  getSchemaByType / reset)
- node-schema.spec.ts 12 用例(mock schema 覆盖 5+ 种 / buildMockMetadata 映射)

i18n: iot.dag.panel.* / iot.dag.field.* / iot.dag.option.* / iot.dag.validate.*
      zh-CN 与 en-US 同步新增。

Known Pitfalls 落地:
- 评审 B5/H2: 模板变量用 ${data.x}/${alarm.x}/${trigger.x} 占位(notify template
  placeholder 字面展示,禁用旧 $[...] 语法)
- form-create schema 切换时调用 fApi.resetFields 防止字段残留
- configuration 过滤 undefined 防止响应式写入 null
- iot:subsystem:simple-list 权限 403 由 @vben/request 拦截器统一处理
- TS 严格模式零 any,configuration 类型 Record<string, unknown>

决策 5 双入口:
- 本任务仅新建 chain/ 目录的组件 + store + API + mock schema
- 路由追加由后续任务处理(项目采用动态菜单机制,静态路由 modules/iot.ts
  仅放 hideInMenu 详情页;chain 的 list/edit 菜单由后端 menu 表配置)
- 现有 iot/rule/scene/* 保持不变 ✓

质检:
- pnpm test:unit src/views/iot/rule/chain → 48/48 通过
- pnpm lint apps/web-antd/src/views/iot/rule/chain/ → 0 errors
- pnpm check:type (web-antd) → chain 目录 0 errors(其他模块预存错误与本任务无关)

note: DagPropertyPanel + DynamicNodeForm 的渲染集成测试留给 F7 edit.vue 真实画布
      dogfood;本次 unit test 覆盖纯函数与 store。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 23:12:11 +08:00

66 lines
2.5 KiB
TypeScript
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.

/**
* F3 — 节点 Provider Metadata API
*
* 后端 B4/B5/B6 Provider SPI 暴露每个节点类型的 form-create schema。
* 前端启动(或打开规则链编辑页)时一次性拉取,缓存到 Pinia。
*
* 后端 B4/B5/B6 未就绪时使用 mock对齐 F2 `useNodeCatalog` 的 NodeTypeMeta
* 并扩展 `schema.rule` 字段。
*/
import type { NodeTypeMeta } from '#/components/iot-dag';
import { requestClient } from '#/api/request';
// ──────────────────────────────────────────────
// 类型定义
// ──────────────────────────────────────────────
/** form-create rule 单项 — 与 @form-create/ant-design-vue 的 Rule 对齐(宽松定义) */
export interface FormCreateRuleItem {
/** 组件类型select / input / DeviceSelector 等) */
type: string;
/** 字段名 */
field?: string;
/** 显示标题i18n key 或原始文案) */
title?: string;
/** 组件 props */
props?: Record<string, unknown>;
/** 下拉选项 */
options?: Array<{ label: string; value: boolean | number | string }>;
/** 校验规则antd Form rule 风格) */
validate?: Array<Record<string, unknown>>;
/** 默认值 */
value?: unknown;
/** 子项(嵌套表单) */
children?: FormCreateRuleItem[];
}
/** form-create schema完整 */
export interface FormCreateSchema {
/** 字段规则数组 */
rule: FormCreateRuleItem[];
/** 全局 optionsubmitBtn / resetBtn 等) */
option?: Record<string, unknown>;
}
/** Provider 节点元数据(含 schema比 NodeTypeMeta 多一层) */
export interface ProviderMetadata extends NodeTypeMeta {
/** 动态表单 schemaform-create 配置) */
schema: FormCreateSchema;
}
// ──────────────────────────────────────────────
// API
// ──────────────────────────────────────────────
/**
* 拉取所有 Provider 节点元数据(含 schema
*
* 后端端点约定:`GET /iot/rule/provider/metadata`
* B4/B5/B6 就绪后返回结构需对齐 `ProviderMetadata[]`。
*/
export function getProviderMetadata(): Promise<ProviderMetadata[]> {
return requestClient.get<ProviderMetadata[]>('/iot/rule/provider/metadata');
}