mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-02 11:12:20 +08:00
feat: improve code
This commit is contained in:
parent
fdba080de7
commit
d911e05a0e
@ -6,7 +6,7 @@ import React from 'react';
|
|||||||
// 实现一个本地存储的模型仓库,负责模型的持久化
|
// 实现一个本地存储的模型仓库,负责模型的持久化
|
||||||
class FlowModelRepository implements IFlowModelRepository<FlowModel> {
|
class FlowModelRepository implements IFlowModelRepository<FlowModel> {
|
||||||
// 从本地存储加载模型数据
|
// 从本地存储加载模型数据
|
||||||
async load(uid: string) {
|
async findOne({ uid }) {
|
||||||
const data = localStorage.getItem(`flow-model:${uid}`);
|
const data = localStorage.getItem(`flow-model:${uid}`);
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
return JSON.parse(data);
|
return JSON.parse(data);
|
||||||
|
@ -180,3 +180,33 @@ steps: {
|
|||||||
- 支持多种定义方式,适应不同复杂度的业务场景。
|
- 支持多种定义方式,适应不同复杂度的业务场景。
|
||||||
- 可通过 `uiSchema` 和 `defaultParams` 配置参数界面和默认值,提升易用性。
|
- 可通过 `uiSchema` 和 `defaultParams` 配置参数界面和默认值,提升易用性。
|
||||||
- 合理使用 `paramsRequired` 和 `hideInSettings`,提升操作安全性和灵活性。
|
- 合理使用 `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 />,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## 主要方法
|
## 主要方法
|
||||||
|
|
||||||
- **load(uid: string): Promise<FlowModel \| null>**
|
- **findOne(query: Query): Promise<FlowModel \| null>**
|
||||||
根据唯一标识符 uid 从远程加载模型数据。
|
根据唯一标识符 uid 从远程加载模型数据。
|
||||||
|
|
||||||
- **save(model: FlowModel): Promise<any>**
|
- **save(model: FlowModel): Promise<any>**
|
||||||
@ -19,7 +19,8 @@
|
|||||||
class FlowModelRepository implements IFlowModelRepository<FlowModel> {
|
class FlowModelRepository implements IFlowModelRepository<FlowModel> {
|
||||||
constructor(private app: Application) {}
|
constructor(private app: Application) {}
|
||||||
|
|
||||||
async load(uid: string) {
|
async findOne(query) {
|
||||||
|
const { uid, parentId } = query;
|
||||||
// 实现:根据 uid 获取模型
|
// 实现:根据 uid 获取模型
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import React from 'react';
|
|||||||
|
|
||||||
class FlowModelRepository implements IFlowModelRepository<FlowModel> {
|
class FlowModelRepository implements IFlowModelRepository<FlowModel> {
|
||||||
constructor(private app: Application) {}
|
constructor(private app: Application) {}
|
||||||
async load(uid: string) {
|
async findOne({ uid, parentId }) {
|
||||||
// implement fetching a model by id
|
// implement fetching a model by id
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,9 @@ import { Button, Tabs } from 'antd';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React from 'react';
|
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() {
|
get models() {
|
||||||
const models = new Map();
|
const models = new Map();
|
||||||
for (let i = 0; i < localStorage.length; i++) {
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
@ -22,8 +24,12 @@ class FlowModelRepository implements IFlowModelRepository<FlowModel<{parent: nev
|
|||||||
return models;
|
return models;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findOne(query) {
|
||||||
|
return this.load(query.uid);
|
||||||
|
}
|
||||||
|
|
||||||
// 从本地存储加载模型数据
|
// 从本地存储加载模型数据
|
||||||
async load(uid: string) {
|
async load({ uid }) {
|
||||||
const data = localStorage.getItem(`flow-model:${uid}`);
|
const data = localStorage.getItem(`flow-model:${uid}`);
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
const json: FlowModel = JSON.parse(data);
|
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()));
|
localStorage.setItem(`flow-model:${subModel.uid}`, JSON.stringify(subModel.serialize()));
|
||||||
});
|
});
|
||||||
} else if (model.subModels[subModelKey] instanceof FlowModel) {
|
} 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;
|
return data;
|
||||||
@ -72,8 +81,7 @@ class FlowModelRepository implements IFlowModelRepository<FlowModel<{parent: nev
|
|||||||
|
|
||||||
class TabFlowModel extends FlowModel {}
|
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) {
|
addTab(tab: any) {
|
||||||
// 使用新的 addSubModel API 添加子模型
|
// 使用新的 addSubModel API 添加子模型
|
||||||
const model = this.addSubModel('tabs', tab);
|
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) => ({
|
items={this.subModels.tabs?.map((tab) => ({
|
||||||
key: tab.getProps().key,
|
key: tab.getProps().key,
|
||||||
label: tab.getProps().label,
|
label: tab.getProps().label,
|
||||||
children: tab.render()
|
children: tab.render(),
|
||||||
}))}
|
}))}
|
||||||
tabBarExtraContent={
|
tabBarExtraContent={
|
||||||
<Button
|
<Button
|
||||||
@ -98,7 +106,7 @@ class HelloFlowModel extends FlowModel<{parent: never, subModels: { tabs: TabFlo
|
|||||||
use: 'TabFlowModel',
|
use: 'TabFlowModel',
|
||||||
uid: tabId,
|
uid: tabId,
|
||||||
props: { key: tabId, label: `Tab - ${tabId}` },
|
props: { key: tabId, label: `Tab - ${tabId}` },
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Add Tab
|
Add Tab
|
||||||
@ -134,7 +142,7 @@ class PluginHelloModel extends Plugin {
|
|||||||
props: { key: 'tab-2', label: 'Tab 2' },
|
props: { key: 'tab-2', label: 'Tab 2' },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
this.router.add('root', { path: '/', element: <FlowModelRenderer model={model} /> });
|
this.router.add('root', { path: '/', element: <FlowModelRenderer model={model} /> });
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,26 @@ export class MockFlowModelRepository implements IFlowModelRepository<FlowModel>
|
|||||||
return models;
|
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) {
|
async load(uid: string) {
|
||||||
const data = localStorage.getItem(`flow-model:${uid}`);
|
const data = localStorage.getItem(`flow-model:${uid}`);
|
||||||
@ -43,10 +63,12 @@ export class MockFlowModelRepository implements IFlowModelRepository<FlowModel>
|
|||||||
json.subModels[model.subKey].push(subModel);
|
json.subModels[model.subKey].push(subModel);
|
||||||
} else if (model.subType === 'object') {
|
} else if (model.subType === 'object') {
|
||||||
const subModel = await this.load(model.uid);
|
const subModel = await this.load(model.uid);
|
||||||
|
if (subModel) {
|
||||||
json.subModels[model.subKey] = subModel;
|
json.subModels[model.subKey] = subModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
console.log('Loading model:', uid, JSON.stringify(json, null, 2));
|
console.log('Loading model:', uid, JSON.stringify(json, null, 2));
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
import { FlowModelRenderer, useFlowEngine, useFlowModel } from '@nocobase/flow-engine';
|
import { FlowModelRenderer, useFlowEngine, useFlowModel } from '@nocobase/flow-engine';
|
||||||
import { useRequest } from 'ahooks';
|
import { useRequest } from 'ahooks';
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
|
|
||||||
function InternalFlowPage({ uid, sharedContext }) {
|
function InternalFlowPage({ uid, sharedContext }) {
|
||||||
@ -20,15 +20,16 @@ function InternalFlowPage({ uid, sharedContext }) {
|
|||||||
|
|
||||||
export const FlowPage = () => {
|
export const FlowPage = () => {
|
||||||
const params = useParams();
|
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 flowEngine = useFlowEngine();
|
||||||
const { loading } = useRequest(
|
const { loading, data } = useRequest(
|
||||||
() => {
|
async () => {
|
||||||
return flowEngine.loadOrCreateModel({
|
const options = {
|
||||||
uid: uid,
|
uid,
|
||||||
use: 'PageFlowModel',
|
use: 'PageFlowModel',
|
||||||
subModels: {
|
subModels: {
|
||||||
tabs: [
|
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 <Spin />;
|
||||||
}
|
}
|
||||||
return <InternalFlowPage uid={uid} sharedContext={sharedContext} />;
|
return <InternalFlowPage uid={data.uid} sharedContext={sharedContext} />;
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,7 @@ AddNewActionModel.registerFlow({
|
|||||||
function DrawerContent() {
|
function DrawerContent() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<FlowPageComponent uid={`${ctx.model.uid}-drawer`} sharedContext={{ ...ctx.extra, currentDrawer }} />
|
<FlowPageComponent parentId={ctx.model.uid} sharedContext={{ ...ctx.extra, currentDrawer }} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ ViewActionModel.registerFlow({
|
|||||||
function DrawerContent() {
|
function DrawerContent() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<FlowPageComponent uid={`${ctx.model.uid}-drawer`} sharedContext={{ ...ctx.extra, currentDrawer }} />
|
<FlowPageComponent parentId={ctx.model.uid} sharedContext={{ ...ctx.extra, currentDrawer }} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -227,13 +227,13 @@ export class FlowEngine {
|
|||||||
|
|
||||||
async loadModel<T extends FlowModel = FlowModel>(uid: string): Promise<T | null> {
|
async loadModel<T extends FlowModel = FlowModel>(uid: string): Promise<T | null> {
|
||||||
if (!this.ensureModelRepository()) return;
|
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;
|
return data?.uid ? this.createModel<T>(data as any) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadOrCreateModel<T extends FlowModel = FlowModel>(options): Promise<T | null> {
|
async loadOrCreateModel<T extends FlowModel = FlowModel>(options): Promise<T | null> {
|
||||||
if (!this.ensureModelRepository()) return;
|
if (!this.ensureModelRepository()) return;
|
||||||
const data = await this.modelRepository.load(options.uid);
|
const data = await this.modelRepository.findOne(options);
|
||||||
if (data?.uid) {
|
if (data?.uid) {
|
||||||
return this.createModel<T>(data as any);
|
return this.createModel<T>(data as any);
|
||||||
} else {
|
} else {
|
||||||
|
@ -14,7 +14,6 @@ import { uid } from 'uid/secure';
|
|||||||
import { openRequiredParamsStepFormDialog as openRequiredParamsStepFormDialogFn } from '../components/settings/wrappers/contextual/StepRequiredSettingsDialog';
|
import { openRequiredParamsStepFormDialog as openRequiredParamsStepFormDialogFn } from '../components/settings/wrappers/contextual/StepRequiredSettingsDialog';
|
||||||
import { openStepSettingsDialog as openStepSettingsDialogFn } from '../components/settings/wrappers/contextual/StepSettingsDialog';
|
import { openStepSettingsDialog as openStepSettingsDialogFn } from '../components/settings/wrappers/contextual/StepSettingsDialog';
|
||||||
import { FlowEngine } from '../flowEngine';
|
import { FlowEngine } from '../flowEngine';
|
||||||
import { FlowExitException, resolveDefaultParams } from '../utils';
|
|
||||||
import type {
|
import type {
|
||||||
ActionStepDefinition,
|
ActionStepDefinition,
|
||||||
ArrayElementType,
|
ArrayElementType,
|
||||||
@ -30,7 +29,7 @@ import type {
|
|||||||
StepParams,
|
StepParams,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { ExtendedFlowDefinition, FlowExtraContext, IModelComponentProps, ReadonlyModelProps } 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';
|
import { ForkFlowModel } from './forkFlowModel';
|
||||||
|
|
||||||
// 使用WeakMap存储每个类的meta
|
// 使用WeakMap存储每个类的meta
|
||||||
@ -68,7 +67,11 @@ export class FlowModel<Structure extends { parent?: any; subModels?: any } = Def
|
|||||||
return options.flowEngine.getModel(options.uid);
|
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.props = options.props || {};
|
||||||
this.stepParams = options.stepParams || {};
|
this.stepParams = options.stepParams || {};
|
||||||
this.subModels = {};
|
this.subModels = {};
|
||||||
|
@ -248,7 +248,7 @@ export interface CreateModelOptions {
|
|||||||
[key: string]: any; // 允许额外的自定义选项
|
[key: string]: any; // 允许额外的自定义选项
|
||||||
}
|
}
|
||||||
export interface IFlowModelRepository<T extends FlowModel = FlowModel> {
|
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>>;
|
save(model: T): Promise<Record<string, any>>;
|
||||||
destroy(uid: string): Promise<boolean>;
|
destroy(uid: string): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user