@arronqzy/vue-blueprint 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/package.json +44 -0
- package/src/BlueprintCanvasContext.ts +71 -0
- package/src/BlueprintNodeConfigSidebar.vue +338 -0
- package/src/blueprint.css +327 -0
- package/src/blueprintNodeTypes.ts +20 -0
- package/src/components/BluePrintVueRoot.vue +73 -0
- package/src/components/BlueprintCanvas.vue +220 -0
- package/src/components/BlueprintContextMenu.vue +114 -0
- package/src/components/BlueprintExecutionLogPanel.vue +294 -0
- package/src/components/BlueprintMetaDialog.vue +80 -0
- package/src/components/BlueprintNodeSwitchTaskDialog.vue +41 -0
- package/src/components/ClockNodeConfigPanel.vue +124 -0
- package/src/components/FetchNodeConfigPanel.vue +559 -0
- package/src/components/FetchUrlAutocomplete.vue +174 -0
- package/src/components/JsonNodeConfigPanel.vue +73 -0
- package/src/components/LogicNodeConfigPanel.vue +73 -0
- package/src/components/ViewElementMultiSelect.vue +50 -0
- package/src/composables/useBlueprintDebugSession.ts +441 -0
- package/src/composables/useBlueprintFlowState.ts +486 -0
- package/src/composables/useBlueprintFlowViewport.ts +65 -0
- package/src/composables/useBlueprintNodeSelectionGuard.ts +41 -0
- package/src/composables/useBlueprintPageLifecycle.ts +244 -0
- package/src/createBlueprintEdgeTypes.ts +10 -0
- package/src/edges/BlueprintSmoothEdge.vue +31 -0
- package/src/env.d.ts +7 -0
- package/src/fetch-config-task-store.ts +206 -0
- package/src/flowCoordinates.ts +19 -0
- package/src/flowDefaults.ts +9 -0
- package/src/graph/blueprint-graph.ts +265 -0
- package/src/graph/document.ts +422 -0
- package/src/graph/index.ts +7 -0
- package/src/graph/node-summary.ts +88 -0
- package/src/graph/node-types.ts +9 -0
- package/src/graph/sync-edges.ts +69 -0
- package/src/graph/sync-nodes.ts +110 -0
- package/src/graph/vue-flow-adapter.ts +127 -0
- package/src/index.ts +37 -0
- package/src/library/blueprint-io.ts +108 -0
- package/src/library/blueprint-library-db.ts +112 -0
- package/src/library/execution-log-db.ts +171 -0
- package/src/library/execution-log-settings.ts +50 -0
- package/src/library/swagger-docs.ts +56 -0
- package/src/library/types.ts +35 -0
- package/src/nodes/AndFlowNode.vue +60 -0
- package/src/nodes/BlueprintFlowNode.vue +26 -0
- package/src/nodes/BlueprintNodeCard.vue +155 -0
- package/src/nodes/BlueprintNodeShell.vue +70 -0
- package/src/nodes/ClockFlowNode.vue +60 -0
- package/src/nodes/FetchFlowNode.vue +26 -0
- package/src/nodes/JsonFlowNode.vue +26 -0
- package/src/nodes/LifecycleFlowNode.vue +45 -0
- package/src/nodes/LogicFlowNode.vue +26 -0
- package/src/runtime/document-to-runnable-graph.ts +51 -0
- package/src/runtime/execution-overlay.ts +169 -0
- package/src/types.ts +1 -0
- package/src/utils/cn.ts +3 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @arronqzy/vue-blueprint
|
|
2
|
+
|
|
3
|
+
Vue 3 版 Abuilder **蓝图编辑器**,使用 **@vue-flow/core** 与 **Ant Design Vue**,功能与 `@arronqzy/react-blueprint` 对齐。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- 可编辑蓝图画布:拖拽节点、连线、右键菜单
|
|
8
|
+
- 7 种内置节点:Blueprint、Logic、And、Lifecycle、Fetch、Json、Clock
|
|
9
|
+
- 自定义边与执行 overlay 高亮
|
|
10
|
+
- 蓝图库(IndexedDB)、导入/导出
|
|
11
|
+
- 节点配置侧栏、执行日志、调试会话
|
|
12
|
+
- 页面生命周期与 Scope 写入视图
|
|
13
|
+
|
|
14
|
+
## 使用
|
|
15
|
+
|
|
16
|
+
```vue
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
import { ref } from "vue";
|
|
19
|
+
import { BluePrintVueRoot, BlueprintGraph } from "@arronqzy/vue-blueprint";
|
|
20
|
+
import "@arronqzy/vue-blueprint/blueprint.css";
|
|
21
|
+
|
|
22
|
+
const graph = ref(BlueprintGraph.empty());
|
|
23
|
+
const selectedNodeId = ref<string | null>(null);
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
<BluePrintVueRoot
|
|
28
|
+
:graph="graph"
|
|
29
|
+
:selected-node-id="selectedNodeId"
|
|
30
|
+
@graph-change="graph = $event"
|
|
31
|
+
@select-node="selectedNodeId = $event"
|
|
32
|
+
/>
|
|
33
|
+
</template>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 样式
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import "@arronqzy/vue-blueprint/blueprint.css";
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 与 React 版关系
|
|
43
|
+
|
|
44
|
+
- 图数据层(`BlueprintGraph`、document 同步等)为独立 TS 实现,结构与 `react-blueprint` 对齐
|
|
45
|
+
- UI 与画布基于 Vue Flow,不依赖 `@xyflow/react`
|
|
46
|
+
- 长期可抽取共享 `blueprint-core` 消除双份 graph 代码
|
|
47
|
+
|
|
48
|
+
## 许可证
|
|
49
|
+
|
|
50
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arronqzy/vue-blueprint",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Vue 3 blueprint editor for Abuilder (Vue Flow + Ant Design Vue)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"src",
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./src/index.ts",
|
|
13
|
+
"./blueprint.css": "./src/blueprint.css"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@vue-flow/core": "^1.41.2",
|
|
17
|
+
"@vue-flow/background": "^1.3.2",
|
|
18
|
+
"@vue-flow/controls": "^1.1.2",
|
|
19
|
+
"ant-design-vue": "^4.2.6",
|
|
20
|
+
"dayjs": "^1.11.13",
|
|
21
|
+
"vue": "^3.5.13",
|
|
22
|
+
"@arronqzy/blueprint-dsl": "1.0.3",
|
|
23
|
+
"@arronqzy/vue-rx-store": "0.1.0"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"vue": "^3.4.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@vitejs/plugin-vue": "^5.2.1",
|
|
30
|
+
"eslint": "^8.57.0",
|
|
31
|
+
"typescript": "^5.5.4",
|
|
32
|
+
"vue-tsc": "^2.2.0",
|
|
33
|
+
"@arronqzy/eslint-config": "0.0.0",
|
|
34
|
+
"@arronqzy/typescript-config": "1.0.0"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"lint": "eslint \"src/**/*.{ts,vue}\"",
|
|
41
|
+
"typecheck": "vue-tsc -p tsconfig.json --noEmit",
|
|
42
|
+
"build": "pnpm run typecheck"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { isClockNodeActive, subscribeActiveClockNodes } from "@arronqzy/blueprint-dsl";
|
|
2
|
+
import {
|
|
3
|
+
inject,
|
|
4
|
+
onScopeDispose,
|
|
5
|
+
provide,
|
|
6
|
+
ref,
|
|
7
|
+
type InjectionKey,
|
|
8
|
+
type Ref,
|
|
9
|
+
} from "vue";
|
|
10
|
+
|
|
11
|
+
type BlueprintCanvasContextValue = {
|
|
12
|
+
onSelectNodeRef: Ref<((nodeId: string | null) => void) | undefined>;
|
|
13
|
+
onAbortClockRef: Ref<((nodeId: string) => void) | undefined>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const blueprintCanvasContextKey: InjectionKey<BlueprintCanvasContextValue> =
|
|
17
|
+
Symbol("BlueprintCanvasContext");
|
|
18
|
+
|
|
19
|
+
export function provideBlueprintCanvasContext(options: {
|
|
20
|
+
onSelectNode?: (nodeId: string | null) => void;
|
|
21
|
+
onAbortClock?: (nodeId: string) => void;
|
|
22
|
+
}) {
|
|
23
|
+
const onSelectNodeRef = ref(options.onSelectNode);
|
|
24
|
+
const onAbortClockRef = ref(options.onAbortClock);
|
|
25
|
+
|
|
26
|
+
provide(blueprintCanvasContextKey, { onSelectNodeRef, onAbortClockRef });
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
onSelectNodeRef,
|
|
30
|
+
onAbortClockRef,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function syncBlueprintCanvasContext(
|
|
35
|
+
ctx: ReturnType<typeof provideBlueprintCanvasContext>,
|
|
36
|
+
options: {
|
|
37
|
+
onSelectNode?: (nodeId: string | null) => void;
|
|
38
|
+
onAbortClock?: (nodeId: string) => void;
|
|
39
|
+
}
|
|
40
|
+
) {
|
|
41
|
+
ctx.onSelectNodeRef.value = options.onSelectNode;
|
|
42
|
+
ctx.onAbortClockRef.value = options.onAbortClock;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function useBlueprintNodeSelect() {
|
|
46
|
+
const ctx = inject(blueprintCanvasContextKey, null);
|
|
47
|
+
return (nodeId: string) => {
|
|
48
|
+
ctx?.onSelectNodeRef.value?.(nodeId);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function useBlueprintClockAbort() {
|
|
53
|
+
const ctx = inject(blueprintCanvasContextKey, null);
|
|
54
|
+
return (nodeId: string) => {
|
|
55
|
+
ctx?.onAbortClockRef.value?.(nodeId);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function useClockNodeCanAbort(nodeId: string) {
|
|
60
|
+
const canAbort = ref(isClockNodeActive(nodeId));
|
|
61
|
+
|
|
62
|
+
const unsubscribe = subscribeActiveClockNodes(() => {
|
|
63
|
+
canAbort.value = isClockNodeActive(nodeId);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
onScopeDispose(() => {
|
|
67
|
+
unsubscribe();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return canAbort;
|
|
71
|
+
}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, watch } from "vue";
|
|
3
|
+
import { Checkbox, Input, Select } from "ant-design-vue";
|
|
4
|
+
import {
|
|
5
|
+
LIFECYCLE_NODE_TYPE,
|
|
6
|
+
PAGE_LIFECYCLE_LABELS,
|
|
7
|
+
PAGE_LIFECYCLE_PHASES,
|
|
8
|
+
type PageLifecyclePhase,
|
|
9
|
+
} from "@arronqzy/blueprint-dsl";
|
|
10
|
+
|
|
11
|
+
import FetchNodeConfigPanel from "./components/FetchNodeConfigPanel.vue";
|
|
12
|
+
import ClockNodeConfigPanel from "./components/ClockNodeConfigPanel.vue";
|
|
13
|
+
import JsonNodeConfigPanel from "./components/JsonNodeConfigPanel.vue";
|
|
14
|
+
import LogicNodeConfigPanel from "./components/LogicNodeConfigPanel.vue";
|
|
15
|
+
import ViewElementMultiSelect from "./components/ViewElementMultiSelect.vue";
|
|
16
|
+
import {
|
|
17
|
+
patchNodeConfigSource,
|
|
18
|
+
pruneViewElementIds,
|
|
19
|
+
resolveBlueprintConfigSource,
|
|
20
|
+
resolveViewElementIds,
|
|
21
|
+
type BlueprintConfigSource,
|
|
22
|
+
type BlueprintGraphNode,
|
|
23
|
+
} from "./graph/document";
|
|
24
|
+
|
|
25
|
+
export type BlueprintViewElementOption = {
|
|
26
|
+
id: string;
|
|
27
|
+
label: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type BlueprintLibraryOption = {
|
|
31
|
+
id: string;
|
|
32
|
+
label: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type BlueprintNodeConfigSidebarProps = {
|
|
36
|
+
node: BlueprintGraphNode;
|
|
37
|
+
viewElementOptions?: BlueprintViewElementOption[];
|
|
38
|
+
blueprintLibraryOptions?: BlueprintLibraryOption[];
|
|
39
|
+
allowFalseSignalPropagation?: boolean;
|
|
40
|
+
onUpdateAllowFalseSignalPropagation?: (value: boolean) => void;
|
|
41
|
+
onUpdateNode: (
|
|
42
|
+
nodeId: string,
|
|
43
|
+
patch: Partial<
|
|
44
|
+
Pick<
|
|
45
|
+
BlueprintGraphNode,
|
|
46
|
+
| "label"
|
|
47
|
+
| "role"
|
|
48
|
+
| "nodeType"
|
|
49
|
+
| "configSource"
|
|
50
|
+
| "viewElementId"
|
|
51
|
+
| "viewElementIds"
|
|
52
|
+
| "nestedBlueprintId"
|
|
53
|
+
| "libraryBlueprintId"
|
|
54
|
+
| "lifecyclePhase"
|
|
55
|
+
| "fetchConfig"
|
|
56
|
+
| "jsonConfig"
|
|
57
|
+
| "logicConfig"
|
|
58
|
+
| "clockConfig"
|
|
59
|
+
>
|
|
60
|
+
>
|
|
61
|
+
) => void;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const props = withDefaults(defineProps<BlueprintNodeConfigSidebarProps>(), {
|
|
65
|
+
viewElementOptions: () => [],
|
|
66
|
+
blueprintLibraryOptions: () => [],
|
|
67
|
+
allowFalseSignalPropagation: false,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const configSource = computed(() => resolveBlueprintConfigSource(props.node));
|
|
71
|
+
const linkedViewElementIds = computed(() => resolveViewElementIds(props.node));
|
|
72
|
+
const existingViewElementIdSet = computed(
|
|
73
|
+
() => new Set(props.viewElementOptions.map((opt) => opt.id))
|
|
74
|
+
);
|
|
75
|
+
const viewElementLabelById = computed(
|
|
76
|
+
() => new Map(props.viewElementOptions.map((opt) => [opt.id, opt.label]))
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const roleLabel = computed(() => {
|
|
80
|
+
const role = props.node.role;
|
|
81
|
+
if (role === "blueprint") return "蓝图节点";
|
|
82
|
+
if (role === "lifecycle") return "生命周期节点";
|
|
83
|
+
if (role === "and") return "并运算节点";
|
|
84
|
+
if (role === "fetch") return "数据源节点";
|
|
85
|
+
if (role === "json") return "JSON 节点";
|
|
86
|
+
return "逻辑节点";
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
watch(
|
|
90
|
+
[
|
|
91
|
+
configSource,
|
|
92
|
+
existingViewElementIdSet,
|
|
93
|
+
() => props.node.id,
|
|
94
|
+
() => props.node.viewElementId,
|
|
95
|
+
() => props.node.viewElementIds,
|
|
96
|
+
() => props.viewElementOptions.length,
|
|
97
|
+
],
|
|
98
|
+
() => {
|
|
99
|
+
if (configSource.value !== "view") return;
|
|
100
|
+
if (props.viewElementOptions.length === 0) return;
|
|
101
|
+
const linked = resolveViewElementIds(props.node);
|
|
102
|
+
if (linked.length === 0) return;
|
|
103
|
+
const pruned = pruneViewElementIds(linked, existingViewElementIdSet.value);
|
|
104
|
+
if (pruned.length === linked.length) return;
|
|
105
|
+
props.onUpdateNode(props.node.id, {
|
|
106
|
+
viewElementIds: pruned.length > 0 ? pruned : undefined,
|
|
107
|
+
viewElementId: undefined,
|
|
108
|
+
configSource: "view",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
function handleConfigSourceChange(value: string) {
|
|
114
|
+
const nextSource = value as BlueprintConfigSource;
|
|
115
|
+
props.onUpdateNode(props.node.id, {
|
|
116
|
+
...patchNodeConfigSource(props.node, nextSource),
|
|
117
|
+
...(nextSource === "view"
|
|
118
|
+
? {
|
|
119
|
+
viewElementIds: linkedViewElementIds.value,
|
|
120
|
+
viewElementId: undefined,
|
|
121
|
+
}
|
|
122
|
+
: {
|
|
123
|
+
viewElementIds: undefined,
|
|
124
|
+
viewElementId: undefined,
|
|
125
|
+
}),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
</script>
|
|
129
|
+
|
|
130
|
+
<template>
|
|
131
|
+
<div class="flex h-full min-h-0 flex-col overflow-hidden bg-background text-foreground">
|
|
132
|
+
<div class="shrink-0 border-b border-border px-3 py-2">
|
|
133
|
+
<div class="text-xs font-semibold">蓝图节点配置</div>
|
|
134
|
+
<div class="mt-0.5 text-[11px] text-muted-foreground">
|
|
135
|
+
{{ roleLabel }} · {{ node.id }}
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="min-h-0 flex-1 space-y-3 overflow-auto p-3 text-xs">
|
|
139
|
+
<label class="block space-y-1">
|
|
140
|
+
<span class="text-muted-foreground">节点名称</span>
|
|
141
|
+
<Input
|
|
142
|
+
size="small"
|
|
143
|
+
:value="node.label"
|
|
144
|
+
@update:value="(v) => onUpdateNode(node.id, { label: String(v) })"
|
|
145
|
+
/>
|
|
146
|
+
</label>
|
|
147
|
+
|
|
148
|
+
<label class="block space-y-1">
|
|
149
|
+
<span class="text-muted-foreground">配置类型</span>
|
|
150
|
+
<Select
|
|
151
|
+
size="small"
|
|
152
|
+
class="w-full"
|
|
153
|
+
:value="configSource"
|
|
154
|
+
@change="(v) => handleConfigSourceChange(String(v))"
|
|
155
|
+
>
|
|
156
|
+
<Select.Option value="blueprint">蓝图配置</Select.Option>
|
|
157
|
+
<Select.Option value="logic">逻辑配置</Select.Option>
|
|
158
|
+
<Select.Option value="and">并运算</Select.Option>
|
|
159
|
+
<Select.Option value="lifecycle">生命周期配置</Select.Option>
|
|
160
|
+
<Select.Option value="fetch">数据源获取</Select.Option>
|
|
161
|
+
<Select.Option value="json">JSON 节点</Select.Option>
|
|
162
|
+
<Select.Option value="clock">时钟</Select.Option>
|
|
163
|
+
<Select.Option value="view">视图节点配置</Select.Option>
|
|
164
|
+
</Select>
|
|
165
|
+
</label>
|
|
166
|
+
|
|
167
|
+
<div v-if="configSource === 'view'" class="block space-y-1">
|
|
168
|
+
<span class="text-muted-foreground">关联视图节点</span>
|
|
169
|
+
<ViewElementMultiSelect
|
|
170
|
+
:options="viewElementOptions"
|
|
171
|
+
:value="linkedViewElementIds"
|
|
172
|
+
placeholder="选择视图节点"
|
|
173
|
+
@change="
|
|
174
|
+
(next) =>
|
|
175
|
+
onUpdateNode(node.id, {
|
|
176
|
+
viewElementIds: next,
|
|
177
|
+
viewElementId: undefined,
|
|
178
|
+
configSource: 'view',
|
|
179
|
+
})
|
|
180
|
+
"
|
|
181
|
+
/>
|
|
182
|
+
<p v-if="linkedViewElementIds.length === 0" class="text-[11px] text-muted-foreground">
|
|
183
|
+
可多选视图画布节点;关联后仍在此配置蓝图节点,视图属性请在视图面板中编辑。
|
|
184
|
+
</p>
|
|
185
|
+
<p v-else class="text-[11px] text-muted-foreground">
|
|
186
|
+
已关联 {{ linkedViewElementIds.length }} 个视图节点:{{
|
|
187
|
+
linkedViewElementIds
|
|
188
|
+
.map((id) => viewElementLabelById.get(id) ?? id)
|
|
189
|
+
.join("、")
|
|
190
|
+
}}。
|
|
191
|
+
</p>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
<div
|
|
195
|
+
v-if="configSource === 'blueprint'"
|
|
196
|
+
class="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5"
|
|
197
|
+
>
|
|
198
|
+
<div class="font-medium text-foreground">蓝图属性</div>
|
|
199
|
+
<p class="text-[11px] text-muted-foreground">
|
|
200
|
+
选中蓝图库中的蓝图后,当输入端收到<strong>真信号</strong>
|
|
201
|
+
时才会执行该蓝图;执行完成后从输出端发出
|
|
202
|
+
<strong>真信号</strong>(含嵌套蓝图输出值与当前节点信息),执行失败则发出
|
|
203
|
+
<strong>假信号</strong>。
|
|
204
|
+
</p>
|
|
205
|
+
<label class="block space-y-1">
|
|
206
|
+
<span class="text-muted-foreground">引用蓝图库</span>
|
|
207
|
+
<Select
|
|
208
|
+
size="small"
|
|
209
|
+
class="w-full"
|
|
210
|
+
:value="node.libraryBlueprintId ?? '__none__'"
|
|
211
|
+
:dropdown-style="{ zIndex: 10100 }"
|
|
212
|
+
@change="
|
|
213
|
+
(v) =>
|
|
214
|
+
onUpdateNode(node.id, {
|
|
215
|
+
libraryBlueprintId: String(v) === '__none__' ? undefined : String(v),
|
|
216
|
+
configSource: 'blueprint',
|
|
217
|
+
})
|
|
218
|
+
"
|
|
219
|
+
>
|
|
220
|
+
<Select.Option value="__none__">未关联</Select.Option>
|
|
221
|
+
<Select.Option
|
|
222
|
+
v-for="opt in blueprintLibraryOptions"
|
|
223
|
+
:key="opt.id"
|
|
224
|
+
:value="opt.id"
|
|
225
|
+
>
|
|
226
|
+
{{ opt.label }}
|
|
227
|
+
</Select.Option>
|
|
228
|
+
</Select>
|
|
229
|
+
</label>
|
|
230
|
+
<p v-if="!node.libraryBlueprintId" class="text-[11px] text-muted-foreground">
|
|
231
|
+
请先从蓝图库选择要引用的蓝图。
|
|
232
|
+
</p>
|
|
233
|
+
<label class="flex items-start gap-2 pt-1">
|
|
234
|
+
<Checkbox
|
|
235
|
+
:checked="allowFalseSignalPropagation"
|
|
236
|
+
class="mt-0.5"
|
|
237
|
+
@update:checked="(v) => onUpdateAllowFalseSignalPropagation?.(Boolean(v))"
|
|
238
|
+
/>
|
|
239
|
+
<span class="text-[11px] leading-relaxed text-muted-foreground">
|
|
240
|
+
允许假信号传递:开启后,节点输出假信号时不会阻塞任务链,错误信息会继续向下游传递。
|
|
241
|
+
</span>
|
|
242
|
+
</label>
|
|
243
|
+
</div>
|
|
244
|
+
|
|
245
|
+
<div
|
|
246
|
+
v-if="configSource === 'lifecycle'"
|
|
247
|
+
class="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5"
|
|
248
|
+
>
|
|
249
|
+
<div class="font-medium text-foreground">生命周期钩子</div>
|
|
250
|
+
<p class="text-[11px] text-muted-foreground">
|
|
251
|
+
生命周期节点<strong>没有输入口</strong>,仅右侧输出口。
|
|
252
|
+
{{
|
|
253
|
+
node.lifecyclePhase === "blueprintActivated"
|
|
254
|
+
? "当本蓝图被其他蓝图的蓝图配置节点引用且收到真信号时,自动向下游发出真信号,输出值为父级传入的输入数据。"
|
|
255
|
+
: "当页面进入对应生命周期时,自动向下游发出真/假信号。"
|
|
256
|
+
}}
|
|
257
|
+
</p>
|
|
258
|
+
<label class="block space-y-1">
|
|
259
|
+
<span class="text-muted-foreground">监听阶段</span>
|
|
260
|
+
<Select
|
|
261
|
+
size="small"
|
|
262
|
+
class="w-full"
|
|
263
|
+
:value="node.lifecyclePhase ?? 'mounted'"
|
|
264
|
+
@change="
|
|
265
|
+
(v) =>
|
|
266
|
+
onUpdateNode(node.id, {
|
|
267
|
+
role: 'lifecycle',
|
|
268
|
+
nodeType: LIFECYCLE_NODE_TYPE,
|
|
269
|
+
lifecyclePhase: v as PageLifecyclePhase,
|
|
270
|
+
configSource: 'lifecycle',
|
|
271
|
+
})
|
|
272
|
+
"
|
|
273
|
+
>
|
|
274
|
+
<Select.Option v-for="phase in PAGE_LIFECYCLE_PHASES" :key="phase" :value="phase">
|
|
275
|
+
{{ PAGE_LIFECYCLE_LABELS[phase] }}
|
|
276
|
+
</Select.Option>
|
|
277
|
+
</Select>
|
|
278
|
+
</label>
|
|
279
|
+
<p v-if="node.parentId" class="text-[11px] text-muted-foreground">
|
|
280
|
+
所属蓝图节点:{{ node.parentId }}
|
|
281
|
+
</p>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
<FetchNodeConfigPanel
|
|
285
|
+
v-if="configSource === 'fetch'"
|
|
286
|
+
:node="node"
|
|
287
|
+
:on-update-node="onUpdateNode"
|
|
288
|
+
/>
|
|
289
|
+
<JsonNodeConfigPanel
|
|
290
|
+
v-if="configSource === 'json'"
|
|
291
|
+
:node="node"
|
|
292
|
+
:on-update-node="onUpdateNode"
|
|
293
|
+
/>
|
|
294
|
+
<ClockNodeConfigPanel
|
|
295
|
+
v-if="configSource === 'clock'"
|
|
296
|
+
:node="node"
|
|
297
|
+
:on-update-node="onUpdateNode"
|
|
298
|
+
/>
|
|
299
|
+
|
|
300
|
+
<div
|
|
301
|
+
v-if="configSource === 'and'"
|
|
302
|
+
class="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5"
|
|
303
|
+
>
|
|
304
|
+
<div class="font-medium text-foreground">并运算</div>
|
|
305
|
+
<p class="text-[11px] text-muted-foreground">
|
|
306
|
+
左侧两个输入口 <strong>inA</strong>、<strong>inB</strong>。
|
|
307
|
+
每个输入口可连 n 条线,同端口任一为真则该端口视为真(或)。
|
|
308
|
+
仅当 <strong>inA 与 inB 均为真信号</strong> 时,从输出口发出真信号;
|
|
309
|
+
否则发出假信号。
|
|
310
|
+
</p>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<template v-if="configSource === 'logic'">
|
|
314
|
+
<LogicNodeConfigPanel :node="node" :on-update-node="onUpdateNode" />
|
|
315
|
+
<p v-if="node.parentId" class="text-[11px] text-muted-foreground">
|
|
316
|
+
所属蓝图节点:{{ node.parentId }}
|
|
317
|
+
</p>
|
|
318
|
+
</template>
|
|
319
|
+
|
|
320
|
+
<div
|
|
321
|
+
v-if="configSource !== 'blueprint' && configSource !== 'and'"
|
|
322
|
+
class="space-y-2 rounded-md border border-border/70 bg-muted/20 p-2.5"
|
|
323
|
+
>
|
|
324
|
+
<div class="font-medium text-foreground">任务链执行</div>
|
|
325
|
+
<label class="flex items-start gap-2">
|
|
326
|
+
<Checkbox
|
|
327
|
+
:checked="allowFalseSignalPropagation"
|
|
328
|
+
class="mt-0.5"
|
|
329
|
+
@update:checked="(v) => onUpdateAllowFalseSignalPropagation?.(Boolean(v))"
|
|
330
|
+
/>
|
|
331
|
+
<span class="text-[11px] leading-relaxed text-muted-foreground">
|
|
332
|
+
允许假信号传递:默认假信号会阻塞任务链;开启后继续向下游传递假信号与错误信息。
|
|
333
|
+
</span>
|
|
334
|
+
</label>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
</template>
|