mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-08 06:59:26 +08:00
fix: demo
This commit is contained in:
parent
f1305b7592
commit
e0ac5ec62d
@ -1,22 +1,51 @@
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useBlockResource } from '@nocobase/client';
|
||||
import { useApplyFilter } from '@nocobase/plugin-event-filter-system/client';
|
||||
import { Spin, Table } from 'antd';
|
||||
import { EventContext, useAddEventListener, useApplyFilter } from '@nocobase/plugin-event-filter-system/client';
|
||||
import { Spin, Table, Button, Space, Row, Flex } from 'antd';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useApp } from '@nocobase/client';
|
||||
|
||||
const DemoTable = (props) => {
|
||||
const { done, result } = useApplyFilter('core:block:table', {
|
||||
props: props,
|
||||
const { done, result } = useApplyFilter('core:block:table', { props });
|
||||
const fieldSchema = useFieldSchema();
|
||||
const resource = useBlockResource();
|
||||
const app = useApp();
|
||||
|
||||
useAddEventListener('core:block:table:refresh', (ctx: EventContext) => {
|
||||
console.log('core:block:table:refresh', ctx);
|
||||
resource.list();
|
||||
});
|
||||
|
||||
const actionEventContext: EventContext = useMemo(() => {
|
||||
return {
|
||||
source: {
|
||||
uischema: fieldSchema.toJSON(),
|
||||
},
|
||||
};
|
||||
}, [fieldSchema]);
|
||||
|
||||
if (!done) {
|
||||
return <Spin />;
|
||||
}
|
||||
|
||||
const columns = result?.columns || [];
|
||||
const data = result?.data?.data || [];
|
||||
const actions = result?.actions || [];
|
||||
|
||||
return <Table style={{ height: result?.height, width: result?.width }} columns={columns} dataSource={data} />;
|
||||
return (
|
||||
<Flex vertical style={{ height: result?.height, width: result?.width }}>
|
||||
<Row justify="end" style={{ marginBottom: '16px' }}>
|
||||
<Space>
|
||||
{actions.map((action) => (
|
||||
<Button key={action.label} onClick={async () => await action.handle(actionEventContext)}>
|
||||
{action.label}
|
||||
</Button>
|
||||
))}
|
||||
</Space>
|
||||
</Row>
|
||||
<Table style={{ width: '100%' }} columns={columns} dataSource={data} />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default DemoTable;
|
||||
|
@ -96,8 +96,22 @@ const TableDataBlockInitializer = () => {
|
||||
},
|
||||
'x-component-settings': {
|
||||
height: '1000px',
|
||||
width: '50%',
|
||||
width: '100%',
|
||||
linkageRules: {},
|
||||
actions: [
|
||||
{
|
||||
label: '添加',
|
||||
type: 'addNew',
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
type: 'delete',
|
||||
},
|
||||
{
|
||||
label: '刷新',
|
||||
type: 'refresh',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
EventListenerOptions,
|
||||
ApplyFilterOptions,
|
||||
FilterContext,
|
||||
EventContext,
|
||||
} from './types';
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
|
||||
@ -46,6 +47,7 @@ export function useAddFilter(name: string, filter: FilterFunction, options: Filt
|
||||
* Hook that returns a function that will apply filters to a given value
|
||||
*
|
||||
* @param name - Filter name to apply
|
||||
* @param options - Apply filter options
|
||||
* @returns A function that applies the filter and returns a Promise
|
||||
*/
|
||||
|
||||
@ -91,31 +93,43 @@ export const useApplyFilter = (name: string, options: ApplyFilterOptions) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook for registering an event listener that will be automatically unregistered on component unmount
|
||||
* 事件监听器的默认过滤函数。
|
||||
* 根据事件上下文 (ctx) 和监听器的选项 (options) 确定监听器是否应执行。
|
||||
*
|
||||
* @param eventName - Event name(s) to listen for
|
||||
* @param listener - Event listener function
|
||||
* @param options - Event listener options
|
||||
* @param deps - Dependency array for memoizing the listener function
|
||||
* 逻辑:
|
||||
* 1. 如果事件分发没有包含目标 (ctx.target 为假值),则监听器始终运行(多播)。
|
||||
* 2. 如果事件分发包含了目标 (ctx.target 存在):
|
||||
* a. 如果监听器选项包含特定的目标条件 (例如 options.uischema),
|
||||
* 则仅当目标条件与上下文的目标匹配时,监听器才运行。
|
||||
*/
|
||||
export function useEventListener(
|
||||
eventName: string | string[],
|
||||
listener: EventListener,
|
||||
options: EventListenerOptions = {},
|
||||
deps: any[] = [],
|
||||
) {
|
||||
function defaultListenerFilter(ctx: EventContext, options: EventListenerOptions): boolean {
|
||||
// 1. 多播: 分发时未指定目标, 监听器运行。
|
||||
if (!ctx.target) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. 单播: 分发时指定了目标。检查监听器选项。
|
||||
if (options?.uischema) {
|
||||
const targetSchema = ctx.target.uischema;
|
||||
// 基本检查:两个 schema 都存在且具有匹配的 'x-uid'
|
||||
return !!(targetSchema && options.uischema['x-uid'] && options.uischema['x-uid'] === targetSchema['x-uid']);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function useAddEventListener(event: string | string[], handler: EventListener, options?: EventListenerOptions) {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const app = useApp();
|
||||
|
||||
// Memoize the listener function based on deps
|
||||
const memoizedListener = useCallback(listener, [listener, ...deps]);
|
||||
|
||||
useEffect(() => {
|
||||
// Register the listener on mount
|
||||
const unsubscribe = app.eventManager.on(eventName, memoizedListener, options);
|
||||
|
||||
// Unregister on unmount
|
||||
const unsubscribe = app.eventManager.on(event, handler, {
|
||||
filter: defaultListenerFilter,
|
||||
uischema: fieldSchema.toJSON(),
|
||||
...options,
|
||||
});
|
||||
return unsubscribe;
|
||||
}, [app, eventName, memoizedListener, options]);
|
||||
}, [handler, app, event, fieldSchema]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,8 +12,9 @@ import { EventManager } from './event-manager';
|
||||
import { FilterManager } from './filter-manager';
|
||||
import { Resource } from '@nocobase/resourcer';
|
||||
import { ComponentProps } from 'react';
|
||||
import { LinkageRuleSettings, LinkageRuleItem } from './types';
|
||||
import { LinkageRuleSettings, LinkageRuleItem, EventContext } from './types';
|
||||
import React from 'react';
|
||||
import { Modal, Form, Input } from 'antd';
|
||||
export * from './event-manager';
|
||||
export * from './filter-manager';
|
||||
export * from './hooks';
|
||||
@ -106,6 +107,7 @@ export class PluginEventFilterSystemClient extends Plugin {
|
||||
this.app.eventManager = this.eventManager;
|
||||
this.app.filterManager = this.filterManager;
|
||||
this.loadDefaultFilters();
|
||||
this.loadDefaultEventListeners();
|
||||
}
|
||||
|
||||
loadDefaultFilters() {
|
||||
@ -146,18 +148,30 @@ export class PluginEventFilterSystemClient extends Plugin {
|
||||
};
|
||||
});
|
||||
|
||||
this.filterManager.addFilter('core:block:table', async function actionsFilter(input, ctx) {
|
||||
this.filterManager.addFilter('core:block:table', async (input, ctx) => {
|
||||
// get actions from settings and input
|
||||
const { settings } = ctx;
|
||||
const linkageRules = settings?.linkageRules;
|
||||
const actionSettings = settings?.actions;
|
||||
const actions = [];
|
||||
const handles = {
|
||||
addNew: (ctx: EventContext) => {
|
||||
this.eventManager.dispatchEvent('core:block:record:addNew', ctx);
|
||||
},
|
||||
delete: (ctx: EventContext) => {
|
||||
this.eventManager.dispatchEvent('core:block:table:record:delete', ctx);
|
||||
},
|
||||
refresh: (ctx: EventContext) => {
|
||||
this.eventManager.dispatchEvent('core:block:table:refresh', ctx);
|
||||
},
|
||||
};
|
||||
Object.keys(actionSettings || {}).forEach((key) => {
|
||||
const action = actionSettings[key];
|
||||
actions.push({
|
||||
...action,
|
||||
const action = {
|
||||
...actionSettings[key],
|
||||
...linkageRules?.['actions'],
|
||||
});
|
||||
};
|
||||
action['handle'] = handles[action.type];
|
||||
actions.push(action);
|
||||
});
|
||||
|
||||
return {
|
||||
@ -204,6 +218,87 @@ export class PluginEventFilterSystemClient extends Plugin {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
loadDefaultEventListeners() {
|
||||
this.eventManager.on('core:block:record:addNew', (ctx: EventContext) => {
|
||||
console.log('core:block:record:addNew', ctx);
|
||||
|
||||
// Simple approach using Modal.open with form elements without Form component
|
||||
const modal = Modal.info({
|
||||
title: '新建记录',
|
||||
icon: null,
|
||||
content: (
|
||||
<div style={{ marginTop: 16 }}>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<label>名称</label>
|
||||
</div>
|
||||
<Input placeholder="请输入名称" id="record-name-input" />
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<label>描述</label>
|
||||
</div>
|
||||
<Input.TextArea placeholder="请输入描述" rows={4} id="record-description-input" />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
// Use footer to replace the default buttons
|
||||
footer: (
|
||||
<div style={{ textAlign: 'right', marginTop: 24 }}>
|
||||
<button
|
||||
onClick={() => {
|
||||
modal.destroy();
|
||||
}}
|
||||
style={{
|
||||
marginRight: 8,
|
||||
padding: '4px 15px',
|
||||
backgroundColor: 'white',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: 2,
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
const nameInput = document.getElementById('record-name-input') as HTMLInputElement;
|
||||
const descInput = document.getElementById('record-description-input') as HTMLTextAreaElement;
|
||||
|
||||
if (nameInput && nameInput.value) {
|
||||
const values = {
|
||||
name: nameInput.value,
|
||||
description: descInput ? descInput.value : '',
|
||||
};
|
||||
console.log('Form values:', values);
|
||||
modal.destroy();
|
||||
} else {
|
||||
// Highlight the name input if empty
|
||||
if (nameInput) {
|
||||
nameInput.style.borderColor = 'red';
|
||||
nameInput.focus();
|
||||
}
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
padding: '4px 15px',
|
||||
backgroundColor: '#1677ff',
|
||||
border: 'none',
|
||||
borderRadius: 2,
|
||||
color: 'white',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
确定
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default PluginEventFilterSystemClient;
|
||||
|
@ -47,7 +47,7 @@ export interface EventContext<T = any> {
|
||||
};
|
||||
|
||||
// 用于收集事件监听器的输出结果
|
||||
results: Record<string, any>;
|
||||
results?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface EventListenerOptions {
|
||||
|
Loading…
x
Reference in New Issue
Block a user