chore: api and demo update

This commit is contained in:
gchust 2025-04-20 15:50:50 +08:00
parent 2ac824c85a
commit f87d5f0e49
5 changed files with 112 additions and 62 deletions

View File

@ -139,36 +139,63 @@ eventFlowManager.addFlow({
], ],
}); });
// 主演示组件 const PARAMS = {
const ConfigurableActionDemo = () => { events: {
const [currentParams, setCurrentParams] = useState<Record<string, any>>({ 'button-id': {
stepParams: {
'message-step': {
title: '消息标题', title: '消息标题',
content: '这是一条测试消息', content: '这是一条测试消息',
type: 'info', type: 'info',
}); },
},
},
},
filters: {},
};
const getParams = async (id: string) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(PARAMS['events'][id]); // 模拟异步获取
}, 1000);
});
};
const setParams = async (id: string, params: Record<string, any>) => {
return new Promise((resolve) => {
setTimeout(() => {
PARAMS['events'][id] = params; // 模拟异步更新
resolve(params);
}, 1000);
});
};
// 主演示组件
const ConfigurableActionDemo = () => {
const componentId = 'button-id';
// 打开配置弹窗 // 打开配置弹窗
const showConfig = () => { const showConfig = async () => {
const step = eventFlowManager.getFlow('message-flow').getStep('message-step'); const step = eventFlowManager.getFlow('message-flow').getStep('message-step');
const ctx = { const ctx = {
payload: { payload: {
step, step,
onChange: (values) => { onChange: async (values) => {
setCurrentParams(values); await setParams(componentId, values);
}, },
currentParams, currentParams: await getParams(componentId),
}, },
}; };
eventBus.dispatchEvent('configure:click', ctx); eventBus.dispatchEvent('configure:click', ctx);
}; };
// 触发消息动作 // 触发消息动作
const triggerAction = () => { const triggerAction = async () => {
const ctx = { const ctx = {
payload: {}, payload: {},
meta: { meta: {
stepParams: { stepParams: {
'message-step': currentParams, 'message-step': await getParams(componentId),
}, },
}, },
}; };
@ -182,15 +209,6 @@ const ConfigurableActionDemo = () => {
&quot;&quot;&quot;&quot; &quot;&quot;&quot;&quot;
</Typography.Paragraph> </Typography.Paragraph>
<div style={{ marginBottom: 16 }}>
<Typography.Text strong>:</Typography.Text>
<ul>
<li>: {currentParams.title}</li>
<li>: {currentParams.content}</li>
<li>: {currentParams.type}</li>
</ul>
</div>
<Space> <Space>
<Button type="primary" onClick={showConfig}> <Button type="primary" onClick={showConfig}>

View File

@ -1,6 +1,6 @@
import { Button, Card, Form, Input, Select, Space, Typography, Modal, Switch, InputNumber } from 'antd'; import { Button, Card, Form, Input, Select, Space, Typography, Modal, Switch, InputNumber } from 'antd';
import React, { useMemo, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import { FilterFlowManager, useApplyFilters } from '@nocobase/client'; import { FilterFlowManager, FilterHandlerContext, FilterStepParams, useApplyFilters } from '@nocobase/client';
import { configureAction } from '../actions/open-configure-dialog'; import { configureAction } from '../actions/open-configure-dialog';
// 创建FilterFlowManager实例 // 创建FilterFlowManager实例
@ -135,9 +135,9 @@ filterFlowManager.addFlow({
], ],
}); });
const ConfigurableFilter = () => { const PARAMS = {
const [inputText, setInputText] = useState('Hello configurable filter demo'); filters: {
const [stepParams, setStepParams] = useState({ 'demo-id': {
'replace-step': { 'replace-step': {
search: 'Hello', search: 'Hello',
replacement: 'hi', replacement: 'hi',
@ -147,30 +147,53 @@ const ConfigurableFilter = () => {
maxLength: 10, maxLength: 10,
suffix: '...', suffix: '...',
}, },
}); },
},
};
const context = useMemo( const getParams = async (id: string): Promise<FilterStepParams> => {
() => ({ return new Promise((resolve) => {
setTimeout(() => {
resolve(PARAMS['filters'][id]); // 模拟异步获取
}, 1000);
});
};
const setParams = async (id: string, params: Record<string, any>) => {
return new Promise((resolve) => {
setTimeout(() => {
PARAMS['filters'][id] = params; // 模拟异步更新
resolve(params);
}, 1000);
});
};
const ConfigurableFilter = () => {
const demoId = 'demo-id';
const [inputText, setInputText] = useState('Hello configurable filter demo');
const getContext = useCallback(
async (): Promise<FilterHandlerContext> => ({
meta: { meta: {
params: stepParams, params: await getParams(demoId),
}, },
}), }),
[inputText, stepParams], [demoId],
); );
const outputText = useApplyFilters(filterFlowManager, 'configurable-text-transform', inputText, context); const outputText = useApplyFilters(filterFlowManager, 'configurable-text-transform', inputText, getContext, demoId);
// 打开配置Modal // 打开配置Modal
const openConfigModal = (stepKey) => { const openConfigModal = async (stepKey) => {
const flow = filterFlowManager.getFlow('configurable-text-transform'); const flow = filterFlowManager.getFlow('configurable-text-transform');
const step = flow.getStep(stepKey); const step = flow.getStep(stepKey);
const actionContext = { const actionContext = {
payload: { payload: {
step, step,
currentParams: stepParams[stepKey], currentParams: (await getParams(demoId))?.[stepKey],
onChange: (values) => { onChange: async (values) => {
setStepParams({ // await setParams(demoId, PARAMS['filters'][demoId]);
...stepParams, await setParams(demoId, {
...PARAMS['filters'][demoId],
[stepKey]: values, [stepKey]: values,
}); });
}, },

View File

@ -197,15 +197,6 @@ const HideShowFilterFlow = () => {
</div> </div>
</Space> </Space>
</Card> </Card>
<Card title="过滤器结果" style={{ marginBottom: 16 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<div>
<Typography.Text code>visibilityConfig:</Typography.Text>
<pre>{JSON.stringify(visibilityConfig, null, 2)}</pre>
</div>
</Space>
</Card>
</div> </div>
); );
}; };

View File

@ -21,6 +21,11 @@
<code src="./demos/filters/multi-step-filterflow.tsx"></code> <code src="./demos/filters/multi-step-filterflow.tsx"></code>
## 控制元素可见性过滤器流
演示如何控制元素的可见性
<code src="./demos/filters/hide-show-filterflow.tsx"></code>
## 数据转换过滤器流 ## 数据转换过滤器流
展示如何使用过滤器流转换数据 展示如何使用过滤器流转换数据

View File

@ -25,24 +25,36 @@ export function useApplyFilters<T = any>(
filterFlowManager: FilterFlowManager, filterFlowManager: FilterFlowManager,
flowName: string, flowName: string,
initialValue: any, initialValue: any,
context?: FilterHandlerContext, context?: FilterHandlerContext | (() => Promise<FilterHandlerContext>),
id?: string,
): T { ): T {
const [, forceUpdate] = useState(0); const [, forceUpdate] = useState(0);
const cacheKey = useMemo(() => { const cacheKey = useMemo(() => {
const key = JSON.stringify([flowName, context]); if (id) {
return key; return `${flowName}-${id}`;
}, [flowName, context]); }
return JSON.stringify([flowName, context]);
}, [flowName, context, id]);
const prevValue = useRef(initialValue); const prevValue = useRef(initialValue);
const prevCacheKey = useRef(cacheKey); const prevCacheKey = useRef(cacheKey);
const contextPromise = new Promise<FilterHandlerContext>((resolve, reject) => {
if (typeof context === 'function') {
context().then(resolve).catch(reject);
} else {
resolve(context);
}
});
useEffect(() => { useEffect(() => {
if (prevValue.current !== initialValue) { if (prevValue.current !== initialValue) {
const refreshData = async () => { const refreshData = async () => {
const cachedEntry = filterCache.get(cacheKey); const cachedEntry = filterCache.get(cacheKey);
if (cachedEntry?.status === 'resolved') { if (cachedEntry?.status === 'resolved') {
const newData = await filterFlowManager.applyFilters(flowName, initialValue, context); const newData = await contextPromise.then((ctx) =>
filterFlowManager.applyFilters(flowName, initialValue, ctx),
);
filterCache.set(cacheKey, { status: 'resolved', data: newData, promise: Promise.resolve(newData) }); filterCache.set(cacheKey, { status: 'resolved', data: newData, promise: Promise.resolve(newData) });
forceUpdate((prev) => prev + 1); forceUpdate((prev) => prev + 1);
} }
@ -50,7 +62,8 @@ export function useApplyFilters<T = any>(
refreshData(); refreshData();
prevValue.current = initialValue; prevValue.current = initialValue;
} }
}, [initialValue]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [initialValue]); //输入变化时,应该重新计算
useEffect(() => { useEffect(() => {
if (prevCacheKey.current !== cacheKey) { if (prevCacheKey.current !== cacheKey) {
@ -77,8 +90,8 @@ export function useApplyFilters<T = any>(
} }
// 创建新的 Promise // 创建新的 Promise
const promise = filterFlowManager const promise = contextPromise
.applyFilters(flowName, initialValue, context) .then((ctx) => filterFlowManager.applyFilters(flowName, initialValue, ctx))
.then((result) => { .then((result) => {
// 成功时更新缓存 // 成功时更新缓存
filterCache.set(cacheKey, { status: 'resolved', data: result, promise }); filterCache.set(cacheKey, { status: 'resolved', data: result, promise });