mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-02 03:02:19 +08:00
fix: autoflow not rerun if render by render function directly
This commit is contained in:
parent
c6e9e9ba79
commit
b643c9a330
@ -309,4 +309,13 @@ export class FlowEngine {
|
|||||||
}
|
}
|
||||||
return modelClasses;
|
return modelClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static generateApplyFlowCacheKey(
|
||||||
|
prefix: string,
|
||||||
|
flowKey: string,
|
||||||
|
modelUid: string,
|
||||||
|
params: Record<string, any>,
|
||||||
|
): string {
|
||||||
|
return `${prefix}:${flowKey}:${modelUid}:${JSON.stringify(params)}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,77 +13,7 @@ import { FlowModel } from '../models';
|
|||||||
import { useFlowEngine } from '../provider';
|
import { useFlowEngine } from '../provider';
|
||||||
import { FlowExtraContext } from '../types';
|
import { FlowExtraContext } from '../types';
|
||||||
import { uid } from 'uid/secure';
|
import { uid } from 'uid/secure';
|
||||||
|
import { FlowEngine } from '../flowEngine';
|
||||||
// 生成稳定的缓存键
|
|
||||||
function generateCacheKey(prefix: string, flowKey: string, modelUid: string): string {
|
|
||||||
return `${prefix}:${flowKey}:${modelUid}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 安全序列化对象的函数
|
|
||||||
function safeStringify(obj: any, visited = new Set(), depth = 0, maxDepth = 5): string {
|
|
||||||
// 深度限制,防止过深递归
|
|
||||||
if (depth > maxDepth) {
|
|
||||||
return '[MaxDepthExceeded]';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理基本类型
|
|
||||||
if (obj === null || obj === undefined) {
|
|
||||||
return String(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof obj !== 'object' && typeof obj !== 'function') {
|
|
||||||
return String(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理函数
|
|
||||||
if (typeof obj === 'function') {
|
|
||||||
// 对于函数,可以使用函数名或为匿名函数生成一个标识符
|
|
||||||
return `function:${obj.name || 'anonymous'}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理循环引用
|
|
||||||
if (visited.has(obj)) {
|
|
||||||
return '[Circular]';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加到已访问集合
|
|
||||||
visited.add(obj);
|
|
||||||
|
|
||||||
// 处理数组
|
|
||||||
if (Array.isArray(obj)) {
|
|
||||||
try {
|
|
||||||
// 限制处理的数组元素数量
|
|
||||||
const maxItems = 100;
|
|
||||||
const items = obj.slice(0, maxItems);
|
|
||||||
const result =
|
|
||||||
'[' +
|
|
||||||
items.map((item) => safeStringify(item, visited, depth + 1, maxDepth)).join(',') +
|
|
||||||
(obj.length > maxItems ? ',...' : '') +
|
|
||||||
']';
|
|
||||||
return result;
|
|
||||||
} catch (e) {
|
|
||||||
return '[Array]';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理普通对象
|
|
||||||
try {
|
|
||||||
const keys = Object.keys(obj).sort(); // 排序确保稳定性
|
|
||||||
// 限制处理的属性数量
|
|
||||||
const maxKeys = 50;
|
|
||||||
const limitedKeys = keys.slice(0, maxKeys);
|
|
||||||
|
|
||||||
const pairs = limitedKeys.map((key) => {
|
|
||||||
const value = obj[key];
|
|
||||||
return `${key}:${safeStringify(value, visited, depth + 1, maxDepth)}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
return '{' + pairs.join(',') + (keys.length > maxKeys ? ',...' : '') + '}';
|
|
||||||
} catch (e) {
|
|
||||||
// 如果无法序列化,返回一个简单的标识
|
|
||||||
return '[Object]';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用的流程执行 Hook
|
* 通用的流程执行 Hook
|
||||||
@ -105,8 +35,8 @@ function useFlowExecutor<T, TModel extends FlowModel = FlowModel>(
|
|||||||
): T {
|
): T {
|
||||||
const engine = useFlowEngine();
|
const engine = useFlowEngine();
|
||||||
const cacheKey = useMemo(
|
const cacheKey = useMemo(
|
||||||
() => generateCacheKey(model['forkId'] ?? cacheKeyPrefix, flowKey, model.uid),
|
() => FlowEngine.generateApplyFlowCacheKey(model['forkId'] ?? cacheKeyPrefix, flowKey, model.uid, model.stepParams),
|
||||||
[cacheKeyPrefix, flowKey, model.uid, model['forkId']],
|
[cacheKeyPrefix, flowKey, model.uid, model['forkId'], model.stepParams],
|
||||||
);
|
);
|
||||||
const [, forceUpdate] = useState({});
|
const [, forceUpdate] = useState({});
|
||||||
const isMounted = useRef(false);
|
const isMounted = useRef(false);
|
||||||
|
@ -325,6 +325,7 @@ export class FlowModel<Structure extends { parent?: any; subModels?: any } = Def
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.applyAutoFlows(); // 参数变化时自动重新执行 autoFlows
|
||||||
}
|
}
|
||||||
|
|
||||||
getStepParams(flowKey: string, stepKey: string): any | undefined;
|
getStepParams(flowKey: string, stepKey: string): any | undefined;
|
||||||
@ -518,9 +519,10 @@ export class FlowModel<Structure extends { parent?: any; subModels?: any } = Def
|
|||||||
/**
|
/**
|
||||||
* 执行所有自动应用流程
|
* 执行所有自动应用流程
|
||||||
* @param {FlowExtraContext} [extra] 可选的额外上下文
|
* @param {FlowExtraContext} [extra] 可选的额外上下文
|
||||||
|
* @param {boolean} [useCache=true] 是否使用缓存机制,默认为 true
|
||||||
* @returns {Promise<any[]>} 所有自动应用流程的执行结果数组
|
* @returns {Promise<any[]>} 所有自动应用流程的执行结果数组
|
||||||
*/
|
*/
|
||||||
async applyAutoFlows(extra?: FlowExtraContext): Promise<any[]> {
|
async applyAutoFlows(extra?: FlowExtraContext, useCache = true): Promise<any[]> {
|
||||||
const autoApplyFlows = this.getAutoFlows();
|
const autoApplyFlows = this.getAutoFlows();
|
||||||
|
|
||||||
if (autoApplyFlows.length === 0) {
|
if (autoApplyFlows.length === 0) {
|
||||||
@ -528,18 +530,65 @@ export class FlowModel<Structure extends { parent?: any; subModels?: any } = Def
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const results: any[] = [];
|
// 生成缓存键,包含 stepParams 的序列化版本以确保参数变化时重新执行
|
||||||
for (const flow of autoApplyFlows) {
|
const cacheKey = useCache
|
||||||
try {
|
? FlowEngine.generateApplyFlowCacheKey(this['forkId'] ?? 'autoFlow', 'all', this.uid, this.stepParams)
|
||||||
const result = await this.applyFlow(flow.key, extra);
|
: null;
|
||||||
results.push(result);
|
|
||||||
} catch (error) {
|
// 检查缓存
|
||||||
console.error(`FlowModel.applyAutoFlows: Error executing auto-apply flow '${flow.key}':`, error);
|
if (cacheKey && this.flowEngine) {
|
||||||
throw error;
|
const cachedEntry = this.flowEngine.applyFlowCache.get(cacheKey);
|
||||||
|
if (cachedEntry) {
|
||||||
|
if (cachedEntry.status === 'resolved') {
|
||||||
|
console.log(`[FlowEngine.applyAutoFlows] Using cached result for model: ${this.uid}`);
|
||||||
|
return cachedEntry.data;
|
||||||
|
}
|
||||||
|
if (cachedEntry.status === 'rejected') throw cachedEntry.error;
|
||||||
|
if (cachedEntry.status === 'pending') return await cachedEntry.promise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
// 执行 autoFlows
|
||||||
|
const executeAutoFlows = async (): Promise<any[]> => {
|
||||||
|
const results: any[] = [];
|
||||||
|
for (const flow of autoApplyFlows) {
|
||||||
|
try {
|
||||||
|
const result = await this.applyFlow(flow.key, extra);
|
||||||
|
results.push(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`FlowModel.applyAutoFlows: Error executing auto-apply flow '${flow.key}':`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 如果不使用缓存,直接执行
|
||||||
|
if (!cacheKey || !this.flowEngine) {
|
||||||
|
return await executeAutoFlows();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用缓存机制
|
||||||
|
const promise = executeAutoFlows()
|
||||||
|
.then((result) => {
|
||||||
|
this.flowEngine.applyFlowCache.set(cacheKey, {
|
||||||
|
status: 'resolved',
|
||||||
|
data: result,
|
||||||
|
promise: Promise.resolve(result),
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.flowEngine.applyFlowCache.set(cacheKey, {
|
||||||
|
status: 'rejected',
|
||||||
|
error: err,
|
||||||
|
promise: Promise.reject(err),
|
||||||
|
});
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.flowEngine.applyFlowCache.set(cacheKey, { status: 'pending', promise });
|
||||||
|
return await promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user