mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-02 03:02:19 +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> {
|
||||
// 从本地存储加载模型数据
|
||||
async load(uid: string) {
|
||||
async findOne({ uid }) {
|
||||
const data = localStorage.getItem(`flow-model:${uid}`);
|
||||
if (!data) return null;
|
||||
return JSON.parse(data);
|
||||
|
@ -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 />,
|
||||
});
|
||||
```
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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} /> });
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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} />;
|
||||
};
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 = {};
|
||||
|
@ -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>;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user