feat(client): improve the sub table field

This commit is contained in:
chenos 2022-02-25 16:24:50 +08:00
parent 6d0978f2c2
commit 585d9dd580
8 changed files with 387 additions and 112 deletions

View File

@ -8,12 +8,19 @@ import {
useDataSourceFromRAC
} from './';
import * as hooks from './action-hooks';
import { DataSourceProvider, ds } from './sub-table';
export const CollectionManagerSchemaComponentProvider: React.FC = (props) => {
return (
<SchemaComponentOptions
scope={{ cm: { ...hooks, useDataSourceFromRAC } }}
components={{ CollectionField, CollectionFieldProvider, CollectionProvider, ResourceActionProvider }}
scope={{ cm: { ...hooks, useDataSourceFromRAC }, ds }}
components={{
DataSourceProvider,
CollectionField,
CollectionFieldProvider,
CollectionProvider,
ResourceActionProvider,
}}
>
{props.children}
</SchemaComponentOptions>

View File

@ -6,7 +6,8 @@ import { Button, Dropdown, Menu } from 'antd';
import { cloneDeep } from 'lodash';
import React, { useState } from 'react';
import { useRequest } from '../../api-client';
import { ActionContext, SchemaComponent, useActionContext, useCompile, useFormBlockContext } from '../../schema-component';
import { RecordProvider } from '../../record-provider';
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
import { useCollectionManager } from '../hooks';
import { IField } from '../interfaces/types';
import { options } from './interfaces';
@ -61,7 +62,7 @@ const getSchema = (schema: IField): ISchema => {
'x-component': 'Action',
'x-component-props': {
type: 'primary',
useAction: '{{ useCreateSubField }}',
useAction: '{{ ds.useCreateAction }}',
},
},
},
@ -73,17 +74,9 @@ const getSchema = (schema: IField): ISchema => {
};
const useCreateSubField = () => {
// const form = useForm();
const { form, parent } = useFormBlockContext();
const ctx = useActionContext();
return {
async run() {
await form.submit();
const children = parent.form.values?.children?.slice?.();
children.push(cloneDeep(form.values));
console.log('form.values', form.values, children);
parent.form.setValuesIn('children', children);
ctx.setVisible(false);
// const options = form?.values?.uiSchema?.enum?.slice() || [];
// form.setValuesIn(
// 'uiSchema.enum',
@ -132,7 +125,9 @@ export const AddSubFieldAction = () => {
</Button>
</Dropdown>
<RecordProvider record={{}}>
<SchemaComponent schema={schema} components={{ ArrayTable }} scope={{ useCreateSubField }} />
</RecordProvider>
</ActionContext.Provider>
);
};

View File

@ -1,12 +1,13 @@
import { ArrayTable } from '@formily/antd';
import { ISchema } from '@formily/react';
import { ISchema, useForm } from '@formily/react';
import { uid } from '@formily/shared';
import cloneDeep from 'lodash/cloneDeep';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useAPIClient, useRequest } from '../../api-client';
import { useRecord } from '../../record-provider';
import { ActionContext, SchemaComponent, useActionContext, useFormBlockContext } from '../../schema-component';
import { ActionContext, SchemaComponent } from '../../schema-component';
import { useUpdateAction } from '../action-hooks';
import { useCollectionManager } from '../hooks';
import { IField } from '../interfaces/types';
@ -54,7 +55,7 @@ const getSchema = (schema: IField): ISchema => {
'x-component': 'Action',
'x-component-props': {
type: 'primary',
useAction: '{{ useUpdateSubField }}',
useAction: '{{ ds.useUpdateAction }}',
},
},
},
@ -65,23 +66,25 @@ const getSchema = (schema: IField): ISchema => {
};
};
const useUpdateSubField = () => {
const { form, parent } = useFormBlockContext();
const ctx = useActionContext();
const useUpdateCollectionField = () => {
const form = useForm();
const { run } = useUpdateAction();
const { refreshCM } = useCollectionManager();
return {
async run() {
await form.submit();
const children = parent.form.values?.children?.slice?.();
parent.form.setValuesIn(
'children',
children.map((child) => {
if (child.name === form.values.name) {
return cloneDeep(form.values);
}
return child;
const options = form?.values?.uiSchema?.enum?.slice() || [];
form.setValuesIn(
'uiSchema.enum',
options.map((option) => {
return {
value: uid(),
...option,
};
}),
);
ctx.setVisible(false);
await run();
await refreshCM();
},
};
};
@ -97,15 +100,13 @@ export const EditSubFieldAction = (props) => {
<ActionContext.Provider value={{ visible, setVisible }}>
<a
onClick={async () => {
// const { data } = await api.resource('fields.children', record.key).get({
// const { data } = await api.resource('collections.fields', record.collectionName).get({
// filterByTk: record.name,
// appends: ['uiSchema'],
// appends: record.interface === 'subTable' ? ['uiSchema', 'children'] : ['uiSchema'],
// });
const schema = getSchema({
...getInterface(record.interface),
default: {
...record,
},
default: record,
});
setSchema(schema);
setVisible(true);
@ -113,7 +114,7 @@ export const EditSubFieldAction = (props) => {
>
{t('Edit')}
</a>
<SchemaComponent schema={schema} components={{ ArrayTable }} scope={{ useUpdateSubField }} />
<SchemaComponent schema={schema} components={{ ArrayTable }} scope={{ useUpdateCollectionField }} />
</ActionContext.Provider>
);
};

View File

@ -33,15 +33,15 @@ export const subTable: IField = {
...defaultProps,
subtable: {
type: 'void',
'x-component': 'div',
'x-component': 'DataSourceProvider',
properties: {
actions: {
type: 'void',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 16,
},
// style: {
// marginBottom: 16,
// },
},
properties: {
delete: {
@ -49,7 +49,7 @@ export const subTable: IField = {
title: '{{ t("Delete") }}',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ useBulkDestroySubField }}',
useAction: '{{ ds.useBulkDestroyAction }}',
confirm: {
title: "{{t('Delete record')}}",
content: "{{t('Are you sure you want to delete it?')}}",
@ -73,11 +73,15 @@ export const subTable: IField = {
'x-component': 'Table.Array',
'x-component-props': {
pagination: false,
expandable: {
childrenColumnName: '__nochildren__',
},
rowKey: 'name',
rowSelection: {
type: 'checkbox',
},
useSelectedRowKeys: '{{ useSelectedRowKeys }}',
useSelectedRowKeys: '{{ ds.useSelectedRowKeys }}',
useDataSource: '{{ ds.useDataSource }}',
// scroll: { x: '100%' },
},
properties: {
@ -96,7 +100,6 @@ export const subTable: IField = {
column2: {
type: 'void',
title: '{{ t("Field name") }}',
'x-decorator': 'Table.Column.Decorator',
'x-component': 'Table.Column',
properties: {
name: {
@ -108,7 +111,6 @@ export const subTable: IField = {
column3: {
type: 'void',
title: '{{ t("Field interface") }}',
'x-decorator': 'Table.Column.Decorator',
'x-component': 'Table.Column',
properties: {
interface: {
@ -134,7 +136,7 @@ export const subTable: IField = {
title: '{{ t("Edit") }}',
'x-component': 'EditSubFieldAction',
'x-component-props': {
type: 'primary',
// useAction: '{{ ds.useUpdateAction }}',
},
},
delete: {
@ -142,7 +144,7 @@ export const subTable: IField = {
title: '{{ t("Delete") }}',
'x-component': 'Action.Link',
'x-component-props': {
useAction: '{{ useDestroySubField }}',
useAction: '{{ ds.useDestroyAction }}',
confirm: {
title: "{{t('Delete record')}}",
content: "{{t('Are you sure you want to delete it?')}}",

View File

@ -0,0 +1,214 @@
import { observer, useForm } from '@formily/react';
import React, { createContext, useContext, useState } from 'react';
import { CollectionOptions, CollectionProvider, useActionContext, useRecord, useRequest } from '../';
import { useAPIClient } from '../api-client';
import { options } from './Configuration/interfaces';
const collection: CollectionOptions = {
name: 'fields',
targetKey: 'name',
fields: [
{
type: 'string',
name: 'type',
interface: 'input',
uiSchema: {
title: '{{ t("Storage type") }}',
type: 'string',
'x-component': 'Select',
enum: [
{
label: 'String',
value: 'string',
},
],
required: true,
},
},
{
type: 'string',
name: 'interface',
interface: 'input',
uiSchema: {
title: '{{ t("Field interface") }}',
type: 'string',
'x-component': 'Select',
enum: options as any,
},
},
{
type: 'string',
name: 'title',
interface: 'input',
uiSchema: {
title: '{{ t("Field display name") }}',
type: 'string',
'x-component': 'Input',
required: true,
},
},
{
type: 'string',
name: 'name',
interface: 'input',
uiSchema: {
title: '{{ t("Field name") }}',
type: 'string',
'x-component': 'Input',
},
},
],
};
export const DataSourceContext = createContext(null);
const useSelectedRowKeys = () => {
const ctx = useContext(DataSourceContext);
return [ctx.selectedRowKeys, ctx.setSelectedRowKeys];
};
const useDataSource = (options) => {
const ctx = useContext(DataSourceContext);
return useRequest(
() => {
return Promise.resolve({
data: ctx.dataSource,
});
},
{
...options,
refreshDeps: [JSON.stringify(ctx.dataSource)],
},
);
};
const useCreateAction = () => {
const ctx = useContext(DataSourceContext);
const form = useForm();
const { setVisible } = useActionContext();
return {
async run() {
// console.log(ctx.dataSource);
const dataSource = ctx.dataSource || [];
dataSource.push(form.values);
ctx.setDataSource([...dataSource]);
setVisible(false);
},
};
};
const useBulkDestroyAction = () => {
const ctx = useContext(DataSourceContext);
const { selectedRowKeys, setSelectedRowKeys } = ctx;
return {
async run() {
const dataSource = ctx.dataSource || [];
ctx.setDataSource(
dataSource.filter((item) => {
return !selectedRowKeys.includes(item[ctx.rowKey]);
}),
);
setSelectedRowKeys([]);
},
};
};
const useUpdateAction = () => {
const record = useRecord();
const form = useForm();
const { setVisible } = useActionContext();
const ctx = useContext(DataSourceContext);
return {
async run() {
const dataSource = ctx?.dataSource || [];
const rowKey = ctx?.rowKey;
const values = dataSource.map((item) => {
if (record[rowKey] === item[rowKey]) {
return { ...form.values };
}
return item;
});
ctx.setDataSource([...values]);
setVisible(false);
},
};
};
const useDestroyAction = () => {
const record = useRecord();
const ctx = useContext(DataSourceContext);
return {
async run() {
const rowKey = ctx.rowKey;
const dataSource = ctx.dataSource || [];
ctx.setDataSource(
dataSource.filter((item) => {
return record[rowKey] !== item[rowKey];
}),
);
},
};
};
export const ds = {
useSelectedRowKeys,
useDataSource,
useCreateAction,
useBulkDestroyAction,
useUpdateAction,
useDestroyAction,
};
export const DataSourceProvider = observer((props) => {
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [dataSource, setDataSource] = useState([]);
const record = useRecord();
const api = useAPIClient();
const service = useRequest(
() => {
if (record.interface === 'subTable') {
if (record?.children?.length) {
return Promise.resolve({
data: record?.children || [],
});
}
return api
.resource('fields')
.list({
paginate: false,
appends: ['uiSchema'],
sort: 'sort',
filter: {
parentKey: record.key,
},
})
.then((res) => res?.data);
}
return Promise.resolve({
data: [],
});
},
{
onSuccess(data) {
console.log('dataSource1', data?.data);
setDataSource(data?.data);
},
},
);
return (
<CollectionProvider collection={collection}>
<DataSourceContext.Provider
value={{
rowKey: 'name',
service,
dataSource,
setDataSource,
selectedRowKeys,
setSelectedRowKeys,
}}
>
{props.children}
</DataSourceContext.Provider>
</CollectionProvider>
);
});

View File

@ -121,7 +121,13 @@ export const TableArray: React.FC<any> = observer((props) => {
};
return (
<div>
<Table {...others} {...restProps} components={components} columns={columns} dataSource={field.value?.slice()} />
<Table
{...others}
{...restProps}
components={components}
columns={columns}
dataSource={field?.value?.slice?.()}
/>
</div>
);
});

View File

@ -13,68 +13,12 @@ import React, { createContext, useContext, useState } from 'react';
const DataSourceContext = createContext(null);
const schema: ISchema = {
type: 'object',
properties: {
context: {
type: 'void',
'x-component': 'Context',
properties: {
action1: {
title: '提交',
'x-component': 'Action',
'x-component-props': {
useAction() {
const ctx = useContext(DataSourceContext);
return {
async run() {
console.log(ctx.dataSource);
const dataSource = ctx.dataSource || [];
dataSource.push({
id: uid(),
name: uid(),
});
ctx.setDataSource([...dataSource]);
},
};
},
},
},
action2: {
title: '删除',
'x-component': 'Action',
'x-component-props': {
useAction() {
const ctx = useContext(DataSourceContext);
const { selectedRowKeys, setSelectedRowKeys } = ctx;
return {
async run() {
const dataSource = ctx.dataSource || [];
ctx.setDataSource(
dataSource.filter((item) => {
return !selectedRowKeys.includes(item.id);
}),
);
setSelectedRowKeys([]);
},
};
},
},
},
input: {
type: 'array',
title: `编辑模式`,
'x-component': 'Table.Array',
'x-component-props': {
rowKey: 'id',
rowSelection: {
type: 'checkbox',
},
useSelectedRowKeys() {
const useSelectedRowKeys = () => {
const ctx = useContext(DataSourceContext);
return [ctx.selectedRowKeys, ctx.setSelectedRowKeys];
},
useDataSource(options) {
};
const useDataSource = (options) => {
const ctx = useContext(DataSourceContext);
return useRequest(
() => {
@ -88,7 +32,116 @@ const schema: ISchema = {
refreshDeps: [JSON.stringify(ctx.dataSource)],
},
);
};
const useCreateAction = () => {
const ctx = useContext(DataSourceContext);
return {
async run() {
console.log(ctx.dataSource);
const dataSource = ctx.dataSource || [];
dataSource.push({
id: uid(),
name: uid(),
});
ctx.setDataSource([...dataSource]);
},
};
};
const useBulkDestroyAction = () => {
const ctx = useContext(DataSourceContext);
const { selectedRowKeys, setSelectedRowKeys } = ctx;
return {
async run() {
const dataSource = ctx.dataSource || [];
ctx.setDataSource(
dataSource.filter((item) => {
return !selectedRowKeys.includes(item.id);
}),
);
setSelectedRowKeys([]);
},
};
};
const useUpdateAction = () => {
const record = useRecord();
// const form = useForm();
const ctx = useContext(DataSourceContext);
return {
async run() {
const dataSource = ctx.dataSource || [];
ctx.setDataSource([
...dataSource.map((item) => {
if (record.id === item.id) {
record.name = uid();
return record;
}
return item;
}),
]);
},
};
};
const useDestroyAction = () => {
const record = useRecord();
const ctx = useContext(DataSourceContext);
return {
async run() {
const dataSource = ctx.dataSource || [];
ctx.setDataSource(
dataSource.filter((item) => {
return record.id !== item.id;
}),
);
},
};
};
const ds = {
useSelectedRowKeys,
useDataSource,
useCreateAction,
useBulkDestroyAction,
useUpdateAction,
useDestroyAction,
};
const schema: ISchema = {
type: 'object',
properties: {
context: {
type: 'void',
'x-component': 'DataSourceProvider',
properties: {
action1: {
title: '添加',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ ds.useCreateAction }}',
},
},
action2: {
title: '删除',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ ds.useBulkDestroyAction }}',
},
},
input: {
type: 'array',
title: `编辑模式`,
'x-component': 'Table.Array',
'x-component-props': {
rowKey: 'id',
pagination: false,
rowSelection: {
type: 'checkbox',
},
useSelectedRowKeys: '{{ ds.useSelectedRowKeys }}',
useDataSource: '{{ ds.useDataSource }}',
},
properties: {
column1: {
@ -108,24 +161,18 @@ const schema: ISchema = {
title: 'Actions',
'x-component': 'Table.Column',
properties: {
action: {
action1: {
title: '编辑',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ ds.useUpdateAction }}',
},
},
action2: {
title: '删除',
'x-component': 'Action',
'x-component-props': {
useAction() {
const record = useRecord();
const ctx = useContext(DataSourceContext);
return {
async run() {
const dataSource = ctx.dataSource || [];
ctx.setDataSource(
dataSource.filter((item) => {
return record.id !== item.id;
}),
);
},
};
},
useAction: '{{ ds.useDestroyAction }}',
},
},
},
@ -137,7 +184,7 @@ const schema: ISchema = {
},
};
const Context = observer((props) => {
const DataSourceProvider = observer((props) => {
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [dataSource, setDataSource] = useState([]);
const service = useRequest(
@ -174,7 +221,7 @@ const Context = observer((props) => {
export default () => {
return (
<SchemaComponentProvider components={{ Action, Context, Table, Input }}>
<SchemaComponentProvider scope={{ ds }} components={{ Action, DataSourceProvider, Table, Input }}>
<SchemaComponent schema={schema} />
</SchemaComponentProvider>
);

View File

@ -25,6 +25,9 @@ export class MagicAttributeModel extends Model {
}
return super.set(`${this.magicAttribute}.${key}`, value, options);
} else {
if (!key) {
return;
}
Object.keys(key).forEach((k) => {
this.set(k, key[k], options);
});