feat: generator add function of getDataSource from ref

This commit is contained in:
helloqian12138 2021-12-20 21:45:05 +08:00
parent 8593e235d7
commit 8fc99d2a25
11 changed files with 128 additions and 95 deletions

View File

@ -1,3 +1,4 @@
/* stylelint-disable selector-class-pattern */
.__dumi-default-layout[data-route="/drip-table-generator/preview"] { .__dumi-default-layout[data-route="/drip-table-generator/preview"] {
padding-top: 64px; padding-top: 64px;
padding-left: 0; padding-left: 0;
@ -12,5 +13,9 @@
padding: 16px 16px; padding: 16px 16px;
border-bottom: 1px solid #e6e6ee; border-bottom: 1px solid #e6e6ee;
box-shadow: 0 1px 4px -1px rgba(0, 0, 0, .05); box-shadow: 0 1px 4px -1px rgba(0, 0, 0, .05);
.header-button {
margin: 0 12px;
}
} }
} }

View File

@ -8,7 +8,7 @@ import React from 'react';
import { Button, Row } from 'antd'; import { Button, Row } from 'antd';
import { DripTableSchema } from 'drip-table'; import { DripTableSchema } from 'drip-table';
import DripTableDriverAntDesign from 'drip-table-driver-antd'; import DripTableDriverAntDesign from 'drip-table-driver-antd';
import DripTableGenerator from 'drip-table-generator'; import DripTableGenerator, { DripTableGeneratorHandler } from 'drip-table-generator';
import 'antd/dist/antd.css'; import 'antd/dist/antd.css';
import 'drip-table-generator/index.css'; import 'drip-table-generator/index.css';
@ -53,9 +53,7 @@ const initialSchema: DripTableSchema = {
const Demo = (props: { showHeader: boolean }) => { const Demo = (props: { showHeader: boolean }) => {
const generator: React.MutableRefObject<null | { const generator: React.MutableRefObject<DripTableGeneratorHandler | null> = React.useRef(null);
getSchemaValue: () => void;
}> = React.useRef(null);
const views = { const views = {
demoHeader: props.showHeader !== false, demoHeader: props.showHeader !== false,
@ -65,17 +63,18 @@ const Demo = (props: { showHeader: boolean }) => {
<React.Fragment> <React.Fragment>
{ views.demoHeader && ( { views.demoHeader && (
<Row className="sample-header-extra-container"> <Row className="sample-header-extra-container">
<Button type="primary" onClick={() => { console.log(generator.current?.getSchemaValue()); }}>schema</Button> <Button className="header-button" type="primary" onClick={() => { console.log(generator.current?.getSchemaValue()); }}>schema</Button>
<Button className="header-button" type="primary" onClick={() => { console.log(generator.current?.getDataSource()); }}>dataSource</Button>
</Row> </Row>
)} )}
<DripTableGenerator <DripTableGenerator
ref={generator} ref={generator}
style={{ height: 720 }} style={{ height: 640 }}
driver={DripTableDriverAntDesign} driver={DripTableDriverAntDesign}
schema={initialSchema} schema={initialSchema}
dataSource={mockData.slice(0, 4)} dataSource={mockData.slice(0, 4)}
dataFields={['id', 'name', 'status', 'description', 'ext.state']} dataFields={['id', 'name', 'status', 'description', 'ext.state']}
onExportSchema={(schema) => { console.log(schema); }} onExportSchema={schema => { console.log(schema); }}
customComponents={{ custom: { TextComponent } }} customComponents={{ custom: { TextComponent } }}
customComponentPanel={components} customComponentPanel={components}
/> />

View File

@ -1,7 +1,4 @@
import { createContext } from 'react'; import { createContext } from 'react';
import { DripTableRecordTypeBase } from 'drip-table';
import { DripTableGeneratorProps } from '@/typing'; import { DripTableGeneratorProps } from '@/typing';
export type IDripTableGeneratorContext<RecordType extends DripTableRecordTypeBase> = DripTableGeneratorProps<RecordType>; export const Ctx = createContext<DripTableGeneratorProps>({});
export const Ctx = createContext<IDripTableGeneratorContext<Record<string, unknown>>>({});

View File

@ -1,17 +1,19 @@
import React, { useState, forwardRef, useImperativeHandle, useRef } from 'react'; import React, { useState, forwardRef, useImperativeHandle, useRef } from 'react';
import { ConfigProvider } from 'antd'; import { ConfigProvider } from 'antd';
import { ColumnConfig, DripTableRecordTypeBase, DripTableSchema } from 'drip-table'; import { ColumnConfig, DripTableSchema } from 'drip-table';
import zhCN from 'antd/lib/locale/zh_CN'; import zhCN from 'antd/lib/locale/zh_CN';
import { Ctx } from '@/context'; import { Ctx } from '@/context';
import { DripTableGeneratorProps, DripTableGeneratorHandler } from '@/typing'; import { DripTableGeneratorProps, DripTableGeneratorHandler } from '@/typing';
import { defaultState, GlobalStore } from '@/store'; import { defaultState, DripTableGeneratorState, GlobalStore } from '@/store';
import Wrapper from './wrapper'; import Wrapper, { GeneratorWrapperHandler } from './wrapper';
import 'antd/dist/antd.less'; const useTableRoot = (
props: DripTableGeneratorProps,
const useTableRoot = (props, store, wrapper) => { store: [DripTableGeneratorState, React.Dispatch<React.SetStateAction<DripTableGeneratorState>>],
wrapper: React.MutableRefObject<GeneratorWrapperHandler | null>,
) => {
const [state, setState] = store; const [state, setState] = store;
const getSchemaValue = (): DripTableSchema => { const getSchemaValue = (): DripTableSchema => {
@ -36,24 +38,34 @@ const useTableRoot = (props, store, wrapper) => {
}; };
}; };
const getDataSource = () => {
if (wrapper.current) {
const currentState = wrapper.current.getState();
return currentState.previewDataSource;
}
return state.previewDataSource;
};
const context = { const context = {
...props, ...props,
...state,
getSchemaValue, getSchemaValue,
getDataSource,
setGlobalData: setState, setGlobalData: setState,
}; };
return context; return context;
}; };
const Container = <RecordType extends DripTableRecordTypeBase>(props: DripTableGeneratorProps<RecordType>, ref: React.ForwardedRef<DripTableGeneratorHandler>) => { const Container = (props: DripTableGeneratorProps, ref: React.ForwardedRef<DripTableGeneratorHandler>) => {
const wrapper = useRef({}); const wrapper = useRef(null);
const initialState = defaultState(); const initialState = defaultState();
const store = useState(initialState); const store = useState(initialState);
const context = useTableRoot(props, store, wrapper); const context = useTableRoot(props, store, wrapper);
useImperativeHandle(ref, () => context); useImperativeHandle(ref, () => context);
const WrapperRef = forwardRef<unknown, DripTableGeneratorProps<RecordType> & { store: GlobalStore }>(Wrapper); const WrapperRef = forwardRef<GeneratorWrapperHandler, DripTableGeneratorProps & { store: GlobalStore }>(Wrapper);
return ( return (
<ConfigProvider locale={zhCN}> <ConfigProvider locale={zhCN}>

View File

@ -7,7 +7,7 @@
*/ */
import React from 'react'; import React from 'react';
import { Result, Tabs } from 'antd'; import { Alert, Result, Tabs } from 'antd';
import { ExclamationCircleTwoTone } from '@ant-design/icons'; import { ExclamationCircleTwoTone } from '@ant-design/icons';
import { DripTableSchema } from 'drip-table'; import { DripTableSchema } from 'drip-table';
import MonacoEditor from '@monaco-editor/react'; import MonacoEditor from '@monaco-editor/react';
@ -38,12 +38,14 @@ const { TabPane } = Tabs;
const AttributeLayout = (props: Props & { store: GlobalStore }) => { const AttributeLayout = (props: Props & { store: GlobalStore }) => {
const { dataFields } = useGlobalData(); const { dataFields } = useGlobalData();
const [state, setState] = props.store;
const store = { state, setState };
const [activeKey, setActiveKey] = React.useState('0'); const [activeKey, setActiveKey] = React.useState('0');
const [state, actions] = props.store; const [codeErrorMessage, setCodeErrorMessage] = React.useState('');
const store = { state, setState: actions };
const [code, setCode] = React.useState(JSON.stringify(state.dataSource, null, 4)); const code = JSON.stringify(state.previewDataSource, null, 4);
const getActiveKey = () => { const getActiveKey = () => {
if (activeKey === '0') { if (activeKey === '0') {
@ -129,17 +131,22 @@ const AttributeLayout = (props: Props & { store: GlobalStore }) => {
} as DripTableColumn; } as DripTableColumn;
}; };
/** TODO: 报错逻辑后续优化 */ /** TODO:
function submitDataWithoutThrottle() { *
* @param {string} codeValue JSON
*/
const submitDataWithoutDebounce = (codeValue: string) => {
setCodeErrorMessage('');
try { try {
state.dataSource = JSON.parse(code); state.previewDataSource = JSON.parse(codeValue);
globalActions.updateDataSource(store); setState({ ...state });
globalActions.updatePreviewDataSource(store);
} catch (error) { } catch (error) {
console.error(error); setCodeErrorMessage((error as Error).message);
}
} }
};
const submitTableData = debounce(submitDataWithoutThrottle, 1000); const submitTableData = debounce(submitDataWithoutDebounce, 1000);
const renderGlobalForm = () => ( const renderGlobalForm = () => (
<CustomForm<GlobalSchema> <CustomForm<GlobalSchema>
@ -169,7 +176,7 @@ const AttributeLayout = (props: Props & { store: GlobalStore }) => {
return; return;
} }
if (uiProps.from === 'dataSource') { if (uiProps.from === 'dataSource') {
uiProps.options = Object.keys(state.dataSource[0] || {}) uiProps.options = Object.keys(state.previewDataSource[0] || {})
.map(key => ({ label: key, value: key })); .map(key => ({ label: key, value: key }));
} else if (uiProps.from === 'dataFields') { } else if (uiProps.from === 'dataFields') {
uiProps.options = dataFields?.map(key => ({ label: key, value: key })) || []; uiProps.options = dataFields?.map(key => ({ label: key, value: key })) || [];
@ -181,7 +188,7 @@ const AttributeLayout = (props: Props & { store: GlobalStore }) => {
return; return;
} }
if (itemUiProps.from === 'dataSource') { if (itemUiProps.from === 'dataSource') {
itemUiProps.options = Object.keys(state.dataSource[0] || {}) itemUiProps.options = Object.keys(state.previewDataSource[0] || {})
.map(key => ({ label: key, value: key })); .map(key => ({ label: key, value: key }));
} else if (itemUiProps.from === 'dataFields') { } else if (itemUiProps.from === 'dataFields') {
itemUiProps.options = dataFields?.map(key => ({ label: key, value: key })) || []; itemUiProps.options = dataFields?.map(key => ({ label: key, value: key })) || [];
@ -226,13 +233,14 @@ const AttributeLayout = (props: Props & { store: GlobalStore }) => {
</TabPane> </TabPane>
<TabPane tab="表格数据" key="3" style={{ height: tabHeight, overflow: 'auto' }}> <TabPane tab="表格数据" key="3" style={{ height: tabHeight, overflow: 'auto' }}>
<div className={styles['attributes-code-panel']}> <div className={styles['attributes-code-panel']}>
{ codeErrorMessage && <Alert style={{ margin: '8px 0' }} message={codeErrorMessage} type="error" showIcon /> }
<MonacoEditor <MonacoEditor
width="100%" width="100%"
height={400} height={400}
language="json" language="json"
theme="vs-dark" theme="vs-dark"
value={code || ''} value={code || ''}
onChange={(value) => { setCode(value || ''); submitTableData(); }} onChange={(value) => { submitTableData(value); }}
/> />
</div> </div>
</TabPane> </TabPane>

View File

@ -18,12 +18,12 @@ import Draggable from '@/components/Draggable';
import styles from './index.module.less'; import styles from './index.module.less';
import { get } from '@/utils'; import { get } from '@/utils';
interface Props<RecordType extends DripTableRecordTypeBase> { interface Props {
driver: DripTableDriver<RecordType>; driver: DripTableDriver<DripTableRecordTypeBase>;
customComponents: DripTableProps<RecordType>['components'] | undefined; customComponents: DripTableProps<DripTableRecordTypeBase>['components'] | undefined;
} }
const EditableTable = <RecordType extends DripTableRecordTypeBase>(props: Props<RecordType> & { store: GlobalStore }) => { const EditableTable = (props: Props & { store: GlobalStore }) => {
const [state, actions] = props.store; const [state, actions] = props.store;
const store = { state, setState: actions }; const store = { state, setState: actions };
@ -36,8 +36,8 @@ const EditableTable = <RecordType extends DripTableRecordTypeBase>(props: Props<
const DripTableComponent = column['ui:type'].startsWith('custom::') const DripTableComponent = column['ui:type'].startsWith('custom::')
? customComponents[column['ui:type'].replace('custom::', '')] ? customComponents[column['ui:type'].replace('custom::', '')]
: builtInComponents[column['ui:type']]; : builtInComponents[column['ui:type']];
const hasRecord = !(!state.dataSource || state.dataSource.length <= 0); const hasRecord = !(!state.previewDataSource || state.previewDataSource.length <= 0);
const record = state.dataSource[0] || {} as Record<string, unknown>; const record = state.previewDataSource[0] || {} as Record<string, unknown>;
const value = column.dataIndex ? get(record, column.dataIndex) : record; const value = column.dataIndex ? get(record, column.dataIndex) : record;
const errorBoundary = () => { const errorBoundary = () => {

View File

@ -13,12 +13,12 @@ import { GlobalStore } from '@/store';
import styles from './index.module.less'; import styles from './index.module.less';
interface Props<RecordType extends DripTableRecordTypeBase> { interface Props {
driver: DripTableDriver<RecordType>; driver: DripTableDriver<DripTableRecordTypeBase>;
customComponents: DripTableProps<RecordType>['components']; customComponents: DripTableProps<DripTableRecordTypeBase>['components'];
} }
const PreviewTable = <RecordType extends DripTableRecordTypeBase>(props: Props<RecordType> & { store: GlobalStore }) => { const PreviewTable = (props: Props & { store: GlobalStore }) => {
const [state] = props.store; const [state] = props.store;
const schema: DripTableSchema = { const schema: DripTableSchema = {
@ -28,14 +28,14 @@ const PreviewTable = <RecordType extends DripTableRecordTypeBase>(props: Props<R
}, },
columns: state.columns as ColumnConfig[], columns: state.columns as ColumnConfig[],
}; };
const totalPage = state.globalConfigs?.pagination && state.globalConfigs?.pagination.pageSize ? state.dataSource.length : 1; const totalPage = state.globalConfigs?.pagination && state.globalConfigs?.pagination.pageSize ? state.previewDataSource.length : 1;
return ( return (
<div className={styles['table-preview-wrapper']}> <div className={styles['table-preview-wrapper']}>
<DripTable<RecordType> <DripTable
driver={(props.driver || DripTableDriverAntDesign)} driver={(props.driver || DripTableDriverAntDesign)}
schema={schema} schema={schema}
total={totalPage} total={totalPage}
dataSource={state.dataSource as RecordType[]} dataSource={state.previewDataSource}
components={props.customComponents} components={props.customComponents}
/> />
</div> </div>

View File

@ -109,6 +109,7 @@ const ToolLayout = (props: { store: GlobalStore }) => {
globalData.onExportSchema(getSchemaValue()); globalData.onExportSchema(getSchemaValue());
} }
} }
message.success('复制成功');
setModalStatus(''); setModalStatus('');
setCode(''); setCode('');
}} }}

View File

@ -23,7 +23,7 @@ export interface DripTableGeneratorState {
currentColumn?: DripTableColumn; currentColumn?: DripTableColumn;
globalConfigs: DripTableSchema['configs']; globalConfigs: DripTableSchema['configs'];
/** 表格数据generator不需要知道数据格式是什么直接交给drip-table即可 */ /** 表格数据generator不需要知道数据格式是什么直接交给drip-table即可 */
dataSource: Record<string, unknown>[]; previewDataSource: Record<string, unknown>[];
} }
export const defaultState: () => DripTableGeneratorState = () => ({ export const defaultState: () => DripTableGeneratorState = () => ({
@ -37,7 +37,7 @@ export const defaultState: () => DripTableGeneratorState = () => ({
pagination: false, pagination: false,
}, },
/** 数据 */ /** 数据 */
dataSource: [], previewDataSource: [],
}); });
export type GlobalStore = [DripTableGeneratorState, React.Dispatch<React.SetStateAction<DripTableGeneratorState>>]; export type GlobalStore = [DripTableGeneratorState, React.Dispatch<React.SetStateAction<DripTableGeneratorState>>];
@ -51,7 +51,7 @@ export type GlobalActions = {
toggleEditMode: (store?: GlobalStoreObject) => void; toggleEditMode: (store?: GlobalStoreObject) => void;
editColumns: (store?: GlobalStoreObject) => void; editColumns: (store?: GlobalStoreObject) => void;
checkColumn: (store?: GlobalStoreObject) => void; checkColumn: (store?: GlobalStoreObject) => void;
updateDataSource: (store?: GlobalStoreObject) => void; updatePreviewDataSource: (store?: GlobalStoreObject) => void;
updateGlobalConfig: (store?: GlobalStoreObject) => void; updateGlobalConfig: (store?: GlobalStoreObject) => void;
} }
@ -65,8 +65,8 @@ export const globalActions: GlobalActions = {
checkColumn(store) { checkColumn(store) {
store?.setState({ ...store.state, currentColumn: store.state.currentColumn ? { ...store.state?.currentColumn } : void 0 }); store?.setState({ ...store.state, currentColumn: store.state.currentColumn ? { ...store.state?.currentColumn } : void 0 });
}, },
updateDataSource(store) { updatePreviewDataSource(store) {
store?.setState({ ...store.state, dataSource: [...store.state.dataSource] }); store?.setState({ ...store.state, previewDataSource: [...store.state.previewDataSource] });
}, },
updateGlobalConfig(store) { updateGlobalConfig(store) {
store?.setState({ ...store.state, globalConfigs: { ...store.state.globalConfigs } }); store?.setState({ ...store.state, globalConfigs: { ...store.state.globalConfigs } });

View File

@ -48,19 +48,27 @@ export interface DripTableGeneratorHandler extends DripTableGeneratorState {
* @returns { DripTableSchema } DripTableSchema配置 * @returns { DripTableSchema } DripTableSchema配置
*/ */
getSchemaValue: () => DripTableSchema; getSchemaValue: () => DripTableSchema;
/**
*
*
* @returns {Record<string, unknown>[]}
*/
getDataSource: () => Record<string, unknown>[];
} }
export interface DripTableGeneratorProps<RecordType extends DripTableRecordTypeBase, CustomComponentEvent extends EventLike = never, Ext = unknown> { export interface DripTableGeneratorProps<CustomComponentEvent extends EventLike = never, Ext = unknown> {
style?: CSSProperties; style?: CSSProperties;
driver?: DripTableDriver<RecordType>; driver?: DripTableDriver<DripTableRecordTypeBase>;
showComponentLayout?: boolean; showComponentLayout?: boolean;
componentLayoutStyle?: CSSProperties; componentLayoutStyle?: CSSProperties;
rightLayoutStyle?: CSSProperties; rightLayoutStyle?: CSSProperties;
showToolLayout?: boolean; showToolLayout?: boolean;
dataSource?: RecordType[]; /** generator无需关心DataSource数据类型是什么唯一做的是直接传递给drip-table */
dataSource?: DripTableRecordTypeBase[];
dataFields?: string[]; dataFields?: string[];
schema?: DripTableSchema; schema?: DripTableSchema;
customComponents?: DripTableProps<RecordType, CustomComponentEvent, Ext>['components']; customComponents?: DripTableProps<DripTableRecordTypeBase, CustomComponentEvent, Ext>['components'];
customComponentPanel?: { customComponentPanel?: {
mode: 'add' | 'replace'; mode: 'add' | 'replace';
components: DripTableComponentConfig[]; components: DripTableComponentConfig[];

View File

@ -1,5 +1,4 @@
import React, { useState, useImperativeHandle } from 'react'; import React, { useState, useImperativeHandle } from 'react';
import { DripTableRecordTypeBase } from 'drip-table';
import DripTableDriverAntDesign from 'drip-table-driver-antd'; import DripTableDriverAntDesign from 'drip-table-driver-antd';
import { useGlobalData } from './hooks'; import { useGlobalData } from './hooks';
import { defaultState, DripTableGeneratorState, GlobalStore, setState } from './store'; import { defaultState, DripTableGeneratorState, GlobalStore, setState } from './store';
@ -12,9 +11,13 @@ import { DripTableGeneratorProps } from './typing';
import styles from './index.module.less'; import styles from './index.module.less';
const Wrapper = <RecordType extends DripTableRecordTypeBase>(props: DripTableGeneratorProps<RecordType> & { export type GeneratorWrapperHandler = {
getState: () => DripTableGeneratorState;
}
const Wrapper = (props: DripTableGeneratorProps & {
store: GlobalStore; store: GlobalStore;
}, ref) => { }, ref: React.ForwardedRef<GeneratorWrapperHandler>) => {
const { const {
style = {}, style = {},
driver, driver,
@ -22,12 +25,12 @@ const Wrapper = <RecordType extends DripTableRecordTypeBase>(props: DripTableGen
componentLayoutStyle = {}, componentLayoutStyle = {},
rightLayoutStyle = {}, rightLayoutStyle = {},
showToolLayout = true, showToolLayout = true,
dataSource = [], dataSource,
schema, schema,
customComponentPanel, customComponentPanel,
customComponents, customComponents,
} = useGlobalData(); } = useGlobalData();
const initialData = { dataSource } as DripTableGeneratorState; const initialData = { previewDataSource: dataSource } as DripTableGeneratorState;
if (schema) { if (schema) {
initialData.globalConfigs = schema.configs; initialData.globalConfigs = schema.configs;
initialData.columns = schema.columns?.map((item, index) => ({ key: index, sort: index, ...item })); initialData.columns = schema.columns?.map((item, index) => ({ key: index, sort: index, ...item }));