perf: 收敛工作流状态与高 IO 节点开销
- 落地 Redis 版本状态、触发租约和定义缓存 - 优化数据批写、插件请求、文件下载与审计日志 - 补齐循环范围校验、轮询兼容和专项测试
This commit is contained in:
@@ -84,6 +84,53 @@
|
||||
let currentNodeId = getCurrentNodeId();
|
||||
let wrapperElement: HTMLDivElement | null = null;
|
||||
const nodeSizeObserver = useTinyflowNodeSizeObserver();
|
||||
const MIN_LOOP_COUNT = 1;
|
||||
const MAX_LOOP_COUNT = 300;
|
||||
let loopCountHint = $state('');
|
||||
|
||||
const normalizeLoopCount = (value: unknown) => {
|
||||
const parsed = Number(value);
|
||||
if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < MIN_LOOP_COUNT) {
|
||||
return MIN_LOOP_COUNT;
|
||||
}
|
||||
return Math.min(parsed, MAX_LOOP_COUNT);
|
||||
};
|
||||
|
||||
const updateLoopEnabled = (event: Event) => {
|
||||
const loopEnable = (event.target as HTMLInputElement).checked;
|
||||
updateNodeData(currentNodeId, {
|
||||
loopEnable,
|
||||
...(loopEnable ? {maxLoopCount: normalizeLoopCount(data.maxLoopCount)} : {})
|
||||
});
|
||||
};
|
||||
|
||||
const updateMaxLoopCount = (event: Event) => {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const parsed = Number(input.value);
|
||||
const normalized = normalizeLoopCount(input.value);
|
||||
if (Number.isFinite(parsed) && parsed > MAX_LOOP_COUNT) {
|
||||
loopCountHint = `最大支持 ${MAX_LOOP_COUNT} 次,已调整为 ${MAX_LOOP_COUNT}`;
|
||||
} else if (!Number.isInteger(parsed) || parsed < MIN_LOOP_COUNT) {
|
||||
loopCountHint = `请输入 ${MIN_LOOP_COUNT}~${MAX_LOOP_COUNT} 的整数`;
|
||||
} else {
|
||||
loopCountHint = '';
|
||||
}
|
||||
updateNodeData(currentNodeId, {maxLoopCount: normalized});
|
||||
};
|
||||
|
||||
$effect(() => {
|
||||
if (!data.loopEnable) {
|
||||
loopCountHint = '';
|
||||
return;
|
||||
}
|
||||
const normalized = normalizeLoopCount(data.maxLoopCount);
|
||||
if (Number(data.maxLoopCount) !== normalized) {
|
||||
loopCountHint = Number(data.maxLoopCount) > MAX_LOOP_COUNT
|
||||
? `最大支持 ${MAX_LOOP_COUNT} 次,已调整为 ${MAX_LOOP_COUNT}`
|
||||
: `请输入 ${MIN_LOOP_COUNT}~${MAX_LOOP_COUNT} 的整数`;
|
||||
updateNodeData(currentNodeId, {maxLoopCount: normalized});
|
||||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
if (!wrapperElement) {
|
||||
@@ -187,12 +234,7 @@
|
||||
|
||||
<label class="input-item-inline">
|
||||
<span>循环执行:</span>
|
||||
<input type="checkbox" checked={!!data.loopEnable} onchange={(event)=>{
|
||||
const value = (event.target as any).checked;
|
||||
updateNodeData(currentNodeId,{
|
||||
loopEnable: value
|
||||
})
|
||||
}} />
|
||||
<input type="checkbox" checked={!!data.loopEnable} onchange={updateLoopEnabled} />
|
||||
</label>
|
||||
|
||||
{#if !!data.loopEnable}
|
||||
@@ -207,13 +249,19 @@
|
||||
</div>
|
||||
|
||||
<div class="input-item">
|
||||
最大循环次数(0 表示不限制):
|
||||
<Textarea rows={1} style="width: 100%;" onchange={(event)=>{
|
||||
const value = (event.target as any).value;
|
||||
updateNodeData(currentNodeId,{
|
||||
maxLoopCount: value
|
||||
})
|
||||
}} value={data.maxLoopCount || '0'} />
|
||||
循环次数:
|
||||
<Input
|
||||
type="number"
|
||||
min={MIN_LOOP_COUNT}
|
||||
max={MAX_LOOP_COUNT}
|
||||
step="1"
|
||||
style="width: 100%;"
|
||||
onchange={updateMaxLoopCount}
|
||||
value={data.maxLoopCount ?? MIN_LOOP_COUNT}
|
||||
/>
|
||||
{#if loopCountHint}
|
||||
<span class="input-hint" role="status" aria-live="polite">{loopCountHint}</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="input-item">
|
||||
@@ -337,6 +385,11 @@
|
||||
color: var(--tf-text-secondary);
|
||||
}
|
||||
|
||||
.input-hint {
|
||||
color: var(--tf-warning-soft-text);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
input[type='checkbox'] {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
|
||||
@@ -14,12 +14,22 @@
|
||||
}
|
||||
});
|
||||
|
||||
const { parameter, index, dataKeyName, useChildrenOnly, showContentType = false }: {
|
||||
const {
|
||||
parameter,
|
||||
index,
|
||||
dataKeyName,
|
||||
useChildrenOnly,
|
||||
showContentType = false,
|
||||
fixedNumberMin,
|
||||
fixedNumberMax
|
||||
}: {
|
||||
parameter: Parameter,
|
||||
index: number,
|
||||
dataKeyName: string,
|
||||
useChildrenOnly?: boolean,
|
||||
showContentType?: boolean,
|
||||
fixedNumberMin?: number,
|
||||
fixedNumberMax?: number,
|
||||
} = $props();
|
||||
|
||||
|
||||
@@ -53,6 +63,39 @@
|
||||
updateParam(name, newValue);
|
||||
};
|
||||
|
||||
let fixedValueHint = $state('');
|
||||
|
||||
const updateFixedValue = (event: Event) => {
|
||||
const value = (event.target as HTMLInputElement).value;
|
||||
if (fixedNumberMin === undefined && fixedNumberMax === undefined) {
|
||||
updateParam('value', value);
|
||||
return;
|
||||
}
|
||||
if (value.trim() === '') {
|
||||
fixedValueHint = '';
|
||||
updateParam('value', value);
|
||||
return;
|
||||
}
|
||||
const parsed = Number(value);
|
||||
if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {
|
||||
fixedValueHint = '请输入整数';
|
||||
updateParam('value', value);
|
||||
return;
|
||||
}
|
||||
if (fixedNumberMax !== undefined && parsed > fixedNumberMax) {
|
||||
fixedValueHint = `最大支持 ${fixedNumberMax} 次,已调整为 ${fixedNumberMax}`;
|
||||
updateParam('value', String(fixedNumberMax));
|
||||
return;
|
||||
}
|
||||
if (fixedNumberMin !== undefined && parsed < fixedNumberMin) {
|
||||
fixedValueHint = `最少执行 ${fixedNumberMin} 次`;
|
||||
updateParam('value', String(fixedNumberMin));
|
||||
return;
|
||||
}
|
||||
fixedValueHint = '';
|
||||
updateParam('value', value);
|
||||
};
|
||||
|
||||
|
||||
const updateRef = (item: any) => {
|
||||
const newValue = item.value;
|
||||
@@ -93,7 +136,21 @@
|
||||
</div>
|
||||
<div class="input-item">
|
||||
{#if param.refType === 'fixed'}
|
||||
<Input value={param.value} placeholder="请输入参数值" oninput={(event)=>updateParamByEvent('value', event)} />
|
||||
<div class="fixed-value">
|
||||
<Input
|
||||
type={fixedNumberMin !== undefined || fixedNumberMax !== undefined ? 'number' : 'text'}
|
||||
min={fixedNumberMin}
|
||||
max={fixedNumberMax}
|
||||
step={fixedNumberMin !== undefined || fixedNumberMax !== undefined ? 1 : undefined}
|
||||
style="width: 100%;"
|
||||
value={param.value}
|
||||
placeholder="请输入参数值"
|
||||
oninput={updateFixedValue}
|
||||
/>
|
||||
{#if fixedValueHint}
|
||||
<span class="input-hint" role="status" aria-live="polite">{fixedValueHint}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if (param.refType !== 'input')}
|
||||
<Select items={selectItems.current} style="width: 100%" defaultValue={["ref"]} value={[param.ref]} variant="reference"
|
||||
expandAll
|
||||
@@ -152,6 +209,20 @@
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.fixed-value {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.input-hint {
|
||||
color: var(--tf-warning-soft-text);
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.input-more-setting {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -7,12 +7,16 @@
|
||||
noneParameterText = '无输入参数',
|
||||
dataKeyName = 'parameters',
|
||||
useChildrenOnly,
|
||||
showContentType = false
|
||||
showContentType = false,
|
||||
fixedNumberMin,
|
||||
fixedNumberMax
|
||||
}: {
|
||||
noneParameterText?: string;
|
||||
dataKeyName?: string;
|
||||
useChildrenOnly?: boolean,
|
||||
showContentType?: boolean,
|
||||
fixedNumberMin?: number,
|
||||
fixedNumberMax?: number,
|
||||
} = $props();
|
||||
|
||||
let currentNodeId = getCurrentNodeId();
|
||||
@@ -31,7 +35,15 @@
|
||||
<div class="input-header"></div>
|
||||
{/if}
|
||||
{#each parameters as param, index (param.id)}
|
||||
<RefParameterItem parameter={param} index={index} {dataKeyName} {useChildrenOnly} {showContentType} />
|
||||
<RefParameterItem
|
||||
parameter={param}
|
||||
index={index}
|
||||
{dataKeyName}
|
||||
{useChildrenOnly}
|
||||
{showContentType}
|
||||
{fixedNumberMin}
|
||||
{fixedNumberMax}
|
||||
/>
|
||||
{:else }
|
||||
<div class="none-params">{noneParameterText}</div>
|
||||
{/each}
|
||||
|
||||
@@ -55,7 +55,8 @@
|
||||
<!-- </svg>-->
|
||||
<!-- </Button>-->
|
||||
</div>
|
||||
<RefParameterList dataKeyName="loopVars" />
|
||||
<RefParameterList dataKeyName="loopVars" fixedNumberMin={1} fixedNumberMax={300} />
|
||||
<div class="loop-limit-hint">单次最多循环 300 次</div>
|
||||
|
||||
<div class="heading">
|
||||
<Heading level={3}>输出参数</Heading>
|
||||
@@ -78,6 +79,13 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loop-limit-hint {
|
||||
margin-top: 6px;
|
||||
color: var(--tf-text-secondary);
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
:global(.loop-handle-wrapper) {
|
||||
&::after {
|
||||
//display: none;
|
||||
|
||||
Reference in New Issue
Block a user