feat: improve code

This commit is contained in:
chenos 2025-06-18 23:45:56 +08:00
parent fdba080de7
commit d911e05a0e
12 changed files with 105 additions and 32 deletions

View File

@ -6,7 +6,7 @@ import React from 'react';
// 实现一个本地存储的模型仓库,负责模型的持久化
class FlowModelRepository implements IFlowModelRepository<FlowModel> {
// 从本地存储加载模型数据
async load(uid: string) {
async findOne({ uid }) {
const data = localStorage.getItem(`flow-model:${uid}`);
if (!data) return null;
return JSON.parse(data);

View File

@ -180,3 +180,33 @@ steps: {
- 支持多种定义方式,适应不同复杂度的业务场景。
- 可通过 `uiSchema``defaultParams` 配置参数界面和默认值,提升易用性。
- 合理使用 `paramsRequired``hideInSettings`,提升操作安全性和灵活性。
---
## 示例:在 Drawer 中使用
以下示例演示如何在 Drawer 中使用 FlowAction并传递 `currentDrawer``sharedContext`
```tsx
// 1. 先声明 currentDrawer
let currentDrawer: any;
// 2. 定义内容组件,确保 currentDrawer 已赋值
function DrawerContent() {
return (
<div>
<FlowPageComponent
uid={`${ctx.model.uid}-drawer`}
sharedContext={{ ...ctx.extra, currentDrawer }}
/>
</div>
);
}
// 3. 打开 Drawer并赋值 currentDrawer
currentDrawer = ctx.globals.drawer.open({
title: '命令式 Drawer',
width: 800,
content: <DrawerContent />,
});
```

View File

@ -4,7 +4,7 @@
## 主要方法
- **load(uid: string): Promise<FlowModel \| null>**
- **findOne(query: Query): Promise<FlowModel \| null>**
根据唯一标识符 uid 从远程加载模型数据。
- **save(model: FlowModel): Promise<any>**
@ -19,7 +19,8 @@
class FlowModelRepository implements IFlowModelRepository<FlowModel> {
constructor(private app: Application) {}
async load(uid: string) {
async findOne(query) {
const { uid, parentId } = query;
// 实现:根据 uid 获取模型
return null;
}

View File

@ -4,7 +4,7 @@ import React from 'react';
class FlowModelRepository implements IFlowModelRepository<FlowModel> {
constructor(private app: Application) {}
async load(uid: string) {
async findOne({ uid, parentId }) {
// implement fetching a model by id
return null;
}

View File

@ -6,7 +6,9 @@ import { Button, Tabs } from 'antd';
import _ from 'lodash';
import React from 'react';
class FlowModelRepository implements IFlowModelRepository<FlowModel<{parent: never, subModels: { tabs: TabFlowModel[] } }>> {
class FlowModelRepository
implements IFlowModelRepository<FlowModel<{ parent: never; subModels: { tabs: TabFlowModel[] } }>>
{
get models() {
const models = new Map();
for (let i = 0; i < localStorage.length; i++) {
@ -22,8 +24,12 @@ class FlowModelRepository implements IFlowModelRepository<FlowModel<{parent: nev
return models;
}
async findOne(query) {
return this.load(query.uid);
}
// 从本地存储加载模型数据
async load(uid: string) {
async load({ uid }) {
const data = localStorage.getItem(`flow-model:${uid}`);
if (!data) return null;
const json: FlowModel = JSON.parse(data);
@ -57,7 +63,10 @@ class FlowModelRepository implements IFlowModelRepository<FlowModel<{parent: nev
localStorage.setItem(`flow-model:${subModel.uid}`, JSON.stringify(subModel.serialize()));
});
} else if (model.subModels[subModelKey] instanceof FlowModel) {
localStorage.setItem(`flow-model:${model.subModels[subModelKey].uid}`, JSON.stringify(model.subModels[subModelKey].serialize()));
localStorage.setItem(
`flow-model:${model.subModels[subModelKey].uid}`,
JSON.stringify(model.subModels[subModelKey].serialize()),
);
}
}
return data;
@ -72,8 +81,7 @@ class FlowModelRepository implements IFlowModelRepository<FlowModel<{parent: nev
class TabFlowModel extends FlowModel {}
class HelloFlowModel extends FlowModel<{parent: never, subModels: { tabs: TabFlowModel[] } }> {
class HelloFlowModel extends FlowModel<{ parent: never; subModels: { tabs: TabFlowModel[] } }> {
addTab(tab: any) {
// 使用新的 addSubModel API 添加子模型
const model = this.addSubModel('tabs', tab);
@ -88,7 +96,7 @@ class HelloFlowModel extends FlowModel<{parent: never, subModels: { tabs: TabFlo
items={this.subModels.tabs?.map((tab) => ({
key: tab.getProps().key,
label: tab.getProps().label,
children: tab.render()
children: tab.render(),
}))}
tabBarExtraContent={
<Button
@ -98,7 +106,7 @@ class HelloFlowModel extends FlowModel<{parent: never, subModels: { tabs: TabFlo
use: 'TabFlowModel',
uid: tabId,
props: { key: tabId, label: `Tab - ${tabId}` },
})
});
}}
>
Add Tab
@ -134,7 +142,7 @@ class PluginHelloModel extends Plugin {
props: { key: 'tab-2', label: 'Tab 2' },
},
],
}
},
});
this.router.add('root', { path: '/', element: <FlowModelRenderer model={model} /> });
}

View File

@ -26,6 +26,26 @@ export class MockFlowModelRepository implements IFlowModelRepository<FlowModel>
return models;
}
async findOne(query) {
const { uid, parentId } = query;
if (uid) {
return this.load(uid);
} else if (parentId) {
return this.loadByParentId(parentId);
}
return null;
}
async loadByParentId(parentId: string) {
for (const model of this.models.values()) {
if (model.parentId == parentId) {
console.log('Loading model by parentId:', parentId, model);
return this.load(model.uid);
}
}
return null;
}
// 从本地存储加载模型数据
async load(uid: string) {
const data = localStorage.getItem(`flow-model:${uid}`);
@ -43,10 +63,12 @@ export class MockFlowModelRepository implements IFlowModelRepository<FlowModel>
json.subModels[model.subKey].push(subModel);
} else if (model.subType === 'object') {
const subModel = await this.load(model.uid);
if (subModel) {
json.subModels[model.subKey] = subModel;
}
}
}
}
console.log('Loading model:', uid, JSON.stringify(json, null, 2));
return json;
}

View File

@ -10,7 +10,7 @@
import { FlowModelRenderer, useFlowEngine, useFlowModel } from '@nocobase/flow-engine';
import { useRequest } from 'ahooks';
import { Spin } from 'antd';
import React from 'react';
import React, { useMemo } from 'react';
import { useParams } from 'react-router-dom';
function InternalFlowPage({ uid, sharedContext }) {
@ -20,15 +20,16 @@ function InternalFlowPage({ uid, sharedContext }) {
export const FlowPage = () => {
const params = useParams();
return <FlowPageComponent uid={params.name} sharedContext={{}} />;
return <FlowPageComponent uid={params.name} />;
};
export const FlowPageComponent = ({ uid, sharedContext }) => {
export const FlowPageComponent = (props) => {
const { uid, parentId, sharedContext } = props;
const flowEngine = useFlowEngine();
const { loading } = useRequest(
() => {
return flowEngine.loadOrCreateModel({
uid: uid,
const { loading, data } = useRequest(
async () => {
const options = {
uid,
use: 'PageFlowModel',
subModels: {
tabs: [
@ -42,14 +43,22 @@ export const FlowPageComponent = ({ uid, sharedContext }) => {
},
],
},
});
};
if (!uid && parentId) {
options['async'] = true;
options['parentId'] = parentId;
options['subKey'] = 'page';
options['subType'] = 'object';
}
const data = await flowEngine.loadOrCreateModel(options);
return data;
},
{
refreshDeps: [uid],
refreshDeps: [uid || parentId],
},
);
if (loading) {
if (loading || !data?.uid) {
return <Spin />;
}
return <InternalFlowPage uid={uid} sharedContext={sharedContext} />;
return <InternalFlowPage uid={data.uid} sharedContext={sharedContext} />;
};

View File

@ -30,7 +30,7 @@ AddNewActionModel.registerFlow({
function DrawerContent() {
return (
<div>
<FlowPageComponent uid={`${ctx.model.uid}-drawer`} sharedContext={{ ...ctx.extra, currentDrawer }} />
<FlowPageComponent parentId={ctx.model.uid} sharedContext={{ ...ctx.extra, currentDrawer }} />
</div>
);
}

View File

@ -31,7 +31,7 @@ ViewActionModel.registerFlow({
function DrawerContent() {
return (
<div>
<FlowPageComponent uid={`${ctx.model.uid}-drawer`} sharedContext={{ ...ctx.extra, currentDrawer }} />
<FlowPageComponent parentId={ctx.model.uid} sharedContext={{ ...ctx.extra, currentDrawer }} />
</div>
);
}

View File

@ -227,13 +227,13 @@ export class FlowEngine {
async loadModel<T extends FlowModel = FlowModel>(uid: string): Promise<T | null> {
if (!this.ensureModelRepository()) return;
const data = await this.modelRepository.load(uid);
const data = await this.modelRepository.findOne({ uid });
return data?.uid ? this.createModel<T>(data as any) : null;
}
async loadOrCreateModel<T extends FlowModel = FlowModel>(options): Promise<T | null> {
if (!this.ensureModelRepository()) return;
const data = await this.modelRepository.load(options.uid);
const data = await this.modelRepository.findOne(options);
if (data?.uid) {
return this.createModel<T>(data as any);
} else {

View File

@ -14,7 +14,6 @@ import { uid } from 'uid/secure';
import { openRequiredParamsStepFormDialog as openRequiredParamsStepFormDialogFn } from '../components/settings/wrappers/contextual/StepRequiredSettingsDialog';
import { openStepSettingsDialog as openStepSettingsDialogFn } from '../components/settings/wrappers/contextual/StepSettingsDialog';
import { FlowEngine } from '../flowEngine';
import { FlowExitException, resolveDefaultParams } from '../utils';
import type {
ActionStepDefinition,
ArrayElementType,
@ -30,7 +29,7 @@ import type {
StepParams,
} from '../types';
import { ExtendedFlowDefinition, FlowExtraContext, IModelComponentProps, ReadonlyModelProps } from '../types';
import { generateUid, mergeFlowDefinitions } from '../utils';
import { FlowExitException, generateUid, mergeFlowDefinitions, resolveDefaultParams } from '../utils';
import { ForkFlowModel } from './forkFlowModel';
// 使用WeakMap存储每个类的meta
@ -68,7 +67,11 @@ export class FlowModel<Structure extends { parent?: any; subModels?: any } = Def
return options.flowEngine.getModel(options.uid);
}
this.uid = options.uid || uid();
if (!options.uid) {
options.uid = uid();
}
this.uid = options.uid;
this.props = options.props || {};
this.stepParams = options.stepParams || {};
this.subModels = {};

View File

@ -248,7 +248,7 @@ export interface CreateModelOptions {
[key: string]: any; // 允许额外的自定义选项
}
export interface IFlowModelRepository<T extends FlowModel = FlowModel> {
load(uid: string): Promise<Record<string, any> | null>;
findOne(query: Record<string, any>): Promise<Record<string, any> | null>;
save(model: T): Promise<Record<string, any>>;
destroy(uid: string): Promise<boolean>;
}