mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 14:46:13 +00:00
feat: improve code
This commit is contained in:
parent
24d5d3cfad
commit
20c839bfa9
@ -80,6 +80,12 @@ const schema: ISchema = {
|
||||
// accept: 'jpg,png'
|
||||
},
|
||||
},
|
||||
showLogoOnly: {
|
||||
type: 'boolean',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Checkbox',
|
||||
'x-content': '只显示 LOGO',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -38,7 +38,7 @@ export const SiteTitle = () => {
|
||||
{!loading && data?.logo?.url && (
|
||||
<img className={'site-logo'} src={data?.logo?.url} />
|
||||
)}
|
||||
{!loading && data.title && (
|
||||
{!loading && !data.showLogoOnly && data.title && (
|
||||
<div className={'site-title'}>{data.title}</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -63,8 +63,14 @@
|
||||
}
|
||||
}
|
||||
.site-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.site-logo {
|
||||
height: 20px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
.site-title {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
@ -40,6 +40,7 @@ import {
|
||||
import { DatePicker } from '../../schemas/date-picker';
|
||||
import { Filter } from '../../schemas/filter';
|
||||
import { Form } from '../../schemas/form';
|
||||
import { ActionLogs } from '../../schemas/action-logs';
|
||||
import { Grid } from '../../schemas/grid';
|
||||
import { IconPicker } from '../../schemas/icon-picker';
|
||||
import { Input } from '../../schemas/input';
|
||||
@ -192,6 +193,8 @@ export const SchemaField = createSchemaField({
|
||||
Tabs,
|
||||
TimePicker,
|
||||
Upload,
|
||||
|
||||
ActionLogs,
|
||||
},
|
||||
});
|
||||
|
||||
|
55
packages/client/src/schemas/action-logs/index.tsx
Normal file
55
packages/client/src/schemas/action-logs/index.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import { Field } from '@formily/core';
|
||||
import {
|
||||
ISchema,
|
||||
observer,
|
||||
RecursionField,
|
||||
Schema,
|
||||
useField,
|
||||
} from '@formily/react';
|
||||
import React from 'react';
|
||||
import { SchemaRenderer } from '../../components/schema-renderer';
|
||||
import ArrayTable from '../array-table';
|
||||
|
||||
export const ActionLogs = () => null;
|
||||
|
||||
ActionLogs.Field = observer((props: any) => {
|
||||
const { value } = props;
|
||||
return <div>{value?.uiSchema?.title || value?.name}</div>;
|
||||
});
|
||||
|
||||
ActionLogs.FieldValue = observer((props: any) => {
|
||||
const field = useField<Field>();
|
||||
const array = ArrayTable.useArray();
|
||||
const index = ArrayTable.useIndex();
|
||||
const collectionField = array.field.value[index]?.field;
|
||||
console.log('ffffff', collectionField?.uiSchema, field.value);
|
||||
|
||||
if (!collectionField.uiSchema) {
|
||||
if (!field.value) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
if (typeof field.value === 'boolean') {
|
||||
return <div>{field.value ? 'true' : 'false'}</div>;
|
||||
}
|
||||
if (typeof field.value === 'string' || typeof field.value === 'number') {
|
||||
return <div>{field.value}</div>;
|
||||
}
|
||||
return <pre>{JSON.stringify(field.value, null, 2)}</pre>;
|
||||
}
|
||||
|
||||
return (
|
||||
<SchemaRenderer
|
||||
schema={{
|
||||
type: 'object',
|
||||
properties: {
|
||||
[collectionField.name as string]: {
|
||||
...collectionField.uiSchema,
|
||||
default: field.value,
|
||||
'x-decorator': null,
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
@ -264,7 +264,7 @@ Action.Dropdown = observer((props: any) => {
|
||||
document.body,
|
||||
)}
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
trigger={['hover']}
|
||||
{...props}
|
||||
overlay={
|
||||
<Menu>
|
||||
|
@ -397,6 +397,7 @@ function generateCardItemSchema(component) {
|
||||
rowKey: 'id',
|
||||
// dragSort: true,
|
||||
showIndex: true,
|
||||
defaultSort: ['-id'],
|
||||
defaultAppends: ['user', 'collection'],
|
||||
refreshRequestOnChange: true,
|
||||
pagination: {
|
||||
@ -459,9 +460,9 @@ function generateCardItemSchema(component) {
|
||||
type: 'string',
|
||||
'x-component': 'Select',
|
||||
enum: [
|
||||
{ label: '新增数据', value: 'create' },
|
||||
{ label: '更新数据', value: 'update' },
|
||||
{ label: '删除数据', value: 'destroy' },
|
||||
{ label: '新增', value: 'create', color: 'green' },
|
||||
{ label: '更新', value: 'update', color: 'blue' },
|
||||
{ label: '删除', value: 'destroy', color: 'red' },
|
||||
],
|
||||
},
|
||||
},
|
||||
@ -521,7 +522,7 @@ function generateCardItemSchema(component) {
|
||||
properties: {
|
||||
created_at: {
|
||||
type: 'string',
|
||||
title: '创建时间',
|
||||
title: '操作时间',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'DatePicker',
|
||||
'x-read-pretty': true,
|
||||
@ -529,6 +530,20 @@ function generateCardItemSchema(component) {
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
},
|
||||
'user.nickname': {
|
||||
type: 'string',
|
||||
title: '操作用户',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
'collection.title': {
|
||||
type: 'string',
|
||||
title: '所属数据表',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
title: '操作类型',
|
||||
@ -536,9 +551,21 @@ function generateCardItemSchema(component) {
|
||||
'x-component': 'Select',
|
||||
'x-read-pretty': true,
|
||||
enum: [
|
||||
{ label: '新增数据', value: 'create' },
|
||||
{ label: '更新数据', value: 'update' },
|
||||
{ label: '删除数据', value: 'destroy' },
|
||||
{
|
||||
label: '新增',
|
||||
value: 'create',
|
||||
color: 'green',
|
||||
},
|
||||
{
|
||||
label: '更新',
|
||||
value: 'update',
|
||||
color: 'blue',
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
value: 'destroy',
|
||||
color: 'red',
|
||||
},
|
||||
],
|
||||
},
|
||||
changes: {
|
||||
@ -550,18 +577,33 @@ function generateCardItemSchema(component) {
|
||||
pagination: false,
|
||||
// scroll: { x: '100%' },
|
||||
},
|
||||
// 'x-reactions': ['{{ filterActionLogs }}'],
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
column0: {
|
||||
type: 'void',
|
||||
'x-component': 'ArrayTable.Column',
|
||||
'x-component-props': {
|
||||
width: 80,
|
||||
align: 'center',
|
||||
},
|
||||
properties: {
|
||||
index: {
|
||||
type: 'void',
|
||||
'x-component': 'ArrayTable.Index',
|
||||
},
|
||||
},
|
||||
},
|
||||
column1: {
|
||||
type: 'void',
|
||||
'x-component': 'ArrayTable.Column',
|
||||
'x-component-props': { title: '字段名称' },
|
||||
properties: {
|
||||
'field.uiSchema.title': {
|
||||
field: {
|
||||
type: 'string',
|
||||
'x-decorator': 'FormilyFormItem',
|
||||
'x-component': 'Input',
|
||||
'x-component': 'ActionLogs.Field',
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -573,7 +615,7 @@ function generateCardItemSchema(component) {
|
||||
before: {
|
||||
type: 'string',
|
||||
'x-decorator': 'FormilyFormItem',
|
||||
'x-component': 'Values',
|
||||
'x-component': 'ActionLogs.FieldValue',
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -585,7 +627,7 @@ function generateCardItemSchema(component) {
|
||||
after: {
|
||||
type: 'string',
|
||||
'x-decorator': 'FormilyFormItem',
|
||||
'x-component': 'Values',
|
||||
'x-component': 'ActionLogs.FieldValue',
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -604,7 +646,7 @@ function generateCardItemSchema(component) {
|
||||
},
|
||||
column1: {
|
||||
type: 'void',
|
||||
title: '创建时间',
|
||||
title: '操作时间',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
created_at: {
|
||||
@ -618,6 +660,30 @@ function generateCardItemSchema(component) {
|
||||
},
|
||||
},
|
||||
column2: {
|
||||
type: 'void',
|
||||
title: '操作用户',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
'user.nickname': {
|
||||
type: 'string',
|
||||
'x-component': 'Input',
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
column3: {
|
||||
type: 'void',
|
||||
title: '所属数据表',
|
||||
'x-component': 'Table.Column',
|
||||
properties: {
|
||||
'collection.title': {
|
||||
type: 'string',
|
||||
'x-component': 'Input',
|
||||
'x-read-pretty': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
column4: {
|
||||
type: 'void',
|
||||
title: '操作类型',
|
||||
'x-component': 'Table.Column',
|
||||
@ -627,9 +693,9 @@ function generateCardItemSchema(component) {
|
||||
'x-component': 'Select',
|
||||
'x-read-pretty': true,
|
||||
enum: [
|
||||
{ label: '新增数据', value: 'create' },
|
||||
{ label: '更新数据', value: 'update' },
|
||||
{ label: '删除数据', value: 'destroy' },
|
||||
{ label: '新增', value: 'create', color: 'green' },
|
||||
{ label: '更新', value: 'update', color: 'blue' },
|
||||
{ label: '删除', value: 'destroy', color: 'red' },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -1,13 +1,370 @@
|
||||
import React from 'react';
|
||||
import { ArrayTable as Table } from '@formily/antd';
|
||||
import { useField, Schema } from '@formily/react';
|
||||
import { Button } from 'antd';
|
||||
import cls from 'classnames';
|
||||
import { isValid, uid } from '@formily/shared';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { usePrefixCls } from '@formily/antd/lib/__builtins__';
|
||||
// import React from 'react';
|
||||
// import { ArrayTable as Table } from '@formily/antd';
|
||||
// import { useField, Schema } from '@formily/react';
|
||||
// import { Button } from 'antd';
|
||||
// import cls from 'classnames';
|
||||
// import { isValid, uid } from '@formily/shared';
|
||||
// import { PlusOutlined } from '@ant-design/icons';
|
||||
// import { usePrefixCls } from '@formily/antd/lib/__builtins__';
|
||||
|
||||
export const ArrayTable = Table;
|
||||
import React, { Fragment, useState, useRef, useEffect } from 'react';
|
||||
import { Table, Pagination, Space, Select, Badge, Button } from 'antd';
|
||||
import { PaginationProps } from 'antd/lib/pagination';
|
||||
import { TableProps, ColumnProps } from 'antd/lib/table';
|
||||
import { SelectProps } from 'antd/lib/select';
|
||||
import cls from 'classnames';
|
||||
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
|
||||
import { GeneralField, FieldDisplayTypes, ArrayField } from '@formily/core';
|
||||
import {
|
||||
useForm,
|
||||
useField,
|
||||
observer,
|
||||
useFieldSchema,
|
||||
RecursionField,
|
||||
} from '@formily/react';
|
||||
import { FormPath, isArr, isBool, uid, isValid } from '@formily/shared';
|
||||
import { Schema } from '@formily/json-schema';
|
||||
import { usePrefixCls } from '@formily/antd/lib/__builtins__';
|
||||
import { ArrayBase, ArrayBaseMixins } from '@formily/antd/lib/array-base';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
|
||||
interface ObservableColumnSource {
|
||||
field: GeneralField;
|
||||
columnProps: ColumnProps<any>;
|
||||
schema: Schema;
|
||||
display: FieldDisplayTypes;
|
||||
name: string;
|
||||
}
|
||||
interface IArrayTablePaginationProps extends PaginationProps {
|
||||
dataSource?: any[];
|
||||
paging?: boolean;
|
||||
children?: (
|
||||
dataSource: any[],
|
||||
pagination: React.ReactNode,
|
||||
) => React.ReactElement;
|
||||
}
|
||||
|
||||
interface IStatusSelectProps extends SelectProps<any> {
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
type ComposedArrayTable = React.FC<TableProps<any>> &
|
||||
ArrayBaseMixins & {
|
||||
Column?: React.FC<ColumnProps<any>>;
|
||||
};
|
||||
|
||||
const SortableRow = SortableElement((props: any) => <tr {...props} />);
|
||||
const SortableBody = SortableContainer((props: any) => <tbody {...props} />);
|
||||
|
||||
const isColumnComponent = (schema: Schema) => {
|
||||
return schema['x-component']?.indexOf('Column') > -1;
|
||||
};
|
||||
|
||||
const isOperationsComponent = (schema: Schema) => {
|
||||
return schema['x-component']?.indexOf('Operations') > -1;
|
||||
};
|
||||
|
||||
const isAdditionComponent = (schema: Schema) => {
|
||||
return schema['x-component']?.indexOf('Addition') > -1;
|
||||
};
|
||||
|
||||
const useArrayTableSources = () => {
|
||||
const arrayField = useField();
|
||||
const schema = useFieldSchema();
|
||||
const parseSources = (schema: Schema): ObservableColumnSource[] => {
|
||||
if (
|
||||
isColumnComponent(schema) ||
|
||||
isOperationsComponent(schema) ||
|
||||
isAdditionComponent(schema)
|
||||
) {
|
||||
if (!schema['x-component-props']?.['dataIndex'] && !schema['name'])
|
||||
return [];
|
||||
const name = schema['x-component-props']?.['dataIndex'] || schema['name'];
|
||||
const field = arrayField.query(arrayField.address.concat(name)).take();
|
||||
const columnProps =
|
||||
field?.component?.[1] || schema['x-component-props'] || {};
|
||||
const display = field?.display || schema['x-display'];
|
||||
return [
|
||||
{
|
||||
name,
|
||||
display,
|
||||
field,
|
||||
schema,
|
||||
columnProps,
|
||||
},
|
||||
];
|
||||
} else if (schema.properties) {
|
||||
return schema.reduceProperties((buf, schema) => {
|
||||
return buf.concat(parseSources(schema));
|
||||
}, []);
|
||||
}
|
||||
};
|
||||
|
||||
const parseArrayItems = (schema: Schema['items']) => {
|
||||
const sources: ObservableColumnSource[] = [];
|
||||
const items = isArr(schema) ? schema : [schema];
|
||||
return items.reduce((columns, schema) => {
|
||||
const item = parseSources(schema);
|
||||
if (item) {
|
||||
return columns.concat(item);
|
||||
}
|
||||
return columns;
|
||||
}, sources);
|
||||
};
|
||||
|
||||
if (!schema) throw new Error('can not found schema object');
|
||||
|
||||
return parseArrayItems(schema.items);
|
||||
};
|
||||
|
||||
const useArrayTableColumns = (
|
||||
dataSource: any[],
|
||||
sources: ObservableColumnSource[],
|
||||
): TableProps<any>['columns'] => {
|
||||
return sources.reduce((buf, { name, columnProps, schema, display }, key) => {
|
||||
if (display !== 'visible') return buf;
|
||||
if (!isColumnComponent(schema)) return buf;
|
||||
return buf.concat({
|
||||
...columnProps,
|
||||
key,
|
||||
dataIndex: name,
|
||||
render: (value: any, record: any) => {
|
||||
const index = dataSource.indexOf(record);
|
||||
const children = (
|
||||
<ArrayBase.Item index={index}>
|
||||
<RecursionField schema={schema} name={index} onlyRenderProperties />
|
||||
</ArrayBase.Item>
|
||||
);
|
||||
return children;
|
||||
},
|
||||
});
|
||||
}, []);
|
||||
};
|
||||
|
||||
const useAddition = () => {
|
||||
const schema = useFieldSchema();
|
||||
return schema.reduceProperties((addition, schema, key) => {
|
||||
if (isAdditionComponent(schema)) {
|
||||
return <RecursionField schema={schema} name={key} />;
|
||||
}
|
||||
return addition;
|
||||
}, null);
|
||||
};
|
||||
|
||||
const StatusSelect: React.FC<IStatusSelectProps> = observer((props) => {
|
||||
const form = useForm();
|
||||
const field = useField<ArrayField>();
|
||||
const prefixCls = usePrefixCls('formily-array-table');
|
||||
const errors = form.queryFeedbacks({
|
||||
type: 'error',
|
||||
address: `${field.address}.*`,
|
||||
});
|
||||
const createIndexPattern = (page: number) => {
|
||||
const pattern = `${field.address}.*[${(page - 1) * props.pageSize}:${
|
||||
page * props.pageSize
|
||||
}].*`;
|
||||
return FormPath.parse(pattern);
|
||||
};
|
||||
const options = props.options?.map(({ label, value }) => {
|
||||
const hasError = errors.some(({ address }) => {
|
||||
return createIndexPattern(value).match(address);
|
||||
});
|
||||
return {
|
||||
label: hasError ? <Badge dot>{label}</Badge> : label,
|
||||
value,
|
||||
};
|
||||
});
|
||||
|
||||
const width = String(options?.length).length * 15;
|
||||
|
||||
return (
|
||||
<Select
|
||||
value={props.value}
|
||||
onChange={props.onChange}
|
||||
options={options}
|
||||
virtual
|
||||
style={{
|
||||
width: width < 60 ? 60 : width,
|
||||
}}
|
||||
className={cls(`${prefixCls}-status-select`, {
|
||||
'has-error': errors?.length,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const ArrayTablePagination: React.FC<IArrayTablePaginationProps> = (props) => {
|
||||
const [current, setCurrent] = useState(1);
|
||||
const prefixCls = usePrefixCls('formily-array-table');
|
||||
const pageSize = props.pageSize || 10;
|
||||
const size = props.size || 'default';
|
||||
const dataSource = props.dataSource || [];
|
||||
const startIndex = (current - 1) * pageSize;
|
||||
const endIndex = startIndex + pageSize - 1;
|
||||
const total = dataSource?.length || 0;
|
||||
const totalPage = Math.ceil(total / pageSize);
|
||||
const pages = Array.from(new Array(totalPage)).map((_, index) => {
|
||||
const page = index + 1;
|
||||
return {
|
||||
label: page,
|
||||
value: page,
|
||||
};
|
||||
});
|
||||
const handleChange = (current: number) => {
|
||||
setCurrent(current);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (totalPage > 0 && totalPage < current) {
|
||||
handleChange(totalPage);
|
||||
}
|
||||
}, [totalPage, current]);
|
||||
|
||||
const renderPagination = () => {
|
||||
if (totalPage <= 1) return;
|
||||
return (
|
||||
<div className={`${prefixCls}-pagination`}>
|
||||
<Space>
|
||||
<StatusSelect
|
||||
value={current}
|
||||
pageSize={pageSize}
|
||||
onChange={handleChange}
|
||||
options={pages}
|
||||
notFoundContent={false}
|
||||
/>
|
||||
<Pagination
|
||||
{...props}
|
||||
pageSize={pageSize}
|
||||
current={current}
|
||||
total={dataSource.length}
|
||||
size={size}
|
||||
showSizeChanger={false}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{props.paging
|
||||
? props.children?.(
|
||||
dataSource?.slice(startIndex, endIndex + 1),
|
||||
renderPagination(),
|
||||
)
|
||||
: props.children?.(dataSource, null)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export const ArrayTable: ComposedArrayTable = observer(
|
||||
(props: TableProps<any>) => {
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
const field = useField<ArrayField>();
|
||||
const prefixCls = usePrefixCls('formily-array-table');
|
||||
const dataSource = Array.isArray(field.value) ? field.value.slice() : [];
|
||||
const sources = useArrayTableSources();
|
||||
const columns = useArrayTableColumns(dataSource, sources);
|
||||
const pagination = isBool(props.pagination) ? {} : props.pagination;
|
||||
const addition = useAddition();
|
||||
const defaultRowKey = (record: any) => {
|
||||
return dataSource.indexOf(record);
|
||||
};
|
||||
const addTdStyles = (node: HTMLElement) => {
|
||||
const helper = document.body.querySelector(`.${prefixCls}-sort-helper`);
|
||||
if (helper) {
|
||||
const tds = node.querySelectorAll('td');
|
||||
requestAnimationFrame(() => {
|
||||
helper.querySelectorAll('td').forEach((td, index) => {
|
||||
if (tds[index]) {
|
||||
td.style.width = getComputedStyle(tds[index]).width;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ArrayTablePagination
|
||||
paging={isBool(props.pagination) ? false : true}
|
||||
{...pagination}
|
||||
dataSource={dataSource}
|
||||
>
|
||||
{(dataSource, pager) => (
|
||||
<div ref={ref} className={prefixCls}>
|
||||
<ArrayBase>
|
||||
<Table
|
||||
size="small"
|
||||
bordered
|
||||
rowKey={defaultRowKey}
|
||||
{...props}
|
||||
onChange={() => {}}
|
||||
pagination={false}
|
||||
columns={columns}
|
||||
dataSource={dataSource}
|
||||
components={{
|
||||
body: {
|
||||
wrapper: (props: any) => (
|
||||
<SortableBody
|
||||
useDragHandle
|
||||
lockAxis="y"
|
||||
helperClass={`${prefixCls}-sort-helper`}
|
||||
helperContainer={() => {
|
||||
return ref.current?.querySelector('tbody');
|
||||
}}
|
||||
onSortStart={({ node }) => {
|
||||
addTdStyles(node);
|
||||
}}
|
||||
onSortEnd={({ oldIndex, newIndex }) => {
|
||||
field.move(oldIndex, newIndex);
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
row: (props: any) => {
|
||||
return (
|
||||
<SortableRow
|
||||
index={props['data-row-key'] || 0}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<div style={{ marginTop: 5, marginBottom: 5 }}>{pager}</div>
|
||||
{sources.map((column, key) => {
|
||||
//专门用来承接对Column的状态管理
|
||||
if (!isColumnComponent(column.schema)) return;
|
||||
return React.createElement(RecursionField, {
|
||||
name: column.name,
|
||||
schema: column.schema,
|
||||
onlyRenderSelf: true,
|
||||
key,
|
||||
});
|
||||
})}
|
||||
{addition}
|
||||
</ArrayBase>
|
||||
</div>
|
||||
)}
|
||||
</ArrayTablePagination>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
ArrayTable.displayName = 'ArrayTable';
|
||||
|
||||
ArrayTable.Column = () => {
|
||||
return <Fragment />;
|
||||
};
|
||||
|
||||
ArrayBase.mixin(ArrayTable);
|
||||
|
||||
ArrayTable.Index = (props) => {
|
||||
const index = ArrayBase.useIndex();
|
||||
return <span {...props}>{index + 1}</span>;
|
||||
};
|
||||
|
||||
const getDefaultValue = (defaultValue: any, schema: Schema) => {
|
||||
if (isValid(defaultValue)) return defaultValue;
|
||||
@ -26,7 +383,7 @@ const getDefaultValue = (defaultValue: any, schema: Schema) => {
|
||||
ArrayTable.Addition = (props: any) => {
|
||||
const { randomValue } = props;
|
||||
const self = useField();
|
||||
const array = Table.useArray();
|
||||
const array = ArrayBase.useArray();
|
||||
const prefixCls = usePrefixCls('formily-array-base');
|
||||
if (!array) return null;
|
||||
if (array.field?.pattern !== 'editable') return null;
|
||||
|
@ -37,6 +37,7 @@ const schema = {
|
||||
loadData: '{{ loadData }}',
|
||||
useDataSource: '{{ useDataSource }}',
|
||||
labelInValue: true,
|
||||
maxLevel: 3,
|
||||
fieldNames: {
|
||||
label: 'name',
|
||||
value: 'code',
|
||||
|
@ -32,6 +32,7 @@ export const Cascader = connect(
|
||||
fieldNames = defaultFieldNames,
|
||||
...others
|
||||
} = props;
|
||||
console.log('Cascader', props)
|
||||
// 兼容值为 object[] 的情况
|
||||
const toValue = () => {
|
||||
return toArr(value).map((item) => {
|
||||
@ -73,7 +74,7 @@ export const Cascader = connect(
|
||||
});
|
||||
};
|
||||
// 这里没有用 x-reactions 是因为 readyPretty=true 时不需要
|
||||
if (useDataSource) {
|
||||
if (typeof useDataSource === 'function') {
|
||||
useDataSource({
|
||||
onSuccess: (data) => {
|
||||
field.dataSource = data;
|
||||
|
@ -4,6 +4,7 @@ import { Checkbox as AntdCheckbox, Tag } from 'antd';
|
||||
import { CheckboxProps, CheckboxGroupProps } from 'antd/lib/checkbox';
|
||||
import uniq from 'lodash/uniq';
|
||||
import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
|
||||
import { isValid } from '@formily/shared';
|
||||
|
||||
type ComposedCheckbox = React.FC<CheckboxProps> & {
|
||||
Group?: React.FC<CheckboxGroupProps>;
|
||||
@ -25,6 +26,9 @@ export const Checkbox: ComposedCheckbox = connect(
|
||||
},
|
||||
),
|
||||
mapReadPretty((props) => {
|
||||
if (!isValid(props.value)) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
return props.value ? (
|
||||
<CheckOutlined style={{ color: '#52c41a' }} />
|
||||
) : (
|
||||
@ -41,6 +45,9 @@ Checkbox.Group = connect(
|
||||
dataSource: 'options',
|
||||
}),
|
||||
mapReadPretty((props) => {
|
||||
if (!isValid(props.value)) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
const { options = [] } = props;
|
||||
const field = useField<any>();
|
||||
const dataSource = field.dataSource || [];
|
||||
@ -50,7 +57,9 @@ Checkbox.Group = connect(
|
||||
{dataSource
|
||||
.filter((option) => value.includes(option.value))
|
||||
.map((option, key) => (
|
||||
<Tag key={key} color={option.color}>{option.label}</Tag>
|
||||
<Tag key={key} color={option.color}>
|
||||
{option.label}
|
||||
</Tag>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
@ -1,33 +1,36 @@
|
||||
import React, { createContext, useContext } from 'react'
|
||||
import { isArr, isValid } from '@formily/shared'
|
||||
import { observer, useField } from '@formily/react'
|
||||
import { InputProps } from 'antd/lib/input'
|
||||
import { InputNumberProps } from 'antd/lib/input-number'
|
||||
import { SelectProps } from 'antd/lib/select'
|
||||
import { TreeSelectProps } from 'antd/lib/tree-select'
|
||||
import { CascaderProps } from 'antd/lib/cascader'
|
||||
import React, { createContext, useContext } from 'react';
|
||||
import { isArr, isValid } from '@formily/shared';
|
||||
import { observer, useField } from '@formily/react';
|
||||
import { InputProps } from 'antd/lib/input';
|
||||
import { InputNumberProps } from 'antd/lib/input-number';
|
||||
import { SelectProps } from 'antd/lib/select';
|
||||
import { TreeSelectProps } from 'antd/lib/tree-select';
|
||||
import { CascaderProps } from 'antd/lib/cascader';
|
||||
import {
|
||||
DatePickerProps,
|
||||
RangePickerProps as DateRangePickerProps,
|
||||
} from 'antd/lib/date-picker'
|
||||
import { TimePickerProps, TimeRangePickerProps } from 'antd/lib/time-picker'
|
||||
import { Tag, Space, Popover } from 'antd'
|
||||
import cls from 'classnames'
|
||||
import { formatMomentValue, usePrefixCls } from '@formily/antd/esm/__builtins__'
|
||||
} from 'antd/lib/date-picker';
|
||||
import { TimePickerProps, TimeRangePickerProps } from 'antd/lib/time-picker';
|
||||
import { Tag, Space, Popover } from 'antd';
|
||||
import cls from 'classnames';
|
||||
import {
|
||||
formatMomentValue,
|
||||
usePrefixCls,
|
||||
} from '@formily/antd/esm/__builtins__';
|
||||
import { FullscreenOutlined } from '@ant-design/icons';
|
||||
import moment from 'moment';
|
||||
|
||||
const PlaceholderContext = createContext<string>('N/A')
|
||||
const PlaceholderContext = createContext<string>('N/A');
|
||||
|
||||
const Placeholder = PlaceholderContext.Provider
|
||||
const Placeholder = PlaceholderContext.Provider;
|
||||
|
||||
const usePlaceholder = (value?: any) => {
|
||||
const placeholder = useContext(PlaceholderContext) || 'N/A'
|
||||
return isValid(value) && value !== '' ? value : placeholder
|
||||
}
|
||||
const placeholder = useContext(PlaceholderContext) || 'N/A';
|
||||
return isValid(value) && value !== '' ? value : placeholder;
|
||||
};
|
||||
|
||||
const Input: React.FC<InputProps> = (props) => {
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
return (
|
||||
<Space className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{props.addonBefore}
|
||||
@ -36,14 +39,16 @@ const Input: React.FC<InputProps> = (props) => {
|
||||
{props.suffix}
|
||||
{props.addonAfter}
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const URL: React.FC<InputProps> = (props) => {
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const content = props.value && (
|
||||
<a target={'_blank'} href={props.value as any}>{props.value}</a>
|
||||
)
|
||||
<a target={'_blank'} href={props.value as any}>
|
||||
{props.value}
|
||||
</a>
|
||||
);
|
||||
return (
|
||||
<Space className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{props.addonBefore}
|
||||
@ -52,11 +57,11 @@ const URL: React.FC<InputProps> = (props) => {
|
||||
{props.suffix}
|
||||
{props.addonAfter}
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const InputNumber: React.FC<InputProps & InputNumberProps> = (props) => {
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const value = usePlaceholder(props.value);
|
||||
return (
|
||||
<Space className={cls(prefixCls, props.className)} style={props.style}>
|
||||
@ -66,30 +71,34 @@ const InputNumber: React.FC<InputProps & InputNumberProps> = (props) => {
|
||||
{props.suffix}
|
||||
{props.addonAfter}
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const TextArea: React.FC<any> = (props) => {
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const ellipsis = props.ellipsis === true ? {} : props.ellipsis;
|
||||
const content = props.ellipsis ? (
|
||||
<div>
|
||||
<Popover content={usePlaceholder(props.value)}>
|
||||
<div style={{
|
||||
display: 'inline-block',
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
width: 100,
|
||||
verticalAlign: 'middle',
|
||||
marginRight: 10,
|
||||
...ellipsis,
|
||||
}}>
|
||||
{usePlaceholder(props.text||props.value)}
|
||||
<div
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
width: 100,
|
||||
verticalAlign: 'middle',
|
||||
marginRight: 10,
|
||||
...ellipsis,
|
||||
}}
|
||||
>
|
||||
{usePlaceholder(props.text || props.value)}
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
) : usePlaceholder(props.value)
|
||||
) : (
|
||||
usePlaceholder(props.value)
|
||||
);
|
||||
return (
|
||||
<Space className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{props.addonBefore}
|
||||
@ -98,199 +107,202 @@ const TextArea: React.FC<any> = (props) => {
|
||||
{props.suffix}
|
||||
{props.addonAfter}
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const Select: React.FC<SelectProps<any>> = observer((props) => {
|
||||
const field = useField<Formily.Core.Models.Field>()
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const field = useField<Formily.Core.Models.Field>();
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const dataSource: any[] = field?.dataSource?.length
|
||||
? field.dataSource
|
||||
: props?.options?.length
|
||||
? props.options
|
||||
: []
|
||||
const placeholder = usePlaceholder()
|
||||
: [];
|
||||
const placeholder = usePlaceholder();
|
||||
const getSelected = () => {
|
||||
const value = props.value
|
||||
const value = props.value;
|
||||
if (props.mode === 'multiple' || props.mode === 'tags') {
|
||||
if (props.labelInValue) {
|
||||
return isArr(value) ? value : []
|
||||
return isArr(value) ? value : [];
|
||||
} else {
|
||||
return isArr(value)
|
||||
? value.map((val) => ({ label: val, value: val }))
|
||||
: []
|
||||
: [];
|
||||
}
|
||||
} else {
|
||||
if (props.labelInValue) {
|
||||
return isValid(value) ? [value] : []
|
||||
return isValid(value) ? [value] : [];
|
||||
} else {
|
||||
return isValid(value) ? [{ label: value, value }] : []
|
||||
return isValid(value) ? [{ label: value, value }] : [];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getLabels = () => {
|
||||
const selected = getSelected()
|
||||
if (!selected.length) return <Tag>{placeholder}</Tag>
|
||||
const selected = getSelected();
|
||||
if (!selected.length) return <Tag>{placeholder}</Tag>;
|
||||
return selected.map(({ value, label }, key) => {
|
||||
const text =
|
||||
dataSource?.find((item) => item.value == value)?.label || label
|
||||
return <Tag key={key}>{text || placeholder}</Tag>
|
||||
})
|
||||
}
|
||||
dataSource?.find((item) => item.value == value)?.label || label;
|
||||
return <Tag key={key}>{text || placeholder}</Tag>;
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{getLabels()}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const ObjectSelect: React.FC<SelectProps<any>> = observer((props) => {
|
||||
const field = useField<Formily.Core.Models.Field>()
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const field = useField<Formily.Core.Models.Field>();
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const dataSource: any[] = field?.dataSource?.length
|
||||
? field.dataSource
|
||||
: props?.options?.length
|
||||
? props.options
|
||||
: []
|
||||
const placeholder = usePlaceholder()
|
||||
: [];
|
||||
const placeholder = usePlaceholder();
|
||||
const getSelected = () => {
|
||||
const value = props.value
|
||||
const value = props.value;
|
||||
if (props.mode === 'multiple' || props.mode === 'tags') {
|
||||
if (props.labelInValue) {
|
||||
return isArr(value) ? value : []
|
||||
return isArr(value) ? value : [];
|
||||
} else {
|
||||
return isArr(value)
|
||||
? value.map((val) => ({ label: val, value: val }))
|
||||
: []
|
||||
: [];
|
||||
}
|
||||
} else {
|
||||
if (props.labelInValue) {
|
||||
return isValid(value) ? [value] : []
|
||||
return isValid(value) ? [value] : [];
|
||||
} else {
|
||||
return isValid(value) ? [{ label: value, value }] : []
|
||||
return isValid(value) ? [{ label: value, value }] : [];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getLabels = () => {
|
||||
const selected = getSelected()
|
||||
if (!selected.length) return <Tag>{placeholder}</Tag>
|
||||
const selected = getSelected();
|
||||
if (!selected.length) return <Tag>{placeholder}</Tag>;
|
||||
return selected.map(({ value, label }, key) => {
|
||||
const text =
|
||||
dataSource?.find((item) => item.value == value)?.label || label
|
||||
return <Tag key={key}>{text || placeholder}</Tag>
|
||||
})
|
||||
}
|
||||
dataSource?.find((item) => item.value == value)?.label || label;
|
||||
return <Tag key={key}>{text || placeholder}</Tag>;
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{getLabels()}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const TreeSelect: React.FC<TreeSelectProps<any>> = observer((props) => {
|
||||
const field = useField<Formily.Core.Models.Field>()
|
||||
const placeholder = usePlaceholder()
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const field = useField<Formily.Core.Models.Field>();
|
||||
const placeholder = usePlaceholder();
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const dataSource = field?.dataSource?.length
|
||||
? field.dataSource
|
||||
: props?.options?.length
|
||||
? props.options
|
||||
: []
|
||||
: [];
|
||||
const getSelected = () => {
|
||||
const value = props.value
|
||||
const value = props.value;
|
||||
if (props.multiple) {
|
||||
if (props.labelInValue) {
|
||||
return isArr(value) ? value : []
|
||||
return isArr(value) ? value : [];
|
||||
} else {
|
||||
return isArr(value)
|
||||
? value.map((val) => ({ label: val, value: val }))
|
||||
: []
|
||||
: [];
|
||||
}
|
||||
} else {
|
||||
if (props.labelInValue) {
|
||||
return value ? [value] : []
|
||||
return value ? [value] : [];
|
||||
} else {
|
||||
return value ? [{ label: value, value }] : []
|
||||
return value ? [{ label: value, value }] : [];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const findLabel = (value: any, dataSource: any[]) => {
|
||||
for (let i = 0; i < dataSource?.length; i++) {
|
||||
const item = dataSource[i]
|
||||
const item = dataSource[i];
|
||||
if (item?.value === value) {
|
||||
return item?.label
|
||||
return item?.label;
|
||||
} else {
|
||||
const childLabel = findLabel(value, item?.children)
|
||||
if (childLabel) return childLabel
|
||||
const childLabel = findLabel(value, item?.children);
|
||||
if (childLabel) return childLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getLabels = () => {
|
||||
const selected = getSelected()
|
||||
if (!selected?.length) return <Tag>{placeholder}</Tag>
|
||||
const selected = getSelected();
|
||||
if (!selected?.length) return <Tag>{placeholder}</Tag>;
|
||||
return selected.map(({ value, label }, key) => {
|
||||
return (
|
||||
<Tag key={key}>
|
||||
{findLabel(value, dataSource) || label || placeholder}
|
||||
</Tag>
|
||||
)
|
||||
})
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{getLabels()}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const Cascader: React.FC<CascaderProps> = observer((props) => {
|
||||
const field = useField<Formily.Core.Models.Field>()
|
||||
const placeholder = usePlaceholder()
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const field = useField<Formily.Core.Models.Field>();
|
||||
const placeholder = usePlaceholder();
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const dataSource: any[] = field?.dataSource?.length
|
||||
? field.dataSource
|
||||
: props?.options?.length
|
||||
? props.options
|
||||
: []
|
||||
: [];
|
||||
const getSelected = () => {
|
||||
return isArr(props.value) ? props.value : []
|
||||
}
|
||||
return isArr(props.value) ? props.value : [];
|
||||
};
|
||||
const findLabel = (value: any, dataSource: any[]) => {
|
||||
for (let i = 0; i < dataSource?.length; i++) {
|
||||
const item = dataSource[i]
|
||||
const item = dataSource[i];
|
||||
if (item?.value === value) {
|
||||
return item?.label
|
||||
return item?.label;
|
||||
} else {
|
||||
const childLabel = findLabel(value, item?.children)
|
||||
if (childLabel) return childLabel
|
||||
const childLabel = findLabel(value, item?.children);
|
||||
if (childLabel) return childLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const getLabels = () => {
|
||||
const selected = getSelected()
|
||||
const selected = getSelected();
|
||||
if (!selected?.length) {
|
||||
return placeholder
|
||||
return placeholder;
|
||||
}
|
||||
return selected
|
||||
.map((value) => {
|
||||
return findLabel(value, dataSource) || placeholder
|
||||
return findLabel(value, dataSource) || placeholder;
|
||||
})
|
||||
.join('/')
|
||||
}
|
||||
.join('/');
|
||||
};
|
||||
return (
|
||||
<div className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{getLabels()}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const DatePicker: React.FC<DatePickerProps> = (props: any) => {
|
||||
const placeholder = usePlaceholder()
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
if (!props.value) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
const placeholder = usePlaceholder();
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const getDefaultFormat = () => {
|
||||
const { dateFormat, showTime, timeFormat } = props;
|
||||
let format = dateFormat;
|
||||
@ -298,56 +310,60 @@ const DatePicker: React.FC<DatePickerProps> = (props: any) => {
|
||||
format += ` ${timeFormat}`;
|
||||
}
|
||||
return format || props.format;
|
||||
}
|
||||
};
|
||||
const getLabels = () => {
|
||||
const d = moment(props.value);
|
||||
const labels = formatMomentValue(d.isValid() ? d : null, getDefaultFormat(), placeholder)
|
||||
return isArr(labels) ? labels.join('~') : labels
|
||||
}
|
||||
return <div className={cls(prefixCls, props.className)}>{getLabels()}</div>
|
||||
}
|
||||
const labels = formatMomentValue(
|
||||
d.isValid() ? d : null,
|
||||
getDefaultFormat(),
|
||||
placeholder,
|
||||
);
|
||||
return isArr(labels) ? labels.join('~') : labels;
|
||||
};
|
||||
return <div className={cls(prefixCls, props.className)}>{getLabels()}</div>;
|
||||
};
|
||||
|
||||
const DateRangePicker: React.FC<DateRangePickerProps> = (props) => {
|
||||
const placeholder = usePlaceholder()
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const placeholder = usePlaceholder();
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const getLabels = () => {
|
||||
const labels = formatMomentValue(props.value, props.format, placeholder)
|
||||
return isArr(labels) ? labels.join('~') : labels
|
||||
}
|
||||
const labels = formatMomentValue(props.value, props.format, placeholder);
|
||||
return isArr(labels) ? labels.join('~') : labels;
|
||||
};
|
||||
return (
|
||||
<div className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{getLabels()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const TimePicker: React.FC<TimePickerProps> = (props) => {
|
||||
const placeholder = usePlaceholder()
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const placeholder = usePlaceholder();
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const getLabels = () => {
|
||||
const labels = formatMomentValue(props.value, props.format, placeholder)
|
||||
return isArr(labels) ? labels.join('~') : labels
|
||||
}
|
||||
const labels = formatMomentValue(props.value, props.format, placeholder);
|
||||
return isArr(labels) ? labels.join('~') : labels;
|
||||
};
|
||||
return (
|
||||
<div className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{getLabels()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const TimeRangePicker: React.FC<TimeRangePickerProps> = (props) => {
|
||||
const placeholder = usePlaceholder()
|
||||
const prefixCls = usePrefixCls('description-text', props)
|
||||
const placeholder = usePlaceholder();
|
||||
const prefixCls = usePrefixCls('description-text', props);
|
||||
const getLabels = () => {
|
||||
const labels = formatMomentValue(props.value, props.format, placeholder)
|
||||
return isArr(labels) ? labels.join('~') : labels
|
||||
}
|
||||
const labels = formatMomentValue(props.value, props.format, placeholder);
|
||||
return isArr(labels) ? labels.join('~') : labels;
|
||||
};
|
||||
return (
|
||||
<div className={cls(prefixCls, props.className)} style={props.style}>
|
||||
{getLabels()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const Display = {
|
||||
Input,
|
||||
@ -364,6 +380,6 @@ export const Display = {
|
||||
Placeholder,
|
||||
InputNumber,
|
||||
usePlaceholder,
|
||||
}
|
||||
};
|
||||
|
||||
export default Display;
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
hasIcon,
|
||||
IconPicker as Icon,
|
||||
} from '../../components/icon-picker';
|
||||
import { isValid } from '@formily/shared';
|
||||
|
||||
function IconField(props: any) {
|
||||
const { value, onChange } = props;
|
||||
@ -72,6 +73,9 @@ export const IconPicker = connect(
|
||||
};
|
||||
}),
|
||||
mapReadPretty((props) => {
|
||||
if (!isValid(props.value)) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
return <Icon type={props.value} />;
|
||||
}),
|
||||
);
|
||||
|
@ -34,8 +34,8 @@ export const InputNumber: any = connect(
|
||||
},
|
||||
mapReadPretty((props: any) => {
|
||||
const { step, value, addonBefore, addonAfter } = props;
|
||||
if (!isValid(value)) {
|
||||
return null;
|
||||
if (!isValid(props.value)) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
const precision = Math.max(
|
||||
getNumberPrecision(String(value)),
|
||||
@ -55,8 +55,8 @@ InputNumber.Percent = connect(
|
||||
AntdNumber,
|
||||
mapReadPretty((props: any) => {
|
||||
const { step, value } = props;
|
||||
if (!isValid(value)) {
|
||||
return null;
|
||||
if (!isValid(props.value)) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
return toFixed(
|
||||
String(value),
|
||||
|
@ -3,63 +3,68 @@ import { connect, mapReadPretty } from '@formily/react';
|
||||
import { Input } from 'antd';
|
||||
import { PasswordProps } from 'antd/lib/input';
|
||||
import { PasswordStrength } from './PasswordStrength';
|
||||
import { isValid } from '@formily/shared';
|
||||
|
||||
export interface IPasswordProps extends PasswordProps {
|
||||
checkStrength: boolean;
|
||||
}
|
||||
|
||||
export const Password = connect((props: IPasswordProps) => {
|
||||
const { value, className, checkStrength, ...others } = props;
|
||||
const blockStyle: React.CSSProperties = {
|
||||
position: 'absolute',
|
||||
zIndex: 1,
|
||||
height: 8,
|
||||
top: 0,
|
||||
background: '#fff',
|
||||
width: 1,
|
||||
transform: 'translate(-50%, 0)',
|
||||
};
|
||||
return (
|
||||
<span className={className}>
|
||||
<Input.Password {...others} value={value} />
|
||||
{checkStrength && (
|
||||
<PasswordStrength value={String(value)}>
|
||||
{(score) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
background: '#e0e0e0',
|
||||
marginBottom: 3,
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<div style={{ ...blockStyle, left: '20%' }} />
|
||||
<div style={{ ...blockStyle, left: '40%' }} />
|
||||
<div style={{ ...blockStyle, left: '60%' }} />
|
||||
<div style={{ ...blockStyle, left: '80%' }} />
|
||||
export const Password = connect(
|
||||
(props: IPasswordProps) => {
|
||||
const { value, className, checkStrength, ...others } = props;
|
||||
const blockStyle: React.CSSProperties = {
|
||||
position: 'absolute',
|
||||
zIndex: 1,
|
||||
height: 8,
|
||||
top: 0,
|
||||
background: '#fff',
|
||||
width: 1,
|
||||
transform: 'translate(-50%, 0)',
|
||||
};
|
||||
return (
|
||||
<span className={className}>
|
||||
<Input.Password {...others} value={value} />
|
||||
{checkStrength && (
|
||||
<PasswordStrength value={String(value)}>
|
||||
{(score) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
background: '#e0e0e0',
|
||||
marginBottom: 3,
|
||||
position: 'relative',
|
||||
backgroundImage:
|
||||
'-webkit-linear-gradient(left, #ff5500, #ff9300)',
|
||||
transition: 'all 0.35s ease-in-out',
|
||||
height: 8,
|
||||
width: '100%',
|
||||
marginTop: 5,
|
||||
clipPath: `polygon(0 0,${score}% 0,${score}% 100%,0 100%)`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</PasswordStrength>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}, mapReadPretty(() => {
|
||||
return (
|
||||
<div>********</div>
|
||||
)
|
||||
}));
|
||||
>
|
||||
<div style={{ ...blockStyle, left: '20%' }} />
|
||||
<div style={{ ...blockStyle, left: '40%' }} />
|
||||
<div style={{ ...blockStyle, left: '60%' }} />
|
||||
<div style={{ ...blockStyle, left: '80%' }} />
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
backgroundImage:
|
||||
'-webkit-linear-gradient(left, #ff5500, #ff9300)',
|
||||
transition: 'all 0.35s ease-in-out',
|
||||
height: 8,
|
||||
width: '100%',
|
||||
marginTop: 5,
|
||||
clipPath: `polygon(0 0,${score}% 0,${score}% 100%,0 100%)`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</PasswordStrength>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
mapReadPretty((props) => {
|
||||
if (!isValid(props.value)) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
return <div>********</div>;
|
||||
}),
|
||||
);
|
||||
|
||||
export default Password;
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { connect, mapProps, mapReadPretty, SchemaOptionsContext, useField } from '@formily/react'
|
||||
import { Radio as AntdRadio, Tag } from 'antd'
|
||||
import { RadioProps, RadioGroupProps } from 'antd/lib/radio'
|
||||
import { isValid } from '@formily/shared';
|
||||
|
||||
type ComposedRadio = React.FC<RadioProps> & {
|
||||
Group?: React.FC<RadioGroupProps>
|
||||
@ -24,6 +25,9 @@ Radio.Group = connect(
|
||||
dataSource: 'options',
|
||||
}),
|
||||
mapReadPretty((props) => {
|
||||
if (!isValid(props.value)) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
const { options = [], value } = props;
|
||||
const field = useField<any>();
|
||||
const dataSource = field.dataSource || [];
|
||||
|
@ -18,7 +18,7 @@ import { useDesignable } from '../';
|
||||
import { createContext } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { isField } from '@formily/core';
|
||||
import { Field, isArrayField, isField } from '@formily/core';
|
||||
|
||||
export const Select: any = connect(
|
||||
(props) => {
|
||||
@ -65,7 +65,15 @@ export const Select: any = connect(
|
||||
},
|
||||
),
|
||||
mapReadPretty((props) => {
|
||||
// console.log('mapReadPretty', props.value)
|
||||
// return <div>N/A</div>;
|
||||
if (!isValid(props.value)) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
const field = useField<any>();
|
||||
if (isArrayField(field) && field?.value?.length === 0) {
|
||||
return <div>N/A</div>;
|
||||
}
|
||||
const dataSource = field.dataSource || [];
|
||||
console.log('field.value', field.value, dataSource);
|
||||
const values = toArr(field.value);
|
||||
|
@ -2244,7 +2244,7 @@ Table.useActionLogDetailsResource = ({ onSuccess }) => {
|
||||
});
|
||||
const service = useRequest(
|
||||
(params?: any) => {
|
||||
return resource.get({ ...params, appends: 'changes' });
|
||||
return resource.get({ ...params, appends: ['changes', 'user', 'collection'] });
|
||||
},
|
||||
{
|
||||
formatResult: (result) => result?.data,
|
||||
|
Loading…
Reference in New Issue
Block a user