style: code formatting
This commit is contained in:
parent
5e9959b987
commit
ce4a22fbb9
@ -187,10 +187,12 @@ describe('list', () => {
|
|||||||
const User = db.getModel('users');
|
const User = db.getModel('users');
|
||||||
const expected = await User.findOne({
|
const expected = await User.findOne({
|
||||||
where: {
|
where: {
|
||||||
nicknames: { [Op.or]: [
|
nicknames: {
|
||||||
|
[Op.or]: [
|
||||||
{ [Op.contains]: 'aaa' },
|
{ [Op.contains]: 'aaa' },
|
||||||
{ [Op.contains]: 'aa' }
|
{ [Op.contains]: 'aa' }
|
||||||
] }
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const response = await agent.get('/users?filter[nicknames.$anyOf]=aaa,aa');
|
const response = await agent.get('/users?filter[nicknames.$anyOf]=aaa,aa');
|
||||||
@ -459,7 +461,8 @@ describe('list', () => {
|
|||||||
const response = await agent.get('/posts?fields[only]=title&fields[appends]=user.name&filter[title]=title0');
|
const response = await agent.get('/posts?fields[only]=title&fields[appends]=user.name&filter[title]=title0');
|
||||||
expect(response.body.rows[0].user.name).toEqual('a');
|
expect(response.body.rows[0].user.name).toEqual('a');
|
||||||
expect(response.body.rows).toEqual([{
|
expect(response.body.rows).toEqual([{
|
||||||
title: 'title0', user: { id: 1, nicknames: ['aa', 'aaa'], name: 'a', ...timestampsStrings } }]);
|
title: 'title0', user: { id: 1, nicknames: ['aa', 'aaa'], name: 'a', ...timestampsStrings }
|
||||||
|
}]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -26,10 +26,20 @@ interface Resource {
|
|||||||
|
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
resource(name: string): Resource {
|
resource(name: string): Resource {
|
||||||
const proxy: any = new Proxy({}, {
|
const proxy: any = new Proxy(
|
||||||
|
{},
|
||||||
|
{
|
||||||
get(target, method, receiver) {
|
get(target, method, receiver) {
|
||||||
return (params: ActionParams = {}) => {
|
return (params: ActionParams = {}) => {
|
||||||
let { associatedKey, resourceKey, filter, sorter, sort = [], values, ...restParams } = params;
|
let {
|
||||||
|
associatedKey,
|
||||||
|
resourceKey,
|
||||||
|
filter,
|
||||||
|
sorter,
|
||||||
|
sort = [],
|
||||||
|
values,
|
||||||
|
...restParams
|
||||||
|
} = params;
|
||||||
let url = `/${name}`;
|
let url = `/${name}`;
|
||||||
sort = sort || [];
|
sort = sort || [];
|
||||||
let options: any = {
|
let options: any = {
|
||||||
@ -72,8 +82,9 @@ class ApiClient {
|
|||||||
console.log({ url, params });
|
console.log({ url, params });
|
||||||
return request(url, options);
|
return request(url, options);
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ configResponsive({
|
|||||||
export const request: RequestConfig = {
|
export const request: RequestConfig = {
|
||||||
prefix: process.env.API,
|
prefix: process.env.API,
|
||||||
errorConfig: {
|
errorConfig: {
|
||||||
adaptor: (resData) => {
|
adaptor: resData => {
|
||||||
return {
|
return {
|
||||||
...resData,
|
...resData,
|
||||||
success: true,
|
success: true,
|
||||||
@ -28,23 +28,21 @@ export const request: RequestConfig = {
|
|||||||
headers['Authorization'] = `Bearer ${token}`;
|
headers['Authorization'] = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
await next();
|
await next();
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const pathnames = [
|
const pathnames = ['/login', '/register', '/lostpassword', '/resetpassword'];
|
||||||
'/login',
|
|
||||||
'/register',
|
|
||||||
'/lostpassword',
|
|
||||||
'/resetpassword',
|
|
||||||
];
|
|
||||||
|
|
||||||
export async function getInitialState() {
|
export async function getInitialState() {
|
||||||
const { pathname, search } = location;
|
const { pathname, search } = location;
|
||||||
console.log(location);
|
console.log(location);
|
||||||
const { data: systemSettings = {} } = await umiRequest('/system_settings:get?fields[appends]=logo,logo.storage', {
|
const { data: systemSettings = {} } = await umiRequest(
|
||||||
|
'/system_settings:get?fields[appends]=logo,logo.storage',
|
||||||
|
{
|
||||||
method: 'get',
|
method: 'get',
|
||||||
});
|
},
|
||||||
|
);
|
||||||
let redirect = `?redirect=${pathname}${search}`;
|
let redirect = `?redirect=${pathname}${search}`;
|
||||||
|
|
||||||
if (!pathnames.includes(pathname)) {
|
if (!pathnames.includes(pathname)) {
|
||||||
@ -66,7 +64,7 @@ export async function getInitialState() {
|
|||||||
currentUser: data,
|
currentUser: data,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error);
|
||||||
history.push('/login' + redirect);
|
history.push('/login' + redirect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,17 @@ export function Create(props) {
|
|||||||
viewName={viewName}
|
viewName={viewName}
|
||||||
{...params}
|
{...params}
|
||||||
/>
|
/>
|
||||||
<Button icon={<PlusOutlined />} type={'primary'} onClick={() => {
|
<Button
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
type={'primary'}
|
||||||
|
onClick={() => {
|
||||||
drawerRef.current.setVisible(true);
|
drawerRef.current.setVisible(true);
|
||||||
}}>{title}</Button>
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Create;
|
export default Create;
|
||||||
|
@ -10,14 +10,19 @@ export function Destroy(props) {
|
|||||||
const drawerRef = useRef<any>();
|
const drawerRef = useRef<any>();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Popconfirm title="确认删除吗?" onConfirm={() => {
|
<Popconfirm
|
||||||
|
title="确认删除吗?"
|
||||||
|
onConfirm={() => {
|
||||||
console.log('destroy', onTrigger);
|
console.log('destroy', onTrigger);
|
||||||
onTrigger && onTrigger();
|
onTrigger && onTrigger();
|
||||||
}}>
|
}}
|
||||||
<Button icon={<DeleteOutlined />} type={'ghost'} danger>{title}</Button>
|
>
|
||||||
|
<Button icon={<DeleteOutlined />} type={'ghost'} danger>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Destroy;
|
export default Destroy;
|
||||||
|
@ -8,7 +8,13 @@ export function Filter(props) {
|
|||||||
const drawerRef = useRef<any>();
|
const drawerRef = useRef<any>();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { title, viewName, collection_name } = props.schema;
|
const { title, viewName, collection_name } = props.schema;
|
||||||
const { filterCount, activeTab = {}, item = {}, associatedName, associatedKey } = props;
|
const {
|
||||||
|
filterCount,
|
||||||
|
activeTab = {},
|
||||||
|
item = {},
|
||||||
|
associatedName,
|
||||||
|
associatedKey,
|
||||||
|
} = props;
|
||||||
const { associationField } = activeTab;
|
const { associationField } = activeTab;
|
||||||
|
|
||||||
const params = {};
|
const params = {};
|
||||||
@ -30,18 +36,20 @@ export function Filter(props) {
|
|||||||
trigger="click"
|
trigger="click"
|
||||||
visible={visible}
|
visible={visible}
|
||||||
placement={'bottomLeft'}
|
placement={'bottomLeft'}
|
||||||
onVisibleChange={(visible) => {
|
onVisibleChange={visible => {
|
||||||
setVisible(visible);
|
setVisible(visible);
|
||||||
}}
|
}}
|
||||||
className={'filters-popover'}
|
className={'filters-popover'}
|
||||||
style={{
|
style={{}}
|
||||||
}}
|
|
||||||
overlayStyle={{
|
overlayStyle={{
|
||||||
minWidth: 500
|
minWidth: 500,
|
||||||
}}
|
}}
|
||||||
content={(
|
content={
|
||||||
<>
|
<>
|
||||||
<div className={'popover-button-mask'} onClick={() => setVisible(false)}></div>
|
<div
|
||||||
|
className={'popover-button-mask'}
|
||||||
|
onClick={() => setVisible(false)}
|
||||||
|
></div>
|
||||||
<ViewFactory
|
<ViewFactory
|
||||||
{...props}
|
{...props}
|
||||||
setVisible={setVisible}
|
setVisible={setVisible}
|
||||||
@ -49,14 +57,19 @@ export function Filter(props) {
|
|||||||
{...params}
|
{...params}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
}
|
||||||
>
|
>
|
||||||
<Button icon={<FilterOutlined />} onClick={() => {
|
<Button
|
||||||
|
icon={<FilterOutlined />}
|
||||||
|
onClick={() => {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}}>{filterCount ? `${filterCount} 个${title}项` : title}</Button>
|
}}
|
||||||
|
>
|
||||||
|
{filterCount ? `${filterCount} 个${title}项` : title}
|
||||||
|
</Button>
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Filter;
|
export default Filter;
|
||||||
|
@ -29,12 +29,18 @@ export function Update(props) {
|
|||||||
mode={'update'}
|
mode={'update'}
|
||||||
{...params}
|
{...params}
|
||||||
/>
|
/>
|
||||||
<Button icon={<EditOutlined />} type={'primary'} onClick={() => {
|
<Button
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
type={'primary'}
|
||||||
|
onClick={() => {
|
||||||
drawerRef.current.setVisible(true);
|
drawerRef.current.setVisible(true);
|
||||||
drawerRef.current.getData(item.itemId || resourceKey);
|
drawerRef.current.getData(item.itemId || resourceKey);
|
||||||
}}>{title}</Button>
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Update;
|
export default Update;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Create from './Create';
|
import Create from './Create';
|
||||||
import Update from './Update';
|
import Update from './Update';
|
||||||
@ -33,7 +32,8 @@ export function Action(props) {
|
|||||||
export function Actions(props) {
|
export function Actions(props) {
|
||||||
const { onTrigger = {}, style, schema, actions = [], ...restProps } = props;
|
const { onTrigger = {}, style, schema, actions = [], ...restProps } = props;
|
||||||
console.log(onTrigger);
|
console.log(onTrigger);
|
||||||
return actions.length > 0 && (
|
return (
|
||||||
|
actions.length > 0 && (
|
||||||
<div className={'action-buttons'} style={style}>
|
<div className={'action-buttons'} style={style}>
|
||||||
{actions.map(action => (
|
{actions.map(action => (
|
||||||
<div className={`${action.name}-action-button action-button`}>
|
<div className={`${action.name}-action-button action-button`}>
|
||||||
@ -46,6 +46,7 @@ export function Actions(props) {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react';
|
||||||
import {
|
import {
|
||||||
ISchemaFieldComponentProps,
|
ISchemaFieldComponentProps,
|
||||||
SchemaField
|
SchemaField,
|
||||||
} from '@formily/react-schema-renderer'
|
} from '@formily/react-schema-renderer';
|
||||||
import { toArr, isFn, FormPath } from '@formily/shared'
|
import { toArr, isFn, FormPath } from '@formily/shared';
|
||||||
import { ArrayList } from '@formily/react-shared-components'
|
import { ArrayList } from '@formily/react-shared-components';
|
||||||
import { CircleButton } from '../circle-button'
|
import { CircleButton } from '../circle-button';
|
||||||
import { TextButton } from '../text-button'
|
import { TextButton } from '../text-button';
|
||||||
import { Card } from 'antd'
|
import { Card } from 'antd';
|
||||||
import {
|
import {
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
DownOutlined,
|
DownOutlined,
|
||||||
UpOutlined
|
UpOutlined,
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons';
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
|
|
||||||
const ArrayComponents = {
|
const ArrayComponents = {
|
||||||
CircleButton,
|
CircleButton,
|
||||||
@ -22,12 +22,12 @@ const ArrayComponents = {
|
|||||||
AdditionIcon: () => <PlusOutlined />,
|
AdditionIcon: () => <PlusOutlined />,
|
||||||
RemoveIcon: () => <DeleteOutlined />,
|
RemoveIcon: () => <DeleteOutlined />,
|
||||||
MoveDownIcon: () => <DownOutlined />,
|
MoveDownIcon: () => <DownOutlined />,
|
||||||
MoveUpIcon: () => <UpOutlined />
|
MoveUpIcon: () => <UpOutlined />,
|
||||||
}
|
};
|
||||||
|
|
||||||
export const ArrayCards: any = styled(
|
export const ArrayCards: any = styled(
|
||||||
(props: ISchemaFieldComponentProps & { className: string }) => {
|
(props: ISchemaFieldComponentProps & { className: string }) => {
|
||||||
const { value, schema, className, editable, path, mutators } = props
|
const { value, schema, className, editable, path, mutators } = props;
|
||||||
const {
|
const {
|
||||||
renderAddition,
|
renderAddition,
|
||||||
renderRemove,
|
renderRemove,
|
||||||
@ -36,17 +36,17 @@ export const ArrayCards: any = styled(
|
|||||||
renderEmpty,
|
renderEmpty,
|
||||||
renderExtraOperations,
|
renderExtraOperations,
|
||||||
...componentProps
|
...componentProps
|
||||||
} = schema.getExtendsComponentProps() || {}
|
} = schema.getExtendsComponentProps() || {};
|
||||||
|
|
||||||
const schemaItems = Array.isArray(schema.items)
|
const schemaItems = Array.isArray(schema.items)
|
||||||
? schema.items[schema.items.length - 1]
|
? schema.items[schema.items.length - 1]
|
||||||
: schema.items
|
: schema.items;
|
||||||
|
|
||||||
const onAdd = () => {
|
const onAdd = () => {
|
||||||
if (schemaItems) {
|
if (schemaItems) {
|
||||||
mutators.push(schemaItems.getEmptyValue())
|
mutators.push(schemaItems.getEmptyValue());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<ArrayList
|
<ArrayList
|
||||||
@ -60,7 +60,7 @@ export const ArrayCards: any = styled(
|
|||||||
renderRemove,
|
renderRemove,
|
||||||
renderMoveDown,
|
renderMoveDown,
|
||||||
renderMoveUp,
|
renderMoveUp,
|
||||||
renderEmpty
|
renderEmpty,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{toArr(value).map((item, index) => {
|
{toArr(value).map((item, index) => {
|
||||||
@ -72,7 +72,8 @@ export const ArrayCards: any = styled(
|
|||||||
key={index}
|
key={index}
|
||||||
title={
|
title={
|
||||||
<span>
|
<span>
|
||||||
{index + 1}<span>.</span> {componentProps.title || schema.title}
|
{index + 1}
|
||||||
|
<span>.</span> {componentProps.title || schema.title}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
extra={
|
extra={
|
||||||
@ -102,7 +103,7 @@ export const ArrayCards: any = styled(
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
<ArrayList.Empty>
|
<ArrayList.Empty>
|
||||||
{({ children, allowAddition }) => {
|
{({ children, allowAddition }) => {
|
||||||
@ -110,12 +111,14 @@ export const ArrayCards: any = styled(
|
|||||||
<Card
|
<Card
|
||||||
{...componentProps}
|
{...componentProps}
|
||||||
size="small"
|
size="small"
|
||||||
className={`card-list-item card-list-empty ${allowAddition ? 'add-pointer' : ''}`}
|
className={`card-list-item card-list-empty ${
|
||||||
|
allowAddition ? 'add-pointer' : ''
|
||||||
|
}`}
|
||||||
onClick={allowAddition ? onAdd : undefined}
|
onClick={allowAddition ? onAdd : undefined}
|
||||||
>
|
>
|
||||||
<div className="empty-wrapper">{children}</div>
|
<div className="empty-wrapper">{children}</div>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
);
|
||||||
}}
|
}}
|
||||||
</ArrayList.Empty>
|
</ArrayList.Empty>
|
||||||
<ArrayList.Addition>
|
<ArrayList.Addition>
|
||||||
@ -125,14 +128,14 @@ export const ArrayCards: any = styled(
|
|||||||
<div className="array-cards-addition" onClick={onAdd}>
|
<div className="array-cards-addition" onClick={onAdd}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
</ArrayList.Addition>
|
</ArrayList.Addition>
|
||||||
</ArrayList>
|
</ArrayList>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
)<ISchemaFieldComponentProps>`
|
)<ISchemaFieldComponentProps>`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.ant-card {
|
.ant-card {
|
||||||
@ -190,8 +193,8 @@ export const ArrayCards: any = styled(
|
|||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
ArrayCards.isFieldComponent = true
|
ArrayCards.isFieldComponent = true;
|
||||||
|
|
||||||
export default ArrayCards
|
export default ArrayCards;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/card/style/index'
|
import 'antd/lib/card/style/index';
|
||||||
|
@ -1,33 +1,37 @@
|
|||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react';
|
||||||
import {
|
import {
|
||||||
ISchemaFieldComponentProps,
|
ISchemaFieldComponentProps,
|
||||||
SchemaField,
|
SchemaField,
|
||||||
Schema,
|
Schema,
|
||||||
complieExpression,
|
complieExpression,
|
||||||
FormExpressionScopeContext
|
FormExpressionScopeContext,
|
||||||
} from '@formily/react-schema-renderer'
|
} from '@formily/react-schema-renderer';
|
||||||
import { toArr, isFn, isArr, FormPath } from '@formily/shared'
|
import { toArr, isFn, isArr, FormPath } from '@formily/shared';
|
||||||
import { ArrayList, DragListView } from '@formily/react-shared-components'
|
import { ArrayList, DragListView } from '@formily/react-shared-components';
|
||||||
import { CircleButton } from '../circle-button'
|
import { CircleButton } from '../circle-button';
|
||||||
import { TextButton } from '../text-button'
|
import { TextButton } from '../text-button';
|
||||||
import { Table, Form, Button } from 'antd'
|
import { Table, Form, Button } from 'antd';
|
||||||
import { FormItemShallowProvider } from '@formily/antd'
|
import { FormItemShallowProvider } from '@formily/antd';
|
||||||
import {
|
import {
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
DownOutlined,
|
DownOutlined,
|
||||||
UpOutlined
|
UpOutlined,
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons';
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
|
|
||||||
const ArrayComponents = {
|
const ArrayComponents = {
|
||||||
CircleButton,
|
CircleButton,
|
||||||
TextButton,
|
TextButton,
|
||||||
AdditionIcon: () => <><PlusOutlined/> 新增</>,
|
AdditionIcon: () => (
|
||||||
|
<>
|
||||||
|
<PlusOutlined /> 新增
|
||||||
|
</>
|
||||||
|
),
|
||||||
RemoveIcon: () => <DeleteOutlined />,
|
RemoveIcon: () => <DeleteOutlined />,
|
||||||
MoveDownIcon: () => <DownOutlined />,
|
MoveDownIcon: () => <DownOutlined />,
|
||||||
MoveUpIcon: () => <UpOutlined />
|
MoveUpIcon: () => <UpOutlined />,
|
||||||
}
|
};
|
||||||
|
|
||||||
const DragHandler = styled.span`
|
const DragHandler = styled.span`
|
||||||
width: 7px;
|
width: 7px;
|
||||||
@ -38,12 +42,12 @@ const DragHandler = styled.span`
|
|||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
cursor: move;
|
cursor: move;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
`
|
`;
|
||||||
|
|
||||||
export const ArrayTable: any = styled(
|
export const ArrayTable: any = styled(
|
||||||
(props: ISchemaFieldComponentProps & { className: string }) => {
|
(props: ISchemaFieldComponentProps & { className: string }) => {
|
||||||
const expressionScope = useContext(FormExpressionScopeContext)
|
const expressionScope = useContext(FormExpressionScopeContext);
|
||||||
const { value, schema, className, editable, path, mutators } = props
|
const { value, schema, className, editable, path, mutators } = props;
|
||||||
const {
|
const {
|
||||||
renderAddition,
|
renderAddition,
|
||||||
renderRemove,
|
renderRemove,
|
||||||
@ -55,31 +59,31 @@ export const ArrayTable: any = styled(
|
|||||||
operations,
|
operations,
|
||||||
draggable,
|
draggable,
|
||||||
...componentProps
|
...componentProps
|
||||||
} = schema.getExtendsComponentProps() || {}
|
} = schema.getExtendsComponentProps() || {};
|
||||||
const schemaItems = Array.isArray(schema.items)
|
const schemaItems = Array.isArray(schema.items)
|
||||||
? schema.items[schema.items.length - 1]
|
? schema.items[schema.items.length - 1]
|
||||||
: schema.items
|
: schema.items;
|
||||||
const onAdd = () => {
|
const onAdd = () => {
|
||||||
if (schemaItems) {
|
if (schemaItems) {
|
||||||
mutators.push(schemaItems.getEmptyValue())
|
mutators.push(schemaItems.getEmptyValue());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
const onMove = (dragIndex, dropIndex) => {
|
const onMove = (dragIndex, dropIndex) => {
|
||||||
mutators.move(dragIndex, dropIndex)
|
mutators.move(dragIndex, dropIndex);
|
||||||
}
|
};
|
||||||
const renderColumns = (items: Schema) => {
|
const renderColumns = (items: Schema) => {
|
||||||
return items.mapProperties((props, key) => {
|
return items.mapProperties((props, key) => {
|
||||||
const itemProps = {
|
const itemProps = {
|
||||||
...props.getExtendsItemProps(),
|
...props.getExtendsItemProps(),
|
||||||
...props.getExtendsProps()
|
...props.getExtendsProps(),
|
||||||
}
|
};
|
||||||
return {
|
return {
|
||||||
title: complieExpression(props.title, expressionScope),
|
title: complieExpression(props.title, expressionScope),
|
||||||
...itemProps,
|
...itemProps,
|
||||||
key,
|
key,
|
||||||
dataIndex: key,
|
dataIndex: key,
|
||||||
render: (value: any, record: any, index: number) => {
|
render: (value: any, record: any, index: number) => {
|
||||||
const newPath = FormPath.parse(path).concat(index, key)
|
const newPath = FormPath.parse(path).concat(index, key);
|
||||||
return (
|
return (
|
||||||
<FormItemShallowProvider
|
<FormItemShallowProvider
|
||||||
key={newPath.toString()}
|
key={newPath.toString()}
|
||||||
@ -89,19 +93,19 @@ export const ArrayTable: any = styled(
|
|||||||
>
|
>
|
||||||
<SchemaField path={newPath} schema={props} />
|
<SchemaField path={newPath} schema={props} />
|
||||||
</FormItemShallowProvider>
|
</FormItemShallowProvider>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
// 兼容异步items schema传入
|
// 兼容异步items schema传入
|
||||||
let columns = []
|
let columns = [];
|
||||||
if (schema.items) {
|
if (schema.items) {
|
||||||
columns = isArr(schema.items)
|
columns = isArr(schema.items)
|
||||||
? schema.items.reduce((buf, items) => {
|
? schema.items.reduce((buf, items) => {
|
||||||
return buf.concat(renderColumns(items))
|
return buf.concat(renderColumns(items));
|
||||||
}, [])
|
}, [])
|
||||||
: renderColumns(schema.items)
|
: renderColumns(schema.items);
|
||||||
}
|
}
|
||||||
if (editable && operations !== false) {
|
if (editable && operations !== false) {
|
||||||
columns.push({
|
columns.push({
|
||||||
@ -130,32 +134,32 @@ export const ArrayTable: any = styled(
|
|||||||
: renderExtraOperations}
|
: renderExtraOperations}
|
||||||
</div>
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
if (draggable) {
|
if (draggable) {
|
||||||
columns.unshift({
|
columns.unshift({
|
||||||
width: 20,
|
width: 20,
|
||||||
key: 'dragHandler',
|
key: 'dragHandler',
|
||||||
render: () => {
|
render: () => {
|
||||||
return <DragHandler className="drag-handler" />
|
return <DragHandler className="drag-handler" />;
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
const renderTable = () => {
|
const renderTable = () => {
|
||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
{...componentProps}
|
{...componentProps}
|
||||||
rowKey={record => {
|
rowKey={record => {
|
||||||
return toArr(value).indexOf(record)
|
return toArr(value).indexOf(record);
|
||||||
}}
|
}}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={toArr(value)}
|
dataSource={toArr(value)}
|
||||||
></Table>
|
></Table>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<ArrayList
|
<ArrayList
|
||||||
@ -169,7 +173,7 @@ export const ArrayTable: any = styled(
|
|||||||
renderRemove,
|
renderRemove,
|
||||||
renderMoveDown,
|
renderMoveDown,
|
||||||
renderMoveUp,
|
renderMoveUp,
|
||||||
renderEmpty
|
renderEmpty,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{draggable ? (
|
{draggable ? (
|
||||||
@ -191,13 +195,13 @@ export const ArrayTable: any = styled(
|
|||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
)
|
);
|
||||||
}}
|
}}
|
||||||
</ArrayList.Addition>
|
</ArrayList.Addition>
|
||||||
</ArrayList>
|
</ArrayList>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
)`
|
)`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
@ -227,8 +231,8 @@ export const ArrayTable: any = styled(
|
|||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
ArrayTable.isFieldComponent = true
|
ArrayTable.isFieldComponent = true;
|
||||||
|
|
||||||
export default ArrayTable
|
export default ArrayTable;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/table/style/index'
|
import 'antd/lib/table/style/index';
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { Button, Select, DatePicker, Tag, InputNumber, TimePicker, Input } from 'antd';
|
import {
|
||||||
|
Button,
|
||||||
|
Select,
|
||||||
|
DatePicker,
|
||||||
|
Tag,
|
||||||
|
InputNumber,
|
||||||
|
TimePicker,
|
||||||
|
Input,
|
||||||
|
} from 'antd';
|
||||||
import {
|
import {
|
||||||
Select as AntdSelect,
|
Select as AntdSelect,
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent
|
mapTextComponent,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
@ -14,11 +22,11 @@ import { useRequest } from 'umi';
|
|||||||
export const DateTime = connect({
|
export const DateTime = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})((props) => {
|
})(props => {
|
||||||
const { associatedKey, automationType, filter, onChange } = props;
|
const { associatedKey, automationType, filter, onChange } = props;
|
||||||
const [aKey, setaKey] = useState(associatedKey);
|
const [aKey, setaKey] = useState(associatedKey);
|
||||||
const [aType, setaType] = useState(automationType);
|
const [aType, setaType] = useState(automationType);
|
||||||
console.log('Automations.DateTime', aKey, associatedKey)
|
console.log('Automations.DateTime', aKey, associatedKey);
|
||||||
const [value, setValue] = useState(props.value || {});
|
const [value, setValue] = useState(props.value || {});
|
||||||
const [offsetType, setOffsetType] = useState(() => {
|
const [offsetType, setOffsetType] = useState(() => {
|
||||||
if (!value.offset) {
|
if (!value.offset) {
|
||||||
@ -31,7 +39,7 @@ export const DateTime = connect({
|
|||||||
return 'before';
|
return 'before';
|
||||||
}
|
}
|
||||||
return 'current';
|
return 'current';
|
||||||
})
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (associatedKey !== aKey || automationType !== aType) {
|
if (associatedKey !== aKey || automationType !== aType) {
|
||||||
@ -48,45 +56,62 @@ export const DateTime = connect({
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
unit: undefined,
|
unit: undefined,
|
||||||
});
|
});
|
||||||
setaKey(associatedKey)
|
setaKey(associatedKey);
|
||||||
}
|
}
|
||||||
}, [associatedKey, automationType, aKey, aType]);
|
}, [associatedKey, automationType, aKey, aType]);
|
||||||
const { data = [], loading = true } = useRequest(() => {
|
const { data = [], loading = true } = useRequest(
|
||||||
return associatedKey && automationType !== 'schedule' ? api.resource('collections.fields').list({
|
() => {
|
||||||
|
return associatedKey && automationType !== 'schedule'
|
||||||
|
? api.resource('collections.fields').list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
filter: filter || {
|
filter: filter || {
|
||||||
type: 'date',
|
type: 'date',
|
||||||
},
|
},
|
||||||
}) : Promise.resolve({data: []});
|
})
|
||||||
}, {
|
: Promise.resolve({ data: [] });
|
||||||
refreshDeps: [associatedKey, automationType, filter]
|
},
|
||||||
});
|
{
|
||||||
|
refreshDeps: [associatedKey, automationType, filter],
|
||||||
|
},
|
||||||
|
);
|
||||||
console.log({ data });
|
console.log({ data });
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
{automationType === 'schedule' ? (
|
{automationType === 'schedule' ? (
|
||||||
<DatePicker showTime onChange={(m, dateString) => {
|
<DatePicker
|
||||||
|
showTime
|
||||||
|
onChange={(m, dateString) => {
|
||||||
onChange({ value: m.toISOString() });
|
onChange({ value: m.toISOString() });
|
||||||
setValue({ value: m.toISOString() });
|
setValue({ value: m.toISOString() });
|
||||||
// console.log('Automations.DateTime', m.toISOString(), {m, dateString})
|
// console.log('Automations.DateTime', m.toISOString(), {m, dateString})
|
||||||
}} defaultValue={(() => {
|
}}
|
||||||
|
defaultValue={(() => {
|
||||||
if (!value.value) {
|
if (!value.value) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const m = moment(value.value);
|
const m = moment(value.value);
|
||||||
return m.isValid() ? m : undefined;
|
return m.isValid() ? m : undefined;
|
||||||
})()}/>
|
})()}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Input.Group compact>
|
<Input.Group compact>
|
||||||
<Select style={{width: 120}} value={value.byField} onChange={(v) => {
|
<Select
|
||||||
|
style={{ width: 120 }}
|
||||||
|
value={value.byField}
|
||||||
|
onChange={v => {
|
||||||
setValue({ ...value, byField: v });
|
setValue({ ...value, byField: v });
|
||||||
onChange({ ...value, byField: v });
|
onChange({ ...value, byField: v });
|
||||||
}} loading={loading} options={data.map(item => ({
|
}}
|
||||||
|
loading={loading}
|
||||||
|
options={data.map(item => ({
|
||||||
value: item.name,
|
value: item.name,
|
||||||
label: item.title || item.name,
|
label: item.title || item.name,
|
||||||
}))} placeholder={'选择日期字段'}></Select>
|
}))}
|
||||||
<Select onChange={(offsetType) => {
|
placeholder={'选择日期字段'}
|
||||||
|
></Select>
|
||||||
|
<Select
|
||||||
|
onChange={offsetType => {
|
||||||
let values = { ...value };
|
let values = { ...value };
|
||||||
switch (offsetType) {
|
switch (offsetType) {
|
||||||
case 'current':
|
case 'current':
|
||||||
@ -106,16 +131,24 @@ export const DateTime = connect({
|
|||||||
setOffsetType(offsetType);
|
setOffsetType(offsetType);
|
||||||
setValue(values);
|
setValue(values);
|
||||||
onChange(values);
|
onChange(values);
|
||||||
}} value={offsetType} placeholder={'选择日期字段'}>
|
}}
|
||||||
|
value={offsetType}
|
||||||
|
placeholder={'选择日期字段'}
|
||||||
|
>
|
||||||
<Select.Option value={'current'}>当天</Select.Option>
|
<Select.Option value={'current'}>当天</Select.Option>
|
||||||
<Select.Option value={'before'}>之前</Select.Option>
|
<Select.Option value={'before'}>之前</Select.Option>
|
||||||
<Select.Option value={'after'}>之后</Select.Option>
|
<Select.Option value={'after'}>之后</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
{offsetType !== 'current' && (
|
{offsetType !== 'current' && (
|
||||||
<InputNumber step={1} min={1} value={Math.abs(value.offset)||undefined} onChange={(offset: number) => {
|
<InputNumber
|
||||||
|
step={1}
|
||||||
|
min={1}
|
||||||
|
value={Math.abs(value.offset) || undefined}
|
||||||
|
onChange={(offset: number) => {
|
||||||
const values = {
|
const values = {
|
||||||
unit: 'day',...value,
|
unit: 'day',
|
||||||
}
|
...value,
|
||||||
|
};
|
||||||
if (offsetType === 'before') {
|
if (offsetType === 'before') {
|
||||||
values.offset = -1 * Math.abs(offset);
|
values.offset = -1 * Math.abs(offset);
|
||||||
} else if (offsetType === 'after') {
|
} else if (offsetType === 'after') {
|
||||||
@ -123,15 +156,21 @@ export const DateTime = connect({
|
|||||||
}
|
}
|
||||||
setValue(values);
|
setValue(values);
|
||||||
onChange(values);
|
onChange(values);
|
||||||
console.log('Automations.DateTime', values)
|
console.log('Automations.DateTime', values);
|
||||||
// console.log(offsetType);
|
// console.log(offsetType);
|
||||||
}} placeholder={'数字'}/>
|
}}
|
||||||
|
placeholder={'数字'}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{offsetType !== 'current' && (
|
{offsetType !== 'current' && (
|
||||||
<Select onChange={(v) => {
|
<Select
|
||||||
|
onChange={v => {
|
||||||
setValue({ ...value, unit: v });
|
setValue({ ...value, unit: v });
|
||||||
onChange({ ...value, unit: v });
|
onChange({ ...value, unit: v });
|
||||||
}} value={value.unit} placeholder={'选择单位'}>
|
}}
|
||||||
|
value={value.unit}
|
||||||
|
placeholder={'选择单位'}
|
||||||
|
>
|
||||||
<Select.Option value={'second'}>秒</Select.Option>
|
<Select.Option value={'second'}>秒</Select.Option>
|
||||||
<Select.Option value={'minute'}>分钟</Select.Option>
|
<Select.Option value={'minute'}>分钟</Select.Option>
|
||||||
<Select.Option value={'hour'}>小时</Select.Option>
|
<Select.Option value={'hour'}>小时</Select.Option>
|
||||||
@ -140,22 +179,27 @@ export const DateTime = connect({
|
|||||||
<Select.Option value={'month'}>月</Select.Option>
|
<Select.Option value={'month'}>月</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
)}
|
)}
|
||||||
{offsetType !== 'current' && value.unit && ['day', 'week', 'month'].indexOf(value.unit) !== -1 && (
|
{offsetType !== 'current' &&
|
||||||
<TimePicker value={(() => {
|
value.unit &&
|
||||||
|
['day', 'week', 'month'].indexOf(value.unit) !== -1 && (
|
||||||
|
<TimePicker
|
||||||
|
value={(() => {
|
||||||
const m = moment(value.time, 'HH:mm:ss');
|
const m = moment(value.time, 'HH:mm:ss');
|
||||||
return m.isValid() ? m : undefined;
|
return m.isValid() ? m : undefined;
|
||||||
})()} onChange={(m, dateString) => {
|
})()}
|
||||||
console.log('Automations.DateTime', m, dateString)
|
onChange={(m, dateString) => {
|
||||||
|
console.log('Automations.DateTime', m, dateString);
|
||||||
setValue({ ...value, time: dateString });
|
setValue({ ...value, time: dateString });
|
||||||
onChange({ ...value, time: dateString });
|
onChange({ ...value, time: dateString });
|
||||||
}}/>
|
}}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</Input.Group>
|
</Input.Group>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
const cronmap = {
|
const cronmap = {
|
||||||
none: '不重复',
|
none: '不重复',
|
||||||
@ -171,10 +215,10 @@ const cronmap = {
|
|||||||
export const Cron = connect({
|
export const Cron = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})((props) => {
|
})(props => {
|
||||||
const { value, onChange } = props;
|
const { value, onChange } = props;
|
||||||
|
|
||||||
console.log('Automations.DateTime', {value})
|
console.log('Automations.DateTime', { value });
|
||||||
|
|
||||||
const re = /every_(\d+)_(.+)/i;
|
const re = /every_(\d+)_(.+)/i;
|
||||||
|
|
||||||
@ -187,33 +231,42 @@ export const Cron = connect({
|
|||||||
return 'none';
|
return 'none';
|
||||||
}
|
}
|
||||||
return match ? 'custom' : cronmap[value];
|
return match ? 'custom' : cronmap[value];
|
||||||
})
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Input.Group compact>
|
<Input.Group compact>
|
||||||
<Select value={cron} onChange={(v) => {
|
<Select
|
||||||
|
value={cron}
|
||||||
|
onChange={v => {
|
||||||
setCron(v);
|
setCron(v);
|
||||||
onChange(v);
|
onChange(v);
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{Object.keys(cronmap).map(key => {
|
{Object.keys(cronmap).map(key => {
|
||||||
return (
|
return <Select.Option value={key}>{cronmap[key]}</Select.Option>;
|
||||||
<Select.Option value={key}>{cronmap[key]}</Select.Option>
|
|
||||||
);
|
|
||||||
})}
|
})}
|
||||||
</Select>
|
</Select>
|
||||||
{cron === 'custom' && (
|
{cron === 'custom' && (
|
||||||
<Input type={'number'} onChange={(e) => {
|
<Input
|
||||||
|
type={'number'}
|
||||||
|
onChange={e => {
|
||||||
const v = parseInt(e.target.value);
|
const v = parseInt(e.target.value);
|
||||||
setNum(v);
|
setNum(v);
|
||||||
onChange(`every_${v}_${unit}`);
|
onChange(`every_${v}_${unit}`);
|
||||||
}} defaultValue={num} addonBefore={'每'}/>
|
}}
|
||||||
|
defaultValue={num}
|
||||||
|
addonBefore={'每'}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{cron === 'custom' && (
|
{cron === 'custom' && (
|
||||||
<Select onChange={(v) => {
|
<Select
|
||||||
|
onChange={v => {
|
||||||
setUnit(v);
|
setUnit(v);
|
||||||
onChange(`every_${num}_${v}`);
|
onChange(`every_${num}_${v}`);
|
||||||
}} defaultValue={unit}>
|
}}
|
||||||
|
defaultValue={unit}
|
||||||
|
>
|
||||||
<Select.Option value={'seconds'}>秒</Select.Option>
|
<Select.Option value={'seconds'}>秒</Select.Option>
|
||||||
<Select.Option value={'minutes'}>分钟</Select.Option>
|
<Select.Option value={'minutes'}>分钟</Select.Option>
|
||||||
<Select.Option value={'hours'}>小时</Select.Option>
|
<Select.Option value={'hours'}>小时</Select.Option>
|
||||||
@ -224,13 +277,13 @@ export const Cron = connect({
|
|||||||
)}
|
)}
|
||||||
</Input.Group>
|
</Input.Group>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
export const EndMode = connect({
|
export const EndMode = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})((props) => {
|
})(props => {
|
||||||
const { value = 'none', onChange, automationType } = props;
|
const { value = 'none', onChange, automationType } = props;
|
||||||
const re = /after_(\d+)_times/i;
|
const re = /after_(\d+)_times/i;
|
||||||
const match = re.exec(value);
|
const match = re.exec(value);
|
||||||
@ -238,7 +291,10 @@ export const EndMode = connect({
|
|||||||
const [mode, setMode] = useState(() => {
|
const [mode, setMode] = useState(() => {
|
||||||
if (automationType === 'schedule' && value === 'byField') {
|
if (automationType === 'schedule' && value === 'byField') {
|
||||||
return 'none';
|
return 'none';
|
||||||
} else if (automationType === 'collections:schedule' && value === 'customTime') {
|
} else if (
|
||||||
|
automationType === 'collections:schedule' &&
|
||||||
|
value === 'customTime'
|
||||||
|
) {
|
||||||
return 'none';
|
return 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,38 +305,57 @@ export const EndMode = connect({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (automationType === 'schedule' && value === 'byField') {
|
if (automationType === 'schedule' && value === 'byField') {
|
||||||
setMode('none')
|
setMode('none');
|
||||||
onChange('none')
|
onChange('none');
|
||||||
} else if (automationType === 'collections:schedule' && value === 'customTime') {
|
} else if (
|
||||||
setMode('none')
|
automationType === 'collections:schedule' &&
|
||||||
onChange('none')
|
value === 'customTime'
|
||||||
|
) {
|
||||||
|
setMode('none');
|
||||||
|
onChange('none');
|
||||||
}
|
}
|
||||||
}, [automationType]);
|
}, [automationType]);
|
||||||
console.log('Automations.DateTime', {value, automationType, mode})
|
console.log('Automations.DateTime', { value, automationType, mode });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Input.Group compact>
|
<Input.Group compact>
|
||||||
<Select style={{width: 150}} value={mode} onChange={(v) => {
|
<Select
|
||||||
|
style={{ width: 150 }}
|
||||||
|
value={mode}
|
||||||
|
onChange={v => {
|
||||||
setMode(v);
|
setMode(v);
|
||||||
onChange(v);
|
onChange(v);
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<Select.Option value={'none'}>永不结束</Select.Option>
|
<Select.Option value={'none'}>永不结束</Select.Option>
|
||||||
<Select.Option value={'times'}>指定重复次数</Select.Option>
|
<Select.Option value={'times'}>指定重复次数</Select.Option>
|
||||||
{automationType === 'schedule' && <Select.Option value={'customTime'}>自定义时间</Select.Option>}
|
{automationType === 'schedule' && (
|
||||||
{automationType === 'collections:schedule' && <Select.Option value={'byField'}>根据日期字段</Select.Option>}
|
<Select.Option value={'customTime'}>自定义时间</Select.Option>
|
||||||
|
)}
|
||||||
|
{automationType === 'collections:schedule' && (
|
||||||
|
<Select.Option value={'byField'}>根据日期字段</Select.Option>
|
||||||
|
)}
|
||||||
</Select>
|
</Select>
|
||||||
{mode === 'times' && <Input type={'number'} onChange={(e) => {
|
{mode === 'times' && (
|
||||||
|
<Input
|
||||||
|
type={'number'}
|
||||||
|
onChange={e => {
|
||||||
const v = parseInt(e.target.value);
|
const v = parseInt(e.target.value);
|
||||||
setNum(v);
|
setNum(v);
|
||||||
onChange(`after_${v}_times`);
|
onChange(`after_${v}_times`);
|
||||||
}} defaultValue={num} addonAfter={'次'}/>}
|
}}
|
||||||
|
defaultValue={num}
|
||||||
|
addonAfter={'次'}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Input.Group>
|
</Input.Group>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
export const Automations = {
|
export const Automations = {
|
||||||
DateTime, Cron, EndMode
|
DateTime,
|
||||||
|
Cron,
|
||||||
|
EndMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { Cascader as AntdCascader } from 'antd'
|
import { Cascader as AntdCascader } from 'antd';
|
||||||
import { useRequest } from 'umi';
|
import { useRequest } from 'umi';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import {
|
import {
|
||||||
transformDataSourceKey,
|
transformDataSourceKey,
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent
|
mapTextComponent,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
|
|
||||||
function findTreeNode(tree, values, { value = 'value', children = 'children' }) {
|
function findTreeNode(
|
||||||
|
tree,
|
||||||
|
values,
|
||||||
|
{ value = 'value', children = 'children' },
|
||||||
|
) {
|
||||||
let node, i;
|
let node, i;
|
||||||
for (node = tree, i = 0; node && values[i]; i++) {
|
for (node = tree, i = 0; node && values[i]; i++) {
|
||||||
node = (node[children] || []).find(item => item[value] === values[i][value]);
|
node = (node[children] || []).find(
|
||||||
|
item => item[value] === values[i][value],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
@ -55,17 +61,17 @@ export const Cascader = connect({
|
|||||||
// 是否可以不选择到最深一级
|
// 是否可以不选择到最深一级
|
||||||
// 'x-component-props': { changeOnSelect: true }
|
// 'x-component-props': { changeOnSelect: true }
|
||||||
incompletely: changeOnSelect,
|
incompletely: changeOnSelect,
|
||||||
|
|
||||||
} = schema;
|
} = schema;
|
||||||
|
|
||||||
const fieldNames = {
|
const fieldNames = {
|
||||||
label: labelField,
|
label: labelField,
|
||||||
value: valueField,
|
value: valueField,
|
||||||
children: 'children'
|
children: 'children',
|
||||||
};
|
};
|
||||||
const [options, setOptions] = useState([]);
|
const [options, setOptions] = useState([]);
|
||||||
|
|
||||||
const { loading, run } = useRequest(async (selectedOptions = []) => {
|
const { loading, run } = useRequest(
|
||||||
|
async (selectedOptions = []) => {
|
||||||
if (maxLevel != null && selectedOptions.length >= maxLevel) {
|
if (maxLevel != null && selectedOptions.length >= maxLevel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -80,17 +86,18 @@ export const Cascader = connect({
|
|||||||
|
|
||||||
return api.resource(target).list({
|
return api.resource(target).list({
|
||||||
filter: {
|
filter: {
|
||||||
[parentField]: last && last[valueField]
|
[parentField]: last && last[valueField],
|
||||||
},
|
},
|
||||||
perPage: -1,
|
perPage: -1,
|
||||||
sort: [valueField]
|
sort: [valueField],
|
||||||
});
|
});
|
||||||
// TODO(bug): 关联资源加载问题较多,暂时先用 filter 解决
|
// TODO(bug): 关联资源加载问题较多,暂时先用 filter 解决
|
||||||
// return api.resource(`${target}.${target}`).list({
|
// return api.resource(`${target}.${target}`).list({
|
||||||
// associatedKey: last,
|
// associatedKey: last,
|
||||||
// perPage: -1
|
// perPage: -1
|
||||||
// });
|
// });
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
manual: true,
|
manual: true,
|
||||||
onSuccess(result, [selectedOptions = []]) {
|
onSuccess(result, [selectedOptions = []]) {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@ -99,7 +106,7 @@ export const Cascader = connect({
|
|||||||
|
|
||||||
const data = result.map(item => ({
|
const data = result.map(item => ({
|
||||||
...item,
|
...item,
|
||||||
isLeaf: maxLevel != null && item.level >= maxLevel
|
isLeaf: maxLevel != null && item.level >= maxLevel,
|
||||||
}));
|
}));
|
||||||
// 找到已有值指向的 options 节点
|
// 找到已有值指向的 options 节点
|
||||||
const root = { [fieldNames.children]: options };
|
const root = { [fieldNames.children]: options };
|
||||||
@ -113,13 +120,17 @@ export const Cascader = connect({
|
|||||||
} else {
|
} else {
|
||||||
setOptions(data);
|
setOptions(data);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// 根据 value 的值,按需预加载相应的数据
|
// 根据 value 的值,按需预加载相应的数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (value.length) {
|
if (value.length) {
|
||||||
value.reduce((promise, option, i) => promise.then(() => run(value.slice(0, i))), Promise.resolve());
|
value.reduce(
|
||||||
|
(promise, option, i) => promise.then(() => run(value.slice(0, i))),
|
||||||
|
Promise.resolve(),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
run([]);
|
run([]);
|
||||||
}
|
}
|
||||||
@ -143,6 +154,6 @@ export const Cascader = connect({
|
|||||||
fieldNames={fieldNames}
|
fieldNames={fieldNames}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
export default Cascader
|
export default Cascader;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/cascader/style/index'
|
import 'antd/lib/cascader/style/index';
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
import {
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
connect
|
import { Checkbox as AntdCheckbox } from 'antd';
|
||||||
} from '@formily/react-schema-renderer'
|
|
||||||
import { Checkbox as AntdCheckbox } from 'antd'
|
|
||||||
import {
|
import {
|
||||||
transformDataSourceKey,
|
transformDataSourceKey,
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent
|
mapTextComponent,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
|
|
||||||
export const Checkbox = connect<'Group'>({
|
export const Checkbox = connect<'Group'>({
|
||||||
valueName: 'checked',
|
valueName: 'checked',
|
||||||
getProps: mapStyledProps
|
getProps: mapStyledProps,
|
||||||
})(AntdCheckbox)
|
})(AntdCheckbox);
|
||||||
|
|
||||||
Checkbox.Group = connect({
|
Checkbox.Group = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(transformDataSourceKey(AntdCheckbox.Group, 'options'))
|
})(transformDataSourceKey(AntdCheckbox.Group, 'options'));
|
||||||
|
|
||||||
export default Checkbox
|
export default Checkbox;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/checkbox/style/index'
|
import 'antd/lib/checkbox/style/index';
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { Button } from 'antd'
|
import { Button } from 'antd';
|
||||||
import { ButtonProps } from 'antd/lib/button'
|
import { ButtonProps } from 'antd/lib/button';
|
||||||
|
|
||||||
export const CircleButton: React.FC<ButtonProps> = props => {
|
export const CircleButton: React.FC<ButtonProps> = props => {
|
||||||
const hasText = String(props.className || '').indexOf('has-text') > -1
|
const hasText = String(props.className || '').indexOf('has-text') > -1;
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
type={hasText ? 'link' : undefined}
|
type={hasText ? 'link' : undefined}
|
||||||
shape={hasText ? undefined : 'circle'}
|
shape={hasText ? undefined : 'circle'}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default CircleButton
|
export default CircleButton;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/button/style/index'
|
import 'antd/lib/button/style/index';
|
||||||
|
@ -1,30 +1,29 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Select, Tag } from 'antd';
|
import { Select, Tag } from 'antd';
|
||||||
import {
|
import {
|
||||||
Select as AntdSelect,
|
Select as AntdSelect,
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent
|
mapTextComponent,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
|
|
||||||
export const ColorSelect = connect({
|
export const ColorSelect = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})((props) => {
|
})(props => {
|
||||||
|
|
||||||
const colors = {
|
const colors = {
|
||||||
'red': '薄暮',
|
red: '薄暮',
|
||||||
'magenta': '法式洋红',
|
magenta: '法式洋红',
|
||||||
'volcano': '火山',
|
volcano: '火山',
|
||||||
'orange': '日暮',
|
orange: '日暮',
|
||||||
'gold': '金盏花',
|
gold: '金盏花',
|
||||||
'lime': '青柠',
|
lime: '青柠',
|
||||||
'green': '极光绿',
|
green: '极光绿',
|
||||||
'cyan': '明青',
|
cyan: '明青',
|
||||||
'blue': '拂晓蓝',
|
blue: '拂晓蓝',
|
||||||
'geekblue': '极客蓝',
|
geekblue: '极客蓝',
|
||||||
'purple': '酱紫',
|
purple: '酱紫',
|
||||||
'default': '默认'
|
default: '默认',
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -35,7 +34,7 @@ export const ColorSelect = connect({
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
|
||||||
export default ColorSelect
|
export default ColorSelect;
|
||||||
|
@ -1,105 +1,105 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import moment from 'moment'
|
import moment from 'moment';
|
||||||
import { DatePicker as AntdDatePicker } from 'antd'
|
import { DatePicker as AntdDatePicker } from 'antd';
|
||||||
import {
|
import {
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent,
|
mapTextComponent,
|
||||||
compose,
|
compose,
|
||||||
isStr,
|
isStr,
|
||||||
isArr
|
isArr,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
|
|
||||||
class YearPicker extends React.Component {
|
class YearPicker extends React.Component {
|
||||||
public render() {
|
public render() {
|
||||||
return <AntdDatePicker {...this.props} picker={'year'} />
|
return <AntdDatePicker {...this.props} picker={'year'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformMoment = (value, format = 'YYYY-MM-DD HH:mm:ss') => {
|
const transformMoment = (value, format = 'YYYY-MM-DD HH:mm:ss') => {
|
||||||
if (value === '') return undefined
|
if (value === '') return undefined;
|
||||||
return value && value.format ? value.format(format) : value
|
return value && value.format ? value.format(format) : value;
|
||||||
}
|
};
|
||||||
|
|
||||||
const mapMomentValue = (props: any, fieldProps: any) => {
|
const mapMomentValue = (props: any, fieldProps: any) => {
|
||||||
const { value, showTime = false } = props
|
const { value, showTime = false } = props;
|
||||||
if (!fieldProps.editable) return props
|
if (!fieldProps.editable) return props;
|
||||||
try {
|
try {
|
||||||
if (isStr(value) && value) {
|
if (isStr(value) && value) {
|
||||||
props.value = moment(
|
props.value = moment(
|
||||||
value,
|
value,
|
||||||
showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'
|
showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD',
|
||||||
)
|
);
|
||||||
} else if (isArr(value) && value.length) {
|
} else if (isArr(value) && value.length) {
|
||||||
props.value = value.map(
|
props.value = value.map(
|
||||||
item =>
|
item =>
|
||||||
(item &&
|
(item &&
|
||||||
moment(item, showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')) ||
|
moment(item, showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')) ||
|
||||||
''
|
'',
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(e)
|
throw new Error(e);
|
||||||
}
|
|
||||||
return props
|
|
||||||
}
|
}
|
||||||
|
return props;
|
||||||
|
};
|
||||||
|
|
||||||
export const DatePicker = connect<
|
export const DatePicker = connect<
|
||||||
'RangePicker' | 'MonthPicker' | 'YearPicker' | 'WeekPicker'
|
'RangePicker' | 'MonthPicker' | 'YearPicker' | 'WeekPicker'
|
||||||
>({
|
>({
|
||||||
getValueFromEvent(_, value) {
|
getValueFromEvent(_, value) {
|
||||||
const props = this.props || {}
|
const props = this.props || {};
|
||||||
return transformMoment(
|
return transformMoment(
|
||||||
value,
|
value,
|
||||||
props.format || (props.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')
|
props.format || (props.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'),
|
||||||
)
|
);
|
||||||
},
|
},
|
||||||
getProps: compose(mapStyledProps, mapMomentValue),
|
getProps: compose(mapStyledProps, mapMomentValue),
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(AntdDatePicker)
|
})(AntdDatePicker);
|
||||||
|
|
||||||
DatePicker.RangePicker = connect({
|
DatePicker.RangePicker = connect({
|
||||||
getValueFromEvent(_, [startDate, endDate]) {
|
getValueFromEvent(_, [startDate, endDate]) {
|
||||||
const props = this.props || {}
|
const props = this.props || {};
|
||||||
const format =
|
const format =
|
||||||
props.format || (props.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')
|
props.format || (props.showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD');
|
||||||
return [
|
return [
|
||||||
transformMoment(startDate, format),
|
transformMoment(startDate, format),
|
||||||
transformMoment(endDate, format)
|
transformMoment(endDate, format),
|
||||||
]
|
];
|
||||||
},
|
},
|
||||||
getProps: compose(mapStyledProps, mapMomentValue),
|
getProps: compose(mapStyledProps, mapMomentValue),
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(AntdDatePicker.RangePicker)
|
})(AntdDatePicker.RangePicker);
|
||||||
|
|
||||||
DatePicker.MonthPicker = connect({
|
DatePicker.MonthPicker = connect({
|
||||||
getValueFromEvent(_, value) {
|
getValueFromEvent(_, value) {
|
||||||
return transformMoment(value)
|
return transformMoment(value);
|
||||||
},
|
},
|
||||||
getProps: compose(mapStyledProps, mapMomentValue),
|
getProps: compose(mapStyledProps, mapMomentValue),
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(AntdDatePicker.MonthPicker)
|
})(AntdDatePicker.MonthPicker);
|
||||||
|
|
||||||
DatePicker.WeekPicker = connect({
|
DatePicker.WeekPicker = connect({
|
||||||
getValueFromEvent(_, value) {
|
getValueFromEvent(_, value) {
|
||||||
return transformMoment(value, 'gggg-wo')
|
return transformMoment(value, 'gggg-wo');
|
||||||
},
|
},
|
||||||
getProps: compose(mapStyledProps, props => {
|
getProps: compose(mapStyledProps, props => {
|
||||||
if (isStr(props.value) && props.value) {
|
if (isStr(props.value) && props.value) {
|
||||||
const parsed = props.value.match(/\D*(\d+)\D*(\d+)\D*/) || ['', '', '']
|
const parsed = props.value.match(/\D*(\d+)\D*(\d+)\D*/) || ['', '', ''];
|
||||||
props.value = moment(parsed[1], 'YYYY').add(parsed[2] - 1, 'weeks')
|
props.value = moment(parsed[1], 'YYYY').add(parsed[2] - 1, 'weeks');
|
||||||
}
|
}
|
||||||
return props
|
return props;
|
||||||
}),
|
}),
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(AntdDatePicker.WeekPicker)
|
})(AntdDatePicker.WeekPicker);
|
||||||
|
|
||||||
DatePicker.YearPicker = connect({
|
DatePicker.YearPicker = connect({
|
||||||
getValueFromEvent(_, value) {
|
getValueFromEvent(_, value) {
|
||||||
return transformMoment(value, 'YYYY')
|
return transformMoment(value, 'YYYY');
|
||||||
},
|
},
|
||||||
getProps: compose(mapStyledProps, mapMomentValue),
|
getProps: compose(mapStyledProps, mapMomentValue),
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(YearPicker)
|
})(YearPicker);
|
||||||
|
|
||||||
export default DatePicker
|
export default DatePicker;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/date-picker/style/index'
|
import 'antd/lib/date-picker/style/index';
|
||||||
|
@ -1,42 +1,61 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import moment from 'moment'
|
import moment from 'moment';
|
||||||
import { Select, Table } from 'antd'
|
import { Select, Table } from 'antd';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import {
|
import {
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent,
|
mapTextComponent,
|
||||||
compose,
|
compose,
|
||||||
isStr,
|
isStr,
|
||||||
isArr
|
isArr,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
import { useRequest } from 'umi';
|
import { useRequest } from 'umi';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import { Spin } from '@nocobase/client'
|
import { Spin } from '@nocobase/client';
|
||||||
import { fields2columns, components } from '@/components/views/SortableTable'
|
import { fields2columns, components } from '@/components/views/SortableTable';
|
||||||
|
|
||||||
function DraggableTableComponent(props) {
|
function DraggableTableComponent(props) {
|
||||||
const { mode = 'showInDetail', value, onChange, disabled, rowKey = 'id', fields = [], resourceName, associatedKey, filter, labelField, valueField = 'id', objectValue, placeholder } = props;
|
const {
|
||||||
const { data = [], loading = true, mutate } = useRequest(() => {
|
mode = 'showInDetail',
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
disabled,
|
||||||
|
rowKey = 'id',
|
||||||
|
fields = [],
|
||||||
|
resourceName,
|
||||||
|
associatedKey,
|
||||||
|
filter,
|
||||||
|
labelField,
|
||||||
|
valueField = 'id',
|
||||||
|
objectValue,
|
||||||
|
placeholder,
|
||||||
|
} = props;
|
||||||
|
const { data = [], loading = true, mutate } = useRequest(
|
||||||
|
() => {
|
||||||
return api.resource(resourceName).list({
|
return api.resource(resourceName).list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
filter,
|
filter,
|
||||||
perPage: -1,
|
perPage: -1,
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
refreshDeps: [resourceName, associatedKey]
|
{
|
||||||
});
|
refreshDeps: [resourceName, associatedKey],
|
||||||
|
},
|
||||||
|
);
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||||
const onTableChange = (selectedRowKeys: React.ReactText[]) => {
|
const onTableChange = (selectedRowKeys: React.ReactText[]) => {
|
||||||
onChange(selectedRowKeys);
|
onChange(selectedRowKeys);
|
||||||
}
|
};
|
||||||
const tableProps: any = {};
|
const tableProps: any = {};
|
||||||
tableProps.rowSelection = {
|
tableProps.rowSelection = {
|
||||||
selectedRowKeys: Array.isArray(value) ? value : data.map(item => item[rowKey]),
|
selectedRowKeys: Array.isArray(value)
|
||||||
|
? value
|
||||||
|
: data.map(item => item[rowKey]),
|
||||||
onChange: onTableChange,
|
onChange: onTableChange,
|
||||||
}
|
};
|
||||||
const dataSource = data.filter(item => {
|
const dataSource = data.filter(item => {
|
||||||
return get(item, ['component', mode])
|
return get(item, ['component', mode]);
|
||||||
});
|
});
|
||||||
// const sortIds = get(value, 'sort')||[];
|
// const sortIds = get(value, 'sort')||[];
|
||||||
// let values = [];
|
// let values = [];
|
||||||
@ -85,6 +104,6 @@ function DraggableTableComponent(props) {
|
|||||||
export const DraggableTable = connect({
|
export const DraggableTable = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})(DraggableTableComponent)
|
})(DraggableTableComponent);
|
||||||
|
|
||||||
export default DraggableTable
|
export default DraggableTable;
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { Select, Button, Space } from 'antd'
|
import { Select, Button, Space } from 'antd';
|
||||||
import {
|
import {
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent,
|
mapTextComponent,
|
||||||
compose,
|
compose,
|
||||||
isStr,
|
isStr,
|
||||||
isArr
|
isArr,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
import ViewFactory from '@/components/views'
|
import ViewFactory from '@/components/views';
|
||||||
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
||||||
import View from '@/components/pages/AdminLoader/View';
|
import View from '@/components/pages/AdminLoader/View';
|
||||||
|
|
||||||
@ -17,11 +17,13 @@ function transform({value, multiple, labelField, valueField = 'id'}) {
|
|||||||
let selectedValue = [];
|
let selectedValue = [];
|
||||||
const values = Array.isArray(value) ? value : [value];
|
const values = Array.isArray(value) ? value : [value];
|
||||||
selectedKeys = values.filter(item => item).map(item => item[valueField]);
|
selectedKeys = values.filter(item => item).map(item => item[valueField]);
|
||||||
selectedValue = values.filter(item => item).map(item => {
|
selectedValue = values
|
||||||
|
.filter(item => item)
|
||||||
|
.map(item => {
|
||||||
return {
|
return {
|
||||||
value: item[valueField],
|
value: item[valueField],
|
||||||
label: item[labelField],
|
label: item[labelField],
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
if (!multiple) {
|
if (!multiple) {
|
||||||
return [selectedKeys.shift(), selectedValue.shift()];
|
return [selectedKeys.shift(), selectedValue.shift()];
|
||||||
@ -30,14 +32,35 @@ function transform({value, multiple, labelField, valueField = 'id'}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function DrawerSelectComponent(props) {
|
export function DrawerSelectComponent(props) {
|
||||||
const { __parent, size, schema = {}, disabled, viewName, target, multiple, filter, resourceName, associatedKey, valueField = 'id', value, onChange } = props;
|
const {
|
||||||
|
__parent,
|
||||||
|
size,
|
||||||
|
schema = {},
|
||||||
|
disabled,
|
||||||
|
viewName,
|
||||||
|
target,
|
||||||
|
multiple,
|
||||||
|
filter,
|
||||||
|
resourceName,
|
||||||
|
associatedKey,
|
||||||
|
valueField = 'id',
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
} = props;
|
||||||
const labelField = props.labelField || schema.labelField;
|
const labelField = props.labelField || schema.labelField;
|
||||||
const [selectedKeys, selectedValue] = transform({value, multiple, labelField, valueField });
|
const [selectedKeys, selectedValue] = transform({
|
||||||
const [selectedRowKeys, setSelectedRowKeys] = useState(multiple ? selectedKeys : [selectedKeys]);
|
value,
|
||||||
|
multiple,
|
||||||
|
labelField,
|
||||||
|
valueField,
|
||||||
|
});
|
||||||
|
const [selectedRowKeys, setSelectedRowKeys] = useState(
|
||||||
|
multiple ? selectedKeys : [selectedKeys],
|
||||||
|
);
|
||||||
const [selectedRows, setSelectedRows] = useState(selectedValue);
|
const [selectedRows, setSelectedRows] = useState(selectedValue);
|
||||||
const [options, setOptions] = useState(selectedValue);
|
const [options, setOptions] = useState(selectedValue);
|
||||||
const { title = '' } = schema;
|
const { title = '' } = schema;
|
||||||
console.log({schema})
|
console.log({ schema });
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Select
|
<Select
|
||||||
@ -49,7 +72,7 @@ export function DrawerSelectComponent(props) {
|
|||||||
allowClear={true}
|
allowClear={true}
|
||||||
value={options}
|
value={options}
|
||||||
notFoundContent={''}
|
notFoundContent={''}
|
||||||
onChange={(data) => {
|
onChange={data => {
|
||||||
setOptions(data);
|
setOptions(data);
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
const srks = data.map(item => item.value);
|
const srks = data.map(item => item.value);
|
||||||
@ -70,10 +93,17 @@ export function DrawerSelectComponent(props) {
|
|||||||
Drawer.open({
|
Drawer.open({
|
||||||
title: `选择要关联的${title}数据`,
|
title: `选择要关联的${title}数据`,
|
||||||
content: ({ resolve }) => {
|
content: ({ resolve }) => {
|
||||||
console.log('valuevaluevaluevaluevaluevalue', selectedRowKeys, selectedRows, options);
|
console.log(
|
||||||
|
'valuevaluevaluevaluevaluevalue',
|
||||||
|
selectedRowKeys,
|
||||||
|
selectedRows,
|
||||||
|
options,
|
||||||
|
);
|
||||||
const [rows, setRows] = useState(selectedRows);
|
const [rows, setRows] = useState(selectedRows);
|
||||||
const [rowKeys, setRowKeys] = useState(selectedRowKeys)
|
const [rowKeys, setRowKeys] = useState(selectedRowKeys);
|
||||||
const [selected, setSelected] = useState(Array.isArray(value) ? value : [value]);
|
const [selected, setSelected] = useState(
|
||||||
|
Array.isArray(value) ? value : [value],
|
||||||
|
);
|
||||||
console.log({ selectedRowKeys });
|
console.log({ selectedRowKeys });
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -83,9 +113,14 @@ export function DrawerSelectComponent(props) {
|
|||||||
multiple={multiple}
|
multiple={multiple}
|
||||||
defaultFilter={filter}
|
defaultFilter={filter}
|
||||||
defaultSelectedRowKeys={selectedRowKeys}
|
defaultSelectedRowKeys={selectedRowKeys}
|
||||||
onSelected={(values) => {
|
onSelected={values => {
|
||||||
setSelected(values);
|
setSelected(values);
|
||||||
const [selectedKeys, selectedValue] = transform({value: values, multiple: true, labelField, valueField });
|
const [selectedKeys, selectedValue] = transform({
|
||||||
|
value: values,
|
||||||
|
multiple: true,
|
||||||
|
labelField,
|
||||||
|
valueField,
|
||||||
|
});
|
||||||
setSelectedRows(selectedValue);
|
setSelectedRows(selectedValue);
|
||||||
setRows(selectedValue);
|
setRows(selectedValue);
|
||||||
setSelectedRowKeys(selectedKeys);
|
setSelectedRowKeys(selectedKeys);
|
||||||
@ -98,19 +133,24 @@ export function DrawerSelectComponent(props) {
|
|||||||
<Drawer.Footer>
|
<Drawer.Footer>
|
||||||
<Space>
|
<Space>
|
||||||
<Button onClick={resolve}>取消</Button>
|
<Button onClick={resolve}>取消</Button>
|
||||||
<Button onClick={() => {
|
<Button
|
||||||
|
onClick={() => {
|
||||||
setOptions(rows);
|
setOptions(rows);
|
||||||
// console.log('valuevaluevaluevaluevaluevalue', {selectedRowKeys});
|
// console.log('valuevaluevaluevaluevaluevalue', {selectedRowKeys});
|
||||||
onChange(multiple ? selected : selected.shift());
|
onChange(multiple ? selected : selected.shift());
|
||||||
// console.log({rows, rowKeys});
|
// console.log({rows, rowKeys});
|
||||||
resolve();
|
resolve();
|
||||||
}} type={'primary'}>确定</Button>
|
}}
|
||||||
|
type={'primary'}
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Drawer.Footer>
|
</Drawer.Footer>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
// setVisible(true);
|
// setVisible(true);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -122,6 +162,6 @@ export function DrawerSelectComponent(props) {
|
|||||||
export const DrawerSelect = connect({
|
export const DrawerSelect = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})(DrawerSelectComponent)
|
})(DrawerSelectComponent);
|
||||||
|
|
||||||
export default DrawerSelect
|
export default DrawerSelect;
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { Button, Select, Input, Space, Form, InputNumber, DatePicker, TimePicker, Radio } from 'antd';
|
import {
|
||||||
|
Button,
|
||||||
|
Select,
|
||||||
|
Input,
|
||||||
|
Space,
|
||||||
|
Form,
|
||||||
|
InputNumber,
|
||||||
|
DatePicker,
|
||||||
|
TimePicker,
|
||||||
|
Radio,
|
||||||
|
} from 'antd';
|
||||||
import { PlusCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
|
import { PlusCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
|
||||||
import useDynamicList from './useDynamicList';
|
import useDynamicList from './useDynamicList';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { mapStyledProps } from '../shared'
|
import { mapStyledProps } from '../shared';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
@ -11,12 +21,22 @@ import api from '@/api-client';
|
|||||||
import { useRequest } from 'umi';
|
import { useRequest } from 'umi';
|
||||||
|
|
||||||
export function FilterGroup(props: any) {
|
export function FilterGroup(props: any) {
|
||||||
const { showDeleteButton = true, fields = [], sourceFields = [], onDelete, onChange, onAdd, dataSource = {} } = props;
|
const {
|
||||||
const { list, getKey, push, remove, replace } = useDynamicList<any>(dataSource.list || [
|
showDeleteButton = true,
|
||||||
|
fields = [],
|
||||||
|
sourceFields = [],
|
||||||
|
onDelete,
|
||||||
|
onChange,
|
||||||
|
onAdd,
|
||||||
|
dataSource = {},
|
||||||
|
} = props;
|
||||||
|
const { list, getKey, push, remove, replace } = useDynamicList<any>(
|
||||||
|
dataSource.list || [
|
||||||
{
|
{
|
||||||
type: 'item',
|
type: 'item',
|
||||||
},
|
},
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
let style: any = {
|
let style: any = {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
};
|
};
|
||||||
@ -26,20 +46,22 @@ export function FilterGroup(props: any) {
|
|||||||
marginBottom: 14,
|
marginBottom: 14,
|
||||||
padding: 14,
|
padding: 14,
|
||||||
border: '1px dashed #dedede',
|
border: '1px dashed #dedede',
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div style={style}>
|
<div style={style}>
|
||||||
<div style={{ marginBottom: 14 }}>
|
<div style={{ marginBottom: 14 }}>
|
||||||
满足组内
|
满足组内{' '}
|
||||||
{' '}
|
<Select
|
||||||
<Select style={{width: 80}} onChange={(value) => {
|
style={{ width: 80 }}
|
||||||
|
onChange={value => {
|
||||||
onChange({ type: 'group', list, andor: value });
|
onChange({ type: 'group', list, andor: value });
|
||||||
}} defaultValue={dataSource.andor||'and'}>
|
}}
|
||||||
|
defaultValue={dataSource.andor || 'and'}
|
||||||
|
>
|
||||||
<Select.Option value={'and'}>全部</Select.Option>
|
<Select.Option value={'and'}>全部</Select.Option>
|
||||||
<Select.Option value={'or'}>任意</Select.Option>
|
<Select.Option value={'or'}>任意</Select.Option>
|
||||||
</Select>
|
</Select>{' '}
|
||||||
{' '}
|
|
||||||
条件
|
条件
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -48,12 +70,13 @@ export function FilterGroup(props: any) {
|
|||||||
const Component = item.type === 'group' ? FilterGroup : FilterItem;
|
const Component = item.type === 'group' ? FilterGroup : FilterItem;
|
||||||
return (
|
return (
|
||||||
<div style={{ marginBottom: 8 }}>
|
<div style={{ marginBottom: 8 }}>
|
||||||
{<Component
|
{
|
||||||
|
<Component
|
||||||
fields={fields}
|
fields={fields}
|
||||||
sourceFields={sourceFields}
|
sourceFields={sourceFields}
|
||||||
dataSource={item}
|
dataSource={item}
|
||||||
// showDeleteButton={list.length > 1}
|
// showDeleteButton={list.length > 1}
|
||||||
onChange={(value) => {
|
onChange={value => {
|
||||||
replace(index, value);
|
replace(index, value);
|
||||||
const newList = [...list];
|
const newList = [...list];
|
||||||
newList[index] = value;
|
newList[index] = value;
|
||||||
@ -67,25 +90,29 @@ export function FilterGroup(props: any) {
|
|||||||
onChange({ ...dataSource, list: newList });
|
onChange({ ...dataSource, list: newList });
|
||||||
// console.log(list, index);
|
// console.log(list, index);
|
||||||
}}
|
}}
|
||||||
/>}
|
/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Space>
|
<Space>
|
||||||
<Button style={{padding: 0}} type={'link'} onClick={() => {
|
<Button
|
||||||
|
style={{ padding: 0 }}
|
||||||
|
type={'link'}
|
||||||
|
onClick={() => {
|
||||||
const data = {
|
const data = {
|
||||||
type: 'item'
|
type: 'item',
|
||||||
};
|
};
|
||||||
push(data);
|
push(data);
|
||||||
const newList = [...list];
|
const newList = [...list];
|
||||||
newList.push(data);
|
newList.push(data);
|
||||||
onChange({ ...dataSource, list: newList });
|
onChange({ ...dataSource, list: newList });
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<PlusCircleOutlined /> 添加条件
|
<PlusCircleOutlined /> 添加条件
|
||||||
</Button>
|
</Button>{' '}
|
||||||
{' '}
|
|
||||||
<Button
|
<Button
|
||||||
style={{ padding: 0 }}
|
style={{ padding: 0 }}
|
||||||
type={'link'}
|
type={'link'}
|
||||||
@ -106,11 +133,24 @@ export function FilterGroup(props: any) {
|
|||||||
>
|
>
|
||||||
<PlusCircleOutlined /> 添加条件组
|
<PlusCircleOutlined /> 添加条件组
|
||||||
</Button>
|
</Button>
|
||||||
{showDeleteButton && <Button className={'filter-remove-link filter-group'} style={{padding: 0, position: 'absolute', top: 0, right: 0, width: 32}} type={'link'} onClick={(e) => {
|
{showDeleteButton && (
|
||||||
|
<Button
|
||||||
|
className={'filter-remove-link filter-group'}
|
||||||
|
style={{
|
||||||
|
padding: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
width: 32,
|
||||||
|
}}
|
||||||
|
type={'link'}
|
||||||
|
onClick={e => {
|
||||||
onDelete && onDelete(e);
|
onDelete && onDelete(e);
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<CloseCircleOutlined />
|
<CloseCircleOutlined />
|
||||||
</Button>}
|
</Button>
|
||||||
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -227,22 +267,26 @@ const op = {
|
|||||||
attachment: OP_MAP.file,
|
attachment: OP_MAP.file,
|
||||||
};
|
};
|
||||||
|
|
||||||
const StringInput = (props) => {
|
const StringInput = props => {
|
||||||
const { value, onChange, ...restProps } = props;
|
const { value, onChange, ...restProps } = props;
|
||||||
return (
|
return (
|
||||||
<Input {...restProps} defaultValue={value} onChange={(e) => {
|
<Input
|
||||||
|
{...restProps}
|
||||||
|
defaultValue={value}
|
||||||
|
onChange={e => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}/>
|
}}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const controls = {
|
const controls = {
|
||||||
string: StringInput,
|
string: StringInput,
|
||||||
textarea: StringInput,
|
textarea: StringInput,
|
||||||
number: InputNumber,
|
number: InputNumber,
|
||||||
percent: (props) => (
|
percent: props => (
|
||||||
<InputNumber
|
<InputNumber
|
||||||
formatter={value => value ? `${value}%` : ''}
|
formatter={value => (value ? `${value}%` : '')}
|
||||||
parser={value => value.replace('%', '')}
|
parser={value => value.replace('%', '')}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
@ -265,9 +309,13 @@ function DateControl(props: any) {
|
|||||||
// }
|
// }
|
||||||
const m = moment(value, format);
|
const m = moment(value, format);
|
||||||
return (
|
return (
|
||||||
<DatePicker format={format} value={m.isValid() ? m : null} onChange={(value) => {
|
<DatePicker
|
||||||
onChange(value ? value.format('YYYY-MM-DD') : null)
|
format={format}
|
||||||
}}/>
|
value={m.isValid() ? m : null}
|
||||||
|
onChange={value => {
|
||||||
|
onChange(value ? value.format('YYYY-MM-DD') : null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
// return (
|
// return (
|
||||||
// <DatePicker format={format} showTime={field.showTime} value={m.isValid() ? m : null} onChange={(value) => {
|
// <DatePicker format={format} showTime={field.showTime} value={m.isValid() ? m : null} onChange={(value) => {
|
||||||
@ -280,13 +328,15 @@ function TimeControl(props: any) {
|
|||||||
const { field, value, onChange, ...restProps } = props;
|
const { field, value, onChange, ...restProps } = props;
|
||||||
let format = field.timeFormat;
|
let format = field.timeFormat;
|
||||||
const m = moment(value, format);
|
const m = moment(value, format);
|
||||||
return <TimePicker
|
return (
|
||||||
|
<TimePicker
|
||||||
value={m.isValid() ? m : null}
|
value={m.isValid() ? m : null}
|
||||||
format={field.timeFormat}
|
format={field.timeFormat}
|
||||||
onChange={(value) => {
|
onChange={value => {
|
||||||
onChange(value ? value.format('HH:mm:ss') : null)
|
onChange(value ? value.format('HH:mm:ss') : null);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function OptionControl(props) {
|
function OptionControl(props) {
|
||||||
@ -296,19 +346,27 @@ function OptionControl(props) {
|
|||||||
mode = undefined;
|
mode = undefined;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Select style={{ minWidth: 120 }} mode={mode} value={value} onChange={(value) => {
|
<Select
|
||||||
|
style={{ minWidth: 120 }}
|
||||||
|
mode={mode}
|
||||||
|
value={value}
|
||||||
|
onChange={value => {
|
||||||
onChange(value);
|
onChange(value);
|
||||||
}} options={options}>
|
}}
|
||||||
</Select>
|
options={options}
|
||||||
|
></Select>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function BooleanControl(props) {
|
function BooleanControl(props) {
|
||||||
const { value, onChange, ...restProps } = props;
|
const { value, onChange, ...restProps } = props;
|
||||||
return (
|
return (
|
||||||
<Radio.Group value={value} onChange={(e) => {
|
<Radio.Group
|
||||||
|
value={value}
|
||||||
|
onChange={e => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<Radio value={true}>是</Radio>
|
<Radio value={true}>是</Radio>
|
||||||
<Radio value={false}>否</Radio>
|
<Radio value={false}>否</Radio>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
@ -331,8 +389,16 @@ function getComponentTypeByField(field) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function FilterItem(props: FilterItemProps) {
|
export function FilterItem(props: FilterItemProps) {
|
||||||
const { index, fields = [], sourceFields = [], showDeleteButton = true, onDelete, onChange } = props;
|
const {
|
||||||
const defaultField: any = fields.find(field => field.name === props.dataSource.column) || {};
|
index,
|
||||||
|
fields = [],
|
||||||
|
sourceFields = [],
|
||||||
|
showDeleteButton = true,
|
||||||
|
onDelete,
|
||||||
|
onChange,
|
||||||
|
} = props;
|
||||||
|
const defaultField: any =
|
||||||
|
fields.find(field => field.name === props.dataSource.column) || {};
|
||||||
const componentType = getComponentTypeByField(defaultField);
|
const componentType = getComponentTypeByField(defaultField);
|
||||||
const [type, setType] = useState(defaultField.interface || 'string');
|
const [type, setType] = useState(defaultField.interface || 'string');
|
||||||
const [field, setField] = useState<any>({});
|
const [field, setField] = useState<any>({});
|
||||||
@ -352,11 +418,11 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
if (/^{{.+}}$/.test(props.dataSource.value)) {
|
if (/^{{.+}}$/.test(props.dataSource.value)) {
|
||||||
setValueType('ref');
|
setValueType('ref');
|
||||||
}
|
}
|
||||||
}, [
|
}, [props.dataSource, type]);
|
||||||
props.dataSource, type,
|
|
||||||
]);
|
|
||||||
let ValueControl = controls[componentType] || controls.string;
|
let ValueControl = controls[componentType] || controls.string;
|
||||||
if (['$null', '$notNull', '$isTruly', '$isFalsy'].indexOf(dataSource.op) !== -1) {
|
if (
|
||||||
|
['$null', '$notNull', '$isTruly', '$isFalsy'].indexOf(dataSource.op) !== -1
|
||||||
|
) {
|
||||||
ValueControl = NullControl;
|
ValueControl = NullControl;
|
||||||
}
|
}
|
||||||
if (['boolean', 'checkbox'].indexOf(componentType) !== -1) {
|
if (['boolean', 'checkbox'].indexOf(componentType) !== -1) {
|
||||||
@ -368,8 +434,9 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
console.log({ componentType, defaultField, field, valueType, opOptions });
|
console.log({ componentType, defaultField, field, valueType, opOptions });
|
||||||
return (
|
return (
|
||||||
<Space>
|
<Space>
|
||||||
<Select value={dataSource.column}
|
<Select
|
||||||
onChange={(value) => {
|
value={dataSource.column}
|
||||||
|
onChange={value => {
|
||||||
const field = fields.find(field => field.name === value);
|
const field = fields.find(field => field.name === value);
|
||||||
let componentType = field.component.type;
|
let componentType = field.component.type;
|
||||||
if (field.component.type === 'select' && field.multiple) {
|
if (field.component.type === 'select' && field.multiple) {
|
||||||
@ -377,16 +444,24 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
}
|
}
|
||||||
setType(componentType);
|
setType(componentType);
|
||||||
setValueType('custom');
|
setValueType('custom');
|
||||||
onChange({...dataSource, column: value, op: get(op, [componentType, 0, 'value']), value: undefined});
|
onChange({
|
||||||
|
...dataSource,
|
||||||
|
column: value,
|
||||||
|
op: get(op, [componentType, 0, 'value']),
|
||||||
|
value: undefined,
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
style={{ width: 120 }}
|
style={{ width: 120 }}
|
||||||
placeholder={'选择字段'}>
|
placeholder={'选择字段'}
|
||||||
|
>
|
||||||
{fields.map(field => (
|
{fields.map(field => (
|
||||||
<Select.Option value={field.name}>{field.title}</Select.Option>
|
<Select.Option value={field.name}>{field.title}</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<Select value={dataSource.column ? dataSource.op : null} style={{ minWidth: 100 }}
|
<Select
|
||||||
onChange={(value) => {
|
value={dataSource.column ? dataSource.op : null}
|
||||||
|
style={{ minWidth: 100 }}
|
||||||
|
onChange={value => {
|
||||||
onChange({ ...dataSource, op: value });
|
onChange({ ...dataSource, op: value });
|
||||||
}}
|
}}
|
||||||
// value={get(opOptions, [0, 'value'])}
|
// value={get(opOptions, [0, 'value'])}
|
||||||
@ -399,12 +474,13 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
{sourceFields.length > 0 && (
|
{sourceFields.length > 0 && (
|
||||||
<Select
|
<Select
|
||||||
style={{ minWidth: 100 }}
|
style={{ minWidth: 100 }}
|
||||||
onChange={(value) => {
|
onChange={value => {
|
||||||
setDataSource({...dataSource, value: undefined})
|
setDataSource({ ...dataSource, value: undefined });
|
||||||
onChange({ ...dataSource, value: undefined });
|
onChange({ ...dataSource, value: undefined });
|
||||||
setValueType(value);
|
setValueType(value);
|
||||||
}}
|
}}
|
||||||
defaultValue={valueType}>
|
defaultValue={valueType}
|
||||||
|
>
|
||||||
<Select.Option value={'custom'}>自定义</Select.Option>
|
<Select.Option value={'custom'}>自定义</Select.Option>
|
||||||
<Select.Option value={'ref'}>触发表字段</Select.Option>
|
<Select.Option value={'ref'}>触发表字段</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
@ -416,27 +492,38 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
op={dataSource.op}
|
op={dataSource.op}
|
||||||
options={defaultField.dataSource}
|
options={defaultField.dataSource}
|
||||||
value={dataSource.value}
|
value={dataSource.value}
|
||||||
onChange={(value) => {
|
onChange={value => {
|
||||||
onChange({ ...dataSource, value: value });
|
onChange({ ...dataSource, value: value });
|
||||||
}}
|
}}
|
||||||
style={{ width: 180 }}
|
style={{ width: 180 }}
|
||||||
/>
|
/>
|
||||||
) : (sourceFields.length > 0 ? (
|
) : sourceFields.length > 0 ? (
|
||||||
<Select value={dataSource.value}
|
<Select
|
||||||
onChange={(value) => {
|
value={dataSource.value}
|
||||||
|
onChange={value => {
|
||||||
onChange({ ...dataSource, value: value });
|
onChange({ ...dataSource, value: value });
|
||||||
}}
|
}}
|
||||||
style={{ width: 120 }}
|
style={{ width: 120 }}
|
||||||
placeholder={'选择字段'}>
|
placeholder={'选择字段'}
|
||||||
|
>
|
||||||
{sourceFields.map(field => (
|
{sourceFields.map(field => (
|
||||||
<Select.Option value={`{{ ${field.name} }}`}>{field.title}</Select.Option>
|
<Select.Option value={`{{ ${field.name} }}`}>
|
||||||
|
{field.title}
|
||||||
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
) : null)}
|
) : null}
|
||||||
{showDeleteButton && (
|
{showDeleteButton && (
|
||||||
<Button className={'filter-remove-link filter-item'} type={'link'} style={{padding: 0}} onClick={(e) => {
|
<Button
|
||||||
|
className={'filter-remove-link filter-item'}
|
||||||
|
type={'link'}
|
||||||
|
style={{ padding: 0 }}
|
||||||
|
onClick={e => {
|
||||||
onDelete && onDelete(e);
|
onDelete && onDelete(e);
|
||||||
}}><CloseCircleOutlined /></Button>
|
}}
|
||||||
|
>
|
||||||
|
<CloseCircleOutlined />
|
||||||
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
@ -447,10 +534,19 @@ function toFilter(values: any) {
|
|||||||
let { type, andor = 'and', list = [], column, op, value } = values;
|
let { type, andor = 'and', list = [], column, op, value } = values;
|
||||||
if (type === 'group') {
|
if (type === 'group') {
|
||||||
filter = {
|
filter = {
|
||||||
[andor]: list.map(value => toFilter(value)).filter(Boolean)
|
[andor]: list.map(value => toFilter(value)).filter(Boolean),
|
||||||
}
|
};
|
||||||
} else if (type === 'item' && column && op) {
|
} else if (type === 'item' && column && op) {
|
||||||
if (['id.$null', 'id.$notNull', '$null', '$notNull', '$isTruly', '$isFalsy'].indexOf(op) !== -1) {
|
if (
|
||||||
|
[
|
||||||
|
'id.$null',
|
||||||
|
'id.$notNull',
|
||||||
|
'$null',
|
||||||
|
'$notNull',
|
||||||
|
'$isTruly',
|
||||||
|
'$isFalsy',
|
||||||
|
].indexOf(op) !== -1
|
||||||
|
) {
|
||||||
value = true;
|
value = true;
|
||||||
}
|
}
|
||||||
// if (op === 'id.gt') {
|
// if (op === 'id.gt') {
|
||||||
@ -458,7 +554,7 @@ function toFilter(values: any) {
|
|||||||
// }
|
// }
|
||||||
filter = {
|
filter = {
|
||||||
[`${column}`]: { [op]: value },
|
[`${column}`]: { [op]: value },
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
@ -483,45 +579,72 @@ function toValues(filter: any = {}) {
|
|||||||
|
|
||||||
export const Filter = connect({
|
export const Filter = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
})((props) => {
|
})(props => {
|
||||||
const dataSource = {
|
const dataSource = {
|
||||||
type: 'group',
|
type: 'group',
|
||||||
list: [
|
list: [
|
||||||
{
|
{
|
||||||
type: 'item',
|
type: 'item',
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const { value, onChange, associatedKey, filter = {}, sourceName, sourceFilter = {}, fields = [], ...restProps } = props;
|
const {
|
||||||
console.log('filter', {associatedKey})
|
value,
|
||||||
const { data = [], loading = true } = useRequest(() => {
|
onChange,
|
||||||
return associatedKey ? api.resource(`collections.fields`).list({
|
associatedKey,
|
||||||
|
filter = {},
|
||||||
|
sourceName,
|
||||||
|
sourceFilter = {},
|
||||||
|
fields = [],
|
||||||
|
...restProps
|
||||||
|
} = props;
|
||||||
|
console.log('filter', { associatedKey });
|
||||||
|
const { data = [], loading = true } = useRequest(
|
||||||
|
() => {
|
||||||
|
return associatedKey
|
||||||
|
? api.resource(`collections.fields`).list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
filter,
|
filter,
|
||||||
}) : Promise.resolve({
|
})
|
||||||
|
: Promise.resolve({
|
||||||
data: fields,
|
data: fields,
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
refreshDeps: [associatedKey]
|
{
|
||||||
});
|
refreshDeps: [associatedKey],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data: sourceFields = [] } = useRequest(
|
||||||
const { data: sourceFields = [] } = useRequest(() => {
|
() => {
|
||||||
return sourceName ? api.resource(`collections.fields`).list({
|
return sourceName
|
||||||
|
? api.resource(`collections.fields`).list({
|
||||||
associatedKey: sourceName,
|
associatedKey: sourceName,
|
||||||
filter: sourceFilter,
|
filter: sourceFilter,
|
||||||
}) : Promise.resolve({
|
})
|
||||||
|
: Promise.resolve({
|
||||||
data: [],
|
data: [],
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
refreshDeps: [sourceName]
|
{
|
||||||
});
|
refreshDeps: [sourceName],
|
||||||
|
},
|
||||||
|
);
|
||||||
console.log({ sourceName, sourceFields });
|
console.log({ sourceName, sourceFields });
|
||||||
|
|
||||||
return <FilterGroup showDeleteButton={false} dataSource={value ? toValues(value) : dataSource} onChange={(values) => {
|
return (
|
||||||
|
<FilterGroup
|
||||||
|
showDeleteButton={false}
|
||||||
|
dataSource={value ? toValues(value) : dataSource}
|
||||||
|
onChange={values => {
|
||||||
console.log(values);
|
console.log(values);
|
||||||
onChange(toFilter(values));
|
onChange(toFilter(values));
|
||||||
}} {...restProps} sourceFields={sourceFields} fields={data.filter(item => item.filterable)}/>
|
}}
|
||||||
|
{...restProps}
|
||||||
|
sourceFields={sourceFields}
|
||||||
|
fields={data.filter(item => item.filterable)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Filter;
|
export default Filter;
|
||||||
|
@ -30,7 +30,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const insert = (index: number, obj: T) => {
|
const insert = (index: number, obj: T) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const temp = [...l];
|
const temp = [...l];
|
||||||
temp.splice(index, 0, obj);
|
temp.splice(index, 0, obj);
|
||||||
setKey(index);
|
setKey(index);
|
||||||
@ -40,10 +40,11 @@ export default <T>(initialValue: T[]) => {
|
|||||||
|
|
||||||
const getAll = () => list;
|
const getAll = () => list;
|
||||||
const getKey = (index: number) => keyList.current[index];
|
const getKey = (index: number) => keyList.current[index];
|
||||||
const getIndex = (index: number) => keyList.current.findIndex((ele) => ele === index);
|
const getIndex = (index: number) =>
|
||||||
|
keyList.current.findIndex(ele => ele === index);
|
||||||
|
|
||||||
const merge = (index: number, obj: T[]) => {
|
const merge = (index: number, obj: T[]) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const temp = [...l];
|
const temp = [...l];
|
||||||
obj.forEach((_, i) => {
|
obj.forEach((_, i) => {
|
||||||
setKey(index + i);
|
setKey(index + i);
|
||||||
@ -54,7 +55,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const replace = (index: number, obj: T) => {
|
const replace = (index: number, obj: T) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const temp = [...l];
|
const temp = [...l];
|
||||||
temp[index] = obj;
|
temp[index] = obj;
|
||||||
return temp;
|
return temp;
|
||||||
@ -62,7 +63,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const remove = (index: number) => {
|
const remove = (index: number) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const temp = [...l];
|
const temp = [...l];
|
||||||
temp.splice(index, 1);
|
temp.splice(index, 1);
|
||||||
|
|
||||||
@ -80,14 +81,16 @@ export default <T>(initialValue: T[]) => {
|
|||||||
if (oldIndex === newIndex) {
|
if (oldIndex === newIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const newList = [...l];
|
const newList = [...l];
|
||||||
const temp = newList.filter((_: {}, index: number) => index !== oldIndex);
|
const temp = newList.filter((_: {}, index: number) => index !== oldIndex);
|
||||||
temp.splice(newIndex, 0, newList[oldIndex]);
|
temp.splice(newIndex, 0, newList[oldIndex]);
|
||||||
|
|
||||||
// move keys if necessary
|
// move keys if necessary
|
||||||
try {
|
try {
|
||||||
const keyTemp = keyList.current.filter((_: {}, index: number) => index !== oldIndex);
|
const keyTemp = keyList.current.filter(
|
||||||
|
(_: {}, index: number) => index !== oldIndex,
|
||||||
|
);
|
||||||
keyTemp.splice(newIndex, 0, keyList.current[oldIndex]);
|
keyTemp.splice(newIndex, 0, keyList.current[oldIndex]);
|
||||||
keyList.current = keyTemp;
|
keyList.current = keyTemp;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -99,7 +102,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const push = (obj: T) => {
|
const push = (obj: T) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
setKey(l.length);
|
setKey(l.length);
|
||||||
return l.concat([obj]);
|
return l.concat([obj]);
|
||||||
});
|
});
|
||||||
@ -113,11 +116,11 @@ export default <T>(initialValue: T[]) => {
|
|||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
setList((l) => l.slice(0, l.length - 1));
|
setList(l => l.slice(0, l.length - 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
const unshift = (obj: T) => {
|
const unshift = (obj: T) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
setKey(0);
|
setKey(0);
|
||||||
return [obj].concat(l);
|
return [obj].concat(l);
|
||||||
});
|
});
|
||||||
@ -127,8 +130,8 @@ export default <T>(initialValue: T[]) => {
|
|||||||
result
|
result
|
||||||
.map((item, index) => ({ key: index, item })) // add index into obj
|
.map((item, index) => ({ key: index, item })) // add index into obj
|
||||||
.sort((a, b) => getIndex(a.key) - getIndex(b.key)) // sort based on the index of table
|
.sort((a, b) => getIndex(a.key) - getIndex(b.key)) // sort based on the index of table
|
||||||
.filter((item) => !!item.item) // remove undefined(s)
|
.filter(item => !!item.item) // remove undefined(s)
|
||||||
.map((item) => item.item); // retrive the data
|
.map(item => item.item); // retrive the data
|
||||||
|
|
||||||
const shift = () => {
|
const shift = () => {
|
||||||
// remove keys if necessary
|
// remove keys if necessary
|
||||||
@ -137,7 +140,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
setList((l) => l.slice(1, l.length));
|
setList(l => l.slice(1, l.length));
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { createVirtualBox } from '@formily/react-schema-renderer'
|
import { createVirtualBox } from '@formily/react-schema-renderer';
|
||||||
import { Card } from 'antd'
|
import { Card } from 'antd';
|
||||||
import { CardProps } from 'antd/lib/card'
|
import { CardProps } from 'antd/lib/card';
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const FormBlock = createVirtualBox<CardProps>(
|
export const FormBlock = createVirtualBox<CardProps>(
|
||||||
'block',
|
'block',
|
||||||
@ -11,14 +11,14 @@ export const FormBlock = createVirtualBox<CardProps>(
|
|||||||
<Card className={className} size="small" {...props}>
|
<Card className={className} size="small" {...props}>
|
||||||
{children}
|
{children}
|
||||||
</Card>
|
</Card>
|
||||||
)
|
);
|
||||||
})`
|
})`
|
||||||
margin-bottom: 10px !important;
|
margin-bottom: 10px !important;
|
||||||
&.ant-card {
|
&.ant-card {
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
)
|
);
|
||||||
|
|
||||||
export default FormBlock
|
export default FormBlock;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/card/style/index'
|
import 'antd/lib/card/style/index';
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { createVirtualBox } from '@formily/react-schema-renderer'
|
import { createVirtualBox } from '@formily/react-schema-renderer';
|
||||||
import { Card } from 'antd'
|
import { Card } from 'antd';
|
||||||
import { CardProps } from 'antd/lib/card'
|
import { CardProps } from 'antd/lib/card';
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const FormCard = createVirtualBox<CardProps>(
|
export const FormCard = createVirtualBox<CardProps>(
|
||||||
'card',
|
'card',
|
||||||
@ -11,10 +11,10 @@ export const FormCard = createVirtualBox<CardProps>(
|
|||||||
<Card className={className} size="small" {...props}>
|
<Card className={className} size="small" {...props}>
|
||||||
{children}
|
{children}
|
||||||
</Card>
|
</Card>
|
||||||
)
|
);
|
||||||
})`
|
})`
|
||||||
margin-bottom: 10px !important;
|
margin-bottom: 10px !important;
|
||||||
`
|
`,
|
||||||
)
|
);
|
||||||
|
|
||||||
export default FormCard
|
export default FormCard;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/card/style/index'
|
import 'antd/lib/card/style/index';
|
||||||
|
@ -1,21 +1,30 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { createVirtualBox } from '@formily/react-schema-renderer'
|
import { createVirtualBox } from '@formily/react-schema-renderer';
|
||||||
import { Card } from 'antd'
|
import { Card } from 'antd';
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
import { markdown } from '@/components/views/Field'
|
import { markdown } from '@/components/views/Field';
|
||||||
|
|
||||||
export const FormDescription = createVirtualBox(
|
export const FormDescription = createVirtualBox(
|
||||||
'description',
|
'description',
|
||||||
styled(({ schema = {}, children, className, ...props }) => {
|
styled(({ schema = {}, children, className, ...props }) => {
|
||||||
const { title, tooltip } = schema as any;
|
const { title, tooltip } = schema as any;
|
||||||
console.log({schema})
|
console.log({ schema });
|
||||||
return (
|
return (
|
||||||
<Card title={title} size={'small'} headStyle={{padding: 0}} bodyStyle={{
|
<Card
|
||||||
|
title={title}
|
||||||
|
size={'small'}
|
||||||
|
headStyle={{ padding: 0 }}
|
||||||
|
bodyStyle={{
|
||||||
padding: 0,
|
padding: 0,
|
||||||
}} className={className} {...props}>
|
}}
|
||||||
{typeof tooltip === 'string' && tooltip && <div dangerouslySetInnerHTML={{__html: markdown(tooltip)}}></div>}
|
className={className}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{typeof tooltip === 'string' && tooltip && (
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: markdown(tooltip) }}></div>
|
||||||
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
)
|
);
|
||||||
})`
|
})`
|
||||||
margin-bottom: 24px !important;
|
margin-bottom: 24px !important;
|
||||||
&.ant-card {
|
&.ant-card {
|
||||||
@ -35,7 +44,7 @@ export const FormDescription = createVirtualBox(
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
)
|
);
|
||||||
|
|
||||||
export default FormDescription
|
export default FormDescription;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { createVirtualBox } from '@formily/react-schema-renderer'
|
import { createVirtualBox } from '@formily/react-schema-renderer';
|
||||||
import { Col } from 'antd'
|
import { Col } from 'antd';
|
||||||
import { ColProps } from 'antd/lib/grid'
|
import { ColProps } from 'antd/lib/grid';
|
||||||
|
|
||||||
export const FormGridCol = createVirtualBox<ColProps>('grid-col', props => {
|
export const FormGridCol = createVirtualBox<ColProps>('grid-col', props => {
|
||||||
return <Col {...props}>{props.children}</Col>
|
return <Col {...props}>{props.children}</Col>;
|
||||||
})
|
});
|
||||||
|
|
||||||
export default FormGridCol
|
export default FormGridCol;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/col/style/index'
|
import 'antd/lib/col/style/index';
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { AntdSchemaFieldAdaptor, pickFormItemProps } from '@formily/antd'
|
import { AntdSchemaFieldAdaptor, pickFormItemProps } from '@formily/antd';
|
||||||
import { createVirtualBox } from '@formily/react-schema-renderer'
|
import { createVirtualBox } from '@formily/react-schema-renderer';
|
||||||
import { Row } from 'antd'
|
import { Row } from 'antd';
|
||||||
import { RowProps } from 'antd/lib/grid'
|
import { RowProps } from 'antd/lib/grid';
|
||||||
import { FormItemProps as ItemProps } from 'antd/lib/form'
|
import { FormItemProps as ItemProps } from 'antd/lib/form';
|
||||||
import { IItemProps } from '../types'
|
import { IItemProps } from '../types';
|
||||||
|
|
||||||
export const FormGridRow = createVirtualBox<RowProps & ItemProps & IItemProps>(
|
export const FormGridRow = createVirtualBox<RowProps & ItemProps & IItemProps>(
|
||||||
'grid-row',
|
'grid-row',
|
||||||
props => {
|
props => {
|
||||||
const { title, label } = props
|
const { title, label } = props;
|
||||||
const grids = <Row {...props}>{props.children}</Row>
|
const grids = <Row {...props}>{props.children}</Row>;
|
||||||
if (title || label) {
|
if (title || label) {
|
||||||
return (
|
return (
|
||||||
<AntdSchemaFieldAdaptor {...pickFormItemProps(props)}>
|
<AntdSchemaFieldAdaptor {...pickFormItemProps(props)}>
|
||||||
{grids}
|
{grids}
|
||||||
</AntdSchemaFieldAdaptor>
|
</AntdSchemaFieldAdaptor>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
return grids
|
return grids;
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
export default FormGridRow
|
export default FormGridRow;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/row/style/index'
|
import 'antd/lib/row/style/index';
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react';
|
||||||
import {
|
import {
|
||||||
AntdSchemaFieldAdaptor,
|
AntdSchemaFieldAdaptor,
|
||||||
pickFormItemProps,
|
pickFormItemProps,
|
||||||
pickNotFormItemProps
|
pickNotFormItemProps,
|
||||||
} from '@formily/antd'
|
} from '@formily/antd';
|
||||||
import { createVirtualBox } from '@formily/react-schema-renderer'
|
import { createVirtualBox } from '@formily/react-schema-renderer';
|
||||||
import { toArr } from '@formily/shared'
|
import { toArr } from '@formily/shared';
|
||||||
import { Row, Col } from 'antd'
|
import { Row, Col } from 'antd';
|
||||||
import { FormItemProps as ItemProps } from 'antd/lib/form'
|
import { FormItemProps as ItemProps } from 'antd/lib/form';
|
||||||
import { IFormItemGridProps, IItemProps } from '../types'
|
import { IFormItemGridProps, IItemProps } from '../types';
|
||||||
import { normalizeCol } from '../shared'
|
import { normalizeCol } from '../shared';
|
||||||
|
|
||||||
export const FormItemGrid = createVirtualBox<
|
export const FormItemGrid = createVirtualBox<
|
||||||
React.PropsWithChildren<IFormItemGridProps & ItemProps & IItemProps>
|
React.PropsWithChildren<IFormItemGridProps & ItemProps & IItemProps>
|
||||||
@ -18,16 +18,16 @@ export const FormItemGrid = createVirtualBox<
|
|||||||
cols: rawCols,
|
cols: rawCols,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
title,
|
title,
|
||||||
label
|
label,
|
||||||
} = props
|
} = props;
|
||||||
const formItemProps = pickFormItemProps(props)
|
const formItemProps = pickFormItemProps(props);
|
||||||
const gridProps = pickNotFormItemProps(props)
|
const gridProps = pickNotFormItemProps(props);
|
||||||
const children = toArr(props.children)
|
const children = toArr(props.children);
|
||||||
const cols = toArr(rawCols).map(col => normalizeCol(col))
|
const cols = toArr(rawCols).map(col => normalizeCol(col));
|
||||||
const childNum = children.length
|
const childNum = children.length;
|
||||||
|
|
||||||
if (cols.length < childNum) {
|
if (cols.length < childNum) {
|
||||||
let offset: number = childNum - cols.length
|
let offset: number = childNum - cols.length;
|
||||||
let lastSpan: number =
|
let lastSpan: number =
|
||||||
24 -
|
24 -
|
||||||
cols.reduce((buf, col) => {
|
cols.reduce((buf, col) => {
|
||||||
@ -35,10 +35,10 @@ export const FormItemGrid = createVirtualBox<
|
|||||||
buf +
|
buf +
|
||||||
Number(col.span ? col.span : 0) +
|
Number(col.span ? col.span : 0) +
|
||||||
Number(col.offset ? col.offset : 0)
|
Number(col.offset ? col.offset : 0)
|
||||||
)
|
);
|
||||||
}, 0)
|
}, 0);
|
||||||
for (let i = 0; i < offset; i++) {
|
for (let i = 0; i < offset; i++) {
|
||||||
cols.push({ span: Math.floor(lastSpan / offset) })
|
cols.push({ span: Math.floor(lastSpan / offset) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const grids = (
|
const grids = (
|
||||||
@ -48,21 +48,21 @@ export const FormItemGrid = createVirtualBox<
|
|||||||
? buf.concat(
|
? buf.concat(
|
||||||
<Col key={key} {...cols[key]}>
|
<Col key={key} {...cols[key]}>
|
||||||
{child}
|
{child}
|
||||||
</Col>
|
</Col>,
|
||||||
)
|
)
|
||||||
: buf
|
: buf;
|
||||||
}, [])}
|
}, [])}
|
||||||
</Row>
|
</Row>
|
||||||
)
|
);
|
||||||
|
|
||||||
if (title || label) {
|
if (title || label) {
|
||||||
return (
|
return (
|
||||||
<AntdSchemaFieldAdaptor {...formItemProps}>
|
<AntdSchemaFieldAdaptor {...formItemProps}>
|
||||||
{grids}
|
{grids}
|
||||||
</AntdSchemaFieldAdaptor>
|
</AntdSchemaFieldAdaptor>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
return <Fragment>{grids}</Fragment>
|
return <Fragment>{grids}</Fragment>;
|
||||||
})
|
});
|
||||||
|
|
||||||
export default FormItemGrid
|
export default FormItemGrid;
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
import 'antd/lib/row/style/index'
|
import 'antd/lib/row/style/index';
|
||||||
import 'antd/lib/col/style/index'
|
import 'antd/lib/col/style/index';
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormItemDeepProvider, useDeepFormItem } from '@formily/antd'
|
import { FormItemDeepProvider, useDeepFormItem } from '@formily/antd';
|
||||||
import { createVirtualBox } from '@formily/react-schema-renderer'
|
import { createVirtualBox } from '@formily/react-schema-renderer';
|
||||||
import cls from 'classnames'
|
import cls from 'classnames';
|
||||||
import { IFormItemTopProps } from '../types'
|
import { IFormItemTopProps } from '../types';
|
||||||
|
|
||||||
export const FormLayout = createVirtualBox<IFormItemTopProps>(
|
export const FormLayout = createVirtualBox<IFormItemTopProps>(
|
||||||
'layout',
|
'layout',
|
||||||
props => {
|
props => {
|
||||||
const { inline } = useDeepFormItem()
|
const { inline } = useDeepFormItem();
|
||||||
const isInline = props.inline || inline
|
const isInline = props.inline || inline;
|
||||||
const children =
|
const children =
|
||||||
isInline || props.className || props.style ? (
|
isInline || props.className || props.style ? (
|
||||||
<div
|
<div
|
||||||
className={cls(props.className, {
|
className={cls(props.className, {
|
||||||
'ant-form ant-form-inline': isInline
|
'ant-form ant-form-inline': isInline,
|
||||||
})}
|
})}
|
||||||
style={props.style}
|
style={props.style}
|
||||||
>
|
>
|
||||||
@ -21,9 +21,9 @@ export const FormLayout = createVirtualBox<IFormItemTopProps>(
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
props.children
|
props.children
|
||||||
)
|
);
|
||||||
return <FormItemDeepProvider {...props}>{children}</FormItemDeepProvider>
|
return <FormItemDeepProvider {...props}>{children}</FormItemDeepProvider>;
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
export default FormLayout
|
export default FormLayout;
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import { MegaLayout, FormMegaLayout } from '@formily/antd'
|
import { MegaLayout, FormMegaLayout } from '@formily/antd';
|
||||||
|
|
||||||
export {
|
export { MegaLayout, FormMegaLayout };
|
||||||
MegaLayout,
|
|
||||||
FormMegaLayout,
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FormSlot } from '@formily/react-schema-renderer'
|
import { FormSlot } from '@formily/react-schema-renderer';
|
||||||
|
|
||||||
export { FormSlot }
|
export { FormSlot };
|
||||||
|
|
||||||
export default FormSlot
|
export default FormSlot;
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
import React, { useRef, Fragment, useEffect } from 'react'
|
import React, { useRef, Fragment, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
createControllerBox,
|
createControllerBox,
|
||||||
ISchemaVirtualFieldComponentProps,
|
ISchemaVirtualFieldComponentProps,
|
||||||
createEffectHook,
|
createEffectHook,
|
||||||
useFormEffects,
|
useFormEffects,
|
||||||
useFieldState,
|
useFieldState,
|
||||||
IVirtualBoxProps
|
IVirtualBoxProps,
|
||||||
} from '@formily/react-schema-renderer'
|
} from '@formily/react-schema-renderer';
|
||||||
import { toArr } from '@formily/shared'
|
import { toArr } from '@formily/shared';
|
||||||
import { Steps } from 'antd'
|
import { Steps } from 'antd';
|
||||||
import { createMatchUpdate } from '../shared'
|
import { createMatchUpdate } from '../shared';
|
||||||
import { IFormStep } from '../types'
|
import { IFormStep } from '../types';
|
||||||
|
|
||||||
enum StateMap {
|
enum StateMap {
|
||||||
ON_FORM_STEP_NEXT = 'onFormStepNext',
|
ON_FORM_STEP_NEXT = 'onFormStepNext',
|
||||||
ON_FORM_STEP_PREVIOUS = 'onFormStepPrevious',
|
ON_FORM_STEP_PREVIOUS = 'onFormStepPrevious',
|
||||||
ON_FORM_STEP_GO_TO = 'onFormStepGoto',
|
ON_FORM_STEP_GO_TO = 'onFormStepGoto',
|
||||||
ON_FORM_STEP_CURRENT_CHANGE = 'onFormStepCurrentChange',
|
ON_FORM_STEP_CURRENT_CHANGE = 'onFormStepCurrentChange',
|
||||||
ON_FORM_STEP_DATA_SOURCE_CHANGED = 'onFormStepDataSourceChanged'
|
ON_FORM_STEP_DATA_SOURCE_CHANGED = 'onFormStepDataSourceChanged',
|
||||||
}
|
}
|
||||||
const EffectHooks = {
|
const EffectHooks = {
|
||||||
onStepNext$: createEffectHook<void>(StateMap.ON_FORM_STEP_NEXT),
|
onStepNext$: createEffectHook<void>(StateMap.ON_FORM_STEP_NEXT),
|
||||||
onStepPrevious$: createEffectHook<void>(StateMap.ON_FORM_STEP_PREVIOUS),
|
onStepPrevious$: createEffectHook<void>(StateMap.ON_FORM_STEP_PREVIOUS),
|
||||||
onStepGoto$: createEffectHook<void>(StateMap.ON_FORM_STEP_GO_TO),
|
onStepGoto$: createEffectHook<void>(StateMap.ON_FORM_STEP_GO_TO),
|
||||||
onStepCurrentChange$: createEffectHook<{
|
onStepCurrentChange$: createEffectHook<{
|
||||||
value: number
|
value: number;
|
||||||
preValue: number
|
preValue: number;
|
||||||
}>(StateMap.ON_FORM_STEP_CURRENT_CHANGE)
|
}>(StateMap.ON_FORM_STEP_CURRENT_CHANGE),
|
||||||
}
|
};
|
||||||
|
|
||||||
type ExtendsProps = StateMap & typeof EffectHooks
|
type ExtendsProps = StateMap & typeof EffectHooks;
|
||||||
|
|
||||||
export const FormStep: React.FC<IVirtualBoxProps<IFormStep>> &
|
export const FormStep: React.FC<IVirtualBoxProps<IFormStep>> &
|
||||||
ExtendsProps = createControllerBox<IFormStep>(
|
ExtendsProps = createControllerBox<IFormStep>(
|
||||||
@ -39,54 +39,54 @@ export const FormStep: React.FC<IVirtualBoxProps<IFormStep>> &
|
|||||||
schema,
|
schema,
|
||||||
path,
|
path,
|
||||||
name,
|
name,
|
||||||
children
|
children,
|
||||||
}: ISchemaVirtualFieldComponentProps) => {
|
}: ISchemaVirtualFieldComponentProps) => {
|
||||||
const { dataSource, ...stepProps } = schema.getExtendsComponentProps()
|
const { dataSource, ...stepProps } = schema.getExtendsComponentProps();
|
||||||
const [{ current }, setFieldState] = useFieldState({
|
const [{ current }, setFieldState] = useFieldState({
|
||||||
current: stepProps.current || 0
|
current: stepProps.current || 0,
|
||||||
})
|
});
|
||||||
const ref = useRef(current)
|
const ref = useRef(current);
|
||||||
const itemsRef = useRef([])
|
const itemsRef = useRef([]);
|
||||||
itemsRef.current = toArr(dataSource)
|
itemsRef.current = toArr(dataSource);
|
||||||
|
|
||||||
const matchUpdate = createMatchUpdate(name, path)
|
const matchUpdate = createMatchUpdate(name, path);
|
||||||
|
|
||||||
const update = (cur: number) => {
|
const update = (cur: number) => {
|
||||||
form.notify(StateMap.ON_FORM_STEP_CURRENT_CHANGE, {
|
form.notify(StateMap.ON_FORM_STEP_CURRENT_CHANGE, {
|
||||||
path,
|
path,
|
||||||
name,
|
name,
|
||||||
value: cur,
|
value: cur,
|
||||||
preValue: current
|
preValue: current,
|
||||||
})
|
});
|
||||||
setFieldState({
|
setFieldState({
|
||||||
current: cur
|
current: cur,
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
form.notify(StateMap.ON_FORM_STEP_DATA_SOURCE_CHANGED, {
|
form.notify(StateMap.ON_FORM_STEP_DATA_SOURCE_CHANGED, {
|
||||||
path,
|
path,
|
||||||
name,
|
name,
|
||||||
value: itemsRef.current
|
value: itemsRef.current,
|
||||||
})
|
});
|
||||||
}, [itemsRef.current.length])
|
}, [itemsRef.current.length]);
|
||||||
|
|
||||||
useFormEffects(($, { setFieldState }) => {
|
useFormEffects(($, { setFieldState }) => {
|
||||||
const updateFields = () => {
|
const updateFields = () => {
|
||||||
itemsRef.current.forEach(({ name }, index) => {
|
itemsRef.current.forEach(({ name }, index) => {
|
||||||
setFieldState(name, (state: any) => {
|
setFieldState(name, (state: any) => {
|
||||||
state.display = index === current
|
state.display = index === current;
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
updateFields()
|
updateFields();
|
||||||
$(StateMap.ON_FORM_STEP_DATA_SOURCE_CHANGED).subscribe(
|
$(StateMap.ON_FORM_STEP_DATA_SOURCE_CHANGED).subscribe(
|
||||||
({ name, path }) => {
|
({ name, path }) => {
|
||||||
matchUpdate(name, path, () => {
|
matchUpdate(name, path, () => {
|
||||||
updateFields()
|
updateFields();
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
$(StateMap.ON_FORM_STEP_CURRENT_CHANGE).subscribe(
|
$(StateMap.ON_FORM_STEP_CURRENT_CHANGE).subscribe(
|
||||||
({ value, name, path }: any = {}) => {
|
({ value, name, path }: any = {}) => {
|
||||||
@ -95,16 +95,16 @@ export const FormStep: React.FC<IVirtualBoxProps<IFormStep>> &
|
|||||||
itemsRef.current.forEach(({ name }, index) => {
|
itemsRef.current.forEach(({ name }, index) => {
|
||||||
if (!name)
|
if (!name)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'FormStep dataSource must include `name` property'
|
'FormStep dataSource must include `name` property',
|
||||||
)
|
);
|
||||||
setFieldState(name, (state: any) => {
|
setFieldState(name, (state: any) => {
|
||||||
state.display = index === value
|
state.display = index === value;
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
$(StateMap.ON_FORM_STEP_NEXT).subscribe(({ name, path }: any = {}) => {
|
$(StateMap.ON_FORM_STEP_NEXT).subscribe(({ name, path }: any = {}) => {
|
||||||
matchUpdate(name, path, () => {
|
matchUpdate(name, path, () => {
|
||||||
@ -113,45 +113,45 @@ export const FormStep: React.FC<IVirtualBoxProps<IFormStep>> &
|
|||||||
update(
|
update(
|
||||||
ref.current + 1 > itemsRef.current.length - 1
|
ref.current + 1 > itemsRef.current.length - 1
|
||||||
? ref.current
|
? ref.current
|
||||||
: ref.current + 1
|
: ref.current + 1,
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
$(StateMap.ON_FORM_STEP_PREVIOUS).subscribe(
|
$(StateMap.ON_FORM_STEP_PREVIOUS).subscribe(
|
||||||
({ name, path }: any = {}) => {
|
({ name, path }: any = {}) => {
|
||||||
matchUpdate(name, path, () => {
|
matchUpdate(name, path, () => {
|
||||||
update(ref.current - 1 < 0 ? ref.current : ref.current - 1)
|
update(ref.current - 1 < 0 ? ref.current : ref.current - 1);
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
$(StateMap.ON_FORM_STEP_GO_TO).subscribe(
|
$(StateMap.ON_FORM_STEP_GO_TO).subscribe(
|
||||||
({ name, path, value }: any = {}) => {
|
({ name, path, value }: any = {}) => {
|
||||||
matchUpdate(name, path, () => {
|
matchUpdate(name, path, () => {
|
||||||
if (!(value < 0 || value > itemsRef.current.length)) {
|
if (!(value < 0 || value > itemsRef.current.length)) {
|
||||||
update(value)
|
update(value);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
ref.current = current
|
ref.current = current;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Steps {...stepProps} current={current}>
|
<Steps {...stepProps} current={current}>
|
||||||
{itemsRef.current.map((props, key) => {
|
{itemsRef.current.map((props, key) => {
|
||||||
return <Steps.Step {...props} key={key} />
|
return <Steps.Step {...props} key={key} />;
|
||||||
})}
|
})}
|
||||||
</Steps>{' '}
|
</Steps>{' '}
|
||||||
{children}
|
{children}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
) as any
|
) as any;
|
||||||
|
|
||||||
Object.assign(FormStep, StateMap, EffectHooks)
|
Object.assign(FormStep, StateMap, EffectHooks);
|
||||||
|
|
||||||
export default FormStep
|
export default FormStep;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/steps/style/index'
|
import 'antd/lib/steps/style/index';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { Fragment, useEffect, useRef } from 'react'
|
import React, { Fragment, useEffect, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
createControllerBox,
|
createControllerBox,
|
||||||
ISchemaVirtualFieldComponentProps,
|
ISchemaVirtualFieldComponentProps,
|
||||||
@ -8,140 +8,156 @@ import {
|
|||||||
FormEffectHooks,
|
FormEffectHooks,
|
||||||
SchemaField,
|
SchemaField,
|
||||||
FormPath,
|
FormPath,
|
||||||
IVirtualBoxProps
|
IVirtualBoxProps,
|
||||||
} from '@formily/react-schema-renderer'
|
} from '@formily/react-schema-renderer';
|
||||||
import { Tabs, Badge } from 'antd'
|
import { Tabs, Badge } from 'antd';
|
||||||
import { TabPaneProps } from 'antd/lib/tabs'
|
import { TabPaneProps } from 'antd/lib/tabs';
|
||||||
import { IFormTab } from '../types'
|
import { IFormTab } from '../types';
|
||||||
import { createMatchUpdate } from '../shared'
|
import { createMatchUpdate } from '../shared';
|
||||||
|
|
||||||
enum StateMap {
|
enum StateMap {
|
||||||
ON_FORM_TAB_ACTIVE_KEY_CHANGE = 'onFormTabActiveKeyChange'
|
ON_FORM_TAB_ACTIVE_KEY_CHANGE = 'onFormTabActiveKeyChange',
|
||||||
}
|
}
|
||||||
|
|
||||||
const { onFormChange$ } = FormEffectHooks
|
const { onFormChange$ } = FormEffectHooks;
|
||||||
|
|
||||||
const EffectHooks = {
|
const EffectHooks = {
|
||||||
onTabActiveKeyChange$: createEffectHook<{
|
onTabActiveKeyChange$: createEffectHook<{
|
||||||
name?: string
|
name?: string;
|
||||||
path?: string
|
path?: string;
|
||||||
value?: any
|
value?: any;
|
||||||
}>(StateMap.ON_FORM_TAB_ACTIVE_KEY_CHANGE)
|
}>(StateMap.ON_FORM_TAB_ACTIVE_KEY_CHANGE),
|
||||||
}
|
};
|
||||||
|
|
||||||
const parseTabItems = (items: any, hiddenKeys?: string[]) => {
|
const parseTabItems = (items: any, hiddenKeys?: string[]) => {
|
||||||
return items.reduce((buf: any, { schema, key }) => {
|
return items.reduce((buf: any, { schema, key }) => {
|
||||||
if (Array.isArray(hiddenKeys)) {
|
if (Array.isArray(hiddenKeys)) {
|
||||||
if (hiddenKeys.includes(key)) {
|
if (hiddenKeys.includes(key)) {
|
||||||
return buf
|
return buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (schema.getExtendsComponent() === 'tabpane') {
|
if (schema.getExtendsComponent() === 'tabpane') {
|
||||||
return buf.concat({
|
return buf.concat({
|
||||||
props: schema.getExtendsComponentProps(),
|
props: schema.getExtendsComponentProps(),
|
||||||
schema,
|
schema,
|
||||||
key
|
key,
|
||||||
})
|
});
|
||||||
}
|
|
||||||
return buf
|
|
||||||
}, [])
|
|
||||||
}
|
}
|
||||||
|
return buf;
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
const parseDefaultActiveKey = (hiddenKeys: Array<string> = [], items: any, defaultActiveKey) => {
|
const parseDefaultActiveKey = (
|
||||||
if(!hiddenKeys.includes(defaultActiveKey))return defaultActiveKey
|
hiddenKeys: Array<string> = [],
|
||||||
|
items: any,
|
||||||
|
defaultActiveKey,
|
||||||
|
) => {
|
||||||
|
if (!hiddenKeys.includes(defaultActiveKey)) return defaultActiveKey;
|
||||||
|
|
||||||
const index = items.findIndex(item => !hiddenKeys.includes(item.key))
|
const index = items.findIndex(item => !hiddenKeys.includes(item.key));
|
||||||
return index >= 0 ? items[index].key : ''
|
return index >= 0 ? items[index].key : '';
|
||||||
}
|
};
|
||||||
|
|
||||||
const parseChildrenErrors = (errors: any, target: string) => {
|
const parseChildrenErrors = (errors: any, target: string) => {
|
||||||
return errors.filter(({ path }) => {
|
return errors.filter(({ path }) => {
|
||||||
return FormPath.parse(path).includes(target)
|
return FormPath.parse(path).includes(target);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const addErrorBadge = (
|
const addErrorBadge = (
|
||||||
tab: React.ReactNode,
|
tab: React.ReactNode,
|
||||||
currentPath: FormPath,
|
currentPath: FormPath,
|
||||||
childrenErrors: any[]
|
childrenErrors: any[],
|
||||||
) => {
|
) => {
|
||||||
const currentErrors = childrenErrors.filter(({ path }) => {
|
const currentErrors = childrenErrors.filter(({ path }) => {
|
||||||
return FormPath.parse(path).includes(currentPath)
|
return FormPath.parse(path).includes(currentPath);
|
||||||
})
|
});
|
||||||
if (currentErrors.length > 0) {
|
if (currentErrors.length > 0) {
|
||||||
return (
|
return (
|
||||||
<Badge offset={[12, 0]} count={currentErrors.length}>
|
<Badge offset={[12, 0]} count={currentErrors.length}>
|
||||||
{tab}
|
{tab}
|
||||||
</Badge>
|
</Badge>
|
||||||
)
|
);
|
||||||
}
|
|
||||||
return tab
|
|
||||||
}
|
}
|
||||||
|
return tab;
|
||||||
|
};
|
||||||
|
|
||||||
type ExtendsProps = StateMap &
|
type ExtendsProps = StateMap &
|
||||||
typeof EffectHooks & {
|
typeof EffectHooks & {
|
||||||
TabPane: React.FC<IVirtualBoxProps<TabPaneProps>>
|
TabPane: React.FC<IVirtualBoxProps<TabPaneProps>>;
|
||||||
}
|
};
|
||||||
|
|
||||||
type ExtendsState = {
|
type ExtendsState = {
|
||||||
activeKey?: string
|
activeKey?: string;
|
||||||
childrenErrors?: any
|
childrenErrors?: any;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const FormTab: React.FC<IVirtualBoxProps<IFormTab>> &
|
export const FormTab: React.FC<IVirtualBoxProps<IFormTab>> &
|
||||||
ExtendsProps = createControllerBox<IFormTab>(
|
ExtendsProps = createControllerBox<IFormTab>(
|
||||||
'tab',
|
'tab',
|
||||||
({ form, schema, name, path }: ISchemaVirtualFieldComponentProps) => {
|
({ form, schema, name, path }: ISchemaVirtualFieldComponentProps) => {
|
||||||
const orderProperties = schema.getOrderProperties()
|
const orderProperties = schema.getOrderProperties();
|
||||||
let { hiddenKeys, defaultActiveKey, ...componentProps } = schema.getExtendsComponentProps()
|
let {
|
||||||
hiddenKeys = hiddenKeys || []
|
hiddenKeys,
|
||||||
|
defaultActiveKey,
|
||||||
|
...componentProps
|
||||||
|
} = schema.getExtendsComponentProps();
|
||||||
|
hiddenKeys = hiddenKeys || [];
|
||||||
const [{ activeKey, childrenErrors }, setFieldState] = useFieldState<
|
const [{ activeKey, childrenErrors }, setFieldState] = useFieldState<
|
||||||
ExtendsState
|
ExtendsState
|
||||||
>({
|
>({
|
||||||
activeKey: parseDefaultActiveKey(hiddenKeys, orderProperties, defaultActiveKey),
|
activeKey: parseDefaultActiveKey(
|
||||||
childrenErrors: []
|
hiddenKeys,
|
||||||
})
|
orderProperties,
|
||||||
const itemsRef = useRef([])
|
defaultActiveKey,
|
||||||
itemsRef.current = parseTabItems(orderProperties, hiddenKeys)
|
),
|
||||||
|
childrenErrors: [],
|
||||||
|
});
|
||||||
|
const itemsRef = useRef([]);
|
||||||
|
itemsRef.current = parseTabItems(orderProperties, hiddenKeys);
|
||||||
const update = (cur: string) => {
|
const update = (cur: string) => {
|
||||||
form.notify(StateMap.ON_FORM_TAB_ACTIVE_KEY_CHANGE, {
|
form.notify(StateMap.ON_FORM_TAB_ACTIVE_KEY_CHANGE, {
|
||||||
name,
|
name,
|
||||||
path,
|
path,
|
||||||
value: cur
|
value: cur,
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
const matchUpdate = createMatchUpdate(name, path)
|
const matchUpdate = createMatchUpdate(name, path);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (Array.isArray(hiddenKeys)) {
|
if (Array.isArray(hiddenKeys)) {
|
||||||
setFieldState({
|
setFieldState({
|
||||||
activeKey: parseDefaultActiveKey(hiddenKeys, orderProperties, defaultActiveKey)
|
activeKey: parseDefaultActiveKey(
|
||||||
})
|
hiddenKeys,
|
||||||
|
orderProperties,
|
||||||
|
defaultActiveKey,
|
||||||
|
),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [hiddenKeys.length])
|
}, [hiddenKeys.length]);
|
||||||
useFormEffects(({ hasChanged }) => {
|
useFormEffects(({ hasChanged }) => {
|
||||||
onFormChange$().subscribe(formState => {
|
onFormChange$().subscribe(formState => {
|
||||||
const errorsChanged = hasChanged(formState, 'errors')
|
const errorsChanged = hasChanged(formState, 'errors');
|
||||||
if (errorsChanged) {
|
if (errorsChanged) {
|
||||||
setFieldState({
|
setFieldState({
|
||||||
childrenErrors: parseChildrenErrors(formState.errors, path)
|
childrenErrors: parseChildrenErrors(formState.errors, path),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
EffectHooks.onTabActiveKeyChange$().subscribe(
|
EffectHooks.onTabActiveKeyChange$().subscribe(
|
||||||
({ value, name, path }: any = {}) => {
|
({ value, name, path }: any = {}) => {
|
||||||
if(!itemsRef.current.map(item => item.key).includes(value))return
|
if (!itemsRef.current.map(item => item.key).includes(value)) return;
|
||||||
matchUpdate(name, path, () => {
|
matchUpdate(name, path, () => {
|
||||||
setFieldState({
|
setFieldState({
|
||||||
activeKey: value
|
activeKey: value,
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
return (
|
return (
|
||||||
<Tabs {...componentProps} activeKey={activeKey} onChange={update}>
|
<Tabs {...componentProps} activeKey={activeKey} onChange={update}>
|
||||||
{itemsRef.current.map(({ props, schema, key }) => {
|
{itemsRef.current.map(({ props, schema, key }) => {
|
||||||
const currentPath = FormPath.parse(path).concat(key)
|
const currentPath = FormPath.parse(path).concat(key);
|
||||||
return (
|
return (
|
||||||
<Tabs.TabPane
|
<Tabs.TabPane
|
||||||
{...props}
|
{...props}
|
||||||
@ -159,20 +175,20 @@ export const FormTab: React.FC<IVirtualBoxProps<IFormTab>> &
|
|||||||
onlyRenderProperties
|
onlyRenderProperties
|
||||||
/>
|
/>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
)
|
);
|
||||||
}
|
},
|
||||||
) as any
|
) as any;
|
||||||
|
|
||||||
FormTab.TabPane = createControllerBox<TabPaneProps>(
|
FormTab.TabPane = createControllerBox<TabPaneProps>(
|
||||||
'tabpane',
|
'tabpane',
|
||||||
({ children }) => {
|
({ children }) => {
|
||||||
return <Fragment>{children}</Fragment>
|
return <Fragment>{children}</Fragment>;
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
Object.assign(FormTab, StateMap, EffectHooks)
|
Object.assign(FormTab, StateMap, EffectHooks);
|
||||||
|
|
||||||
export default FormTab
|
export default FormTab;
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
import 'antd/lib/tabs/style/index'
|
import 'antd/lib/tabs/style/index';
|
||||||
import 'antd/lib/badge/style/index'
|
import 'antd/lib/badge/style/index';
|
||||||
|
@ -1,64 +1,64 @@
|
|||||||
import React, { useRef, useLayoutEffect } from 'react'
|
import React, { useRef, useLayoutEffect } from 'react';
|
||||||
import { createControllerBox, Schema } from '@formily/react-schema-renderer'
|
import { createControllerBox, Schema } from '@formily/react-schema-renderer';
|
||||||
import { IFormTextBox } from '../types'
|
import { IFormTextBox } from '../types';
|
||||||
import { toArr } from '@formily/shared'
|
import { toArr } from '@formily/shared';
|
||||||
import { FormItemProps as ItemProps } from 'antd/lib/form'
|
import { FormItemProps as ItemProps } from 'antd/lib/form';
|
||||||
import { version } from 'antd'
|
import { version } from 'antd';
|
||||||
import { AntdSchemaFieldAdaptor, pickFormItemProps } from '@formily/antd'
|
import { AntdSchemaFieldAdaptor, pickFormItemProps } from '@formily/antd';
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
|
|
||||||
const isV4 = /^4\./.test(version)
|
const isV4 = /^4\./.test(version);
|
||||||
|
|
||||||
export const FormTextBox = createControllerBox<IFormTextBox & ItemProps>(
|
export const FormTextBox = createControllerBox<IFormTextBox & ItemProps>(
|
||||||
'text-box',
|
'text-box',
|
||||||
styled(({ props, form, className, children }) => {
|
styled(({ props, form, className, children }) => {
|
||||||
const schema = new Schema(props)
|
const schema = new Schema(props);
|
||||||
const mergeProps = schema.getExtendsComponentProps()
|
const mergeProps = schema.getExtendsComponentProps();
|
||||||
const { title, label, text, gutter, style } = Object.assign(
|
const { title, label, text, gutter, style } = Object.assign(
|
||||||
{
|
{
|
||||||
gutter: 5
|
gutter: 5,
|
||||||
},
|
},
|
||||||
mergeProps
|
mergeProps,
|
||||||
)
|
);
|
||||||
const formItemProps = pickFormItemProps(mergeProps)
|
const formItemProps = pickFormItemProps(mergeProps);
|
||||||
const ref: React.RefObject<HTMLDivElement> = useRef()
|
const ref: React.RefObject<HTMLDivElement> = useRef();
|
||||||
const arrChildren = toArr(children)
|
const arrChildren = toArr(children);
|
||||||
const split = text.split('%s')
|
const split = text.split('%s');
|
||||||
let index = 0
|
let index = 0;
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
const elements = ref.current.querySelectorAll('.text-box-field')
|
const elements = ref.current.querySelectorAll('.text-box-field');
|
||||||
const syncLayouts = Array.prototype.map.call(
|
const syncLayouts = Array.prototype.map.call(
|
||||||
elements,
|
elements,
|
||||||
(el: HTMLElement) => {
|
(el: HTMLElement) => {
|
||||||
return [
|
return [
|
||||||
el,
|
el,
|
||||||
() => {
|
() => {
|
||||||
const ctrl = el.querySelector('.ant-form-item-children')
|
const ctrl = el.querySelector('.ant-form-item-children');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (ctrl) {
|
if (ctrl) {
|
||||||
const editable = form.getFormState(state => state.editable)
|
const editable = form.getFormState(state => state.editable);
|
||||||
el.style.width = editable
|
el.style.width = editable
|
||||||
? ctrl.getBoundingClientRect().width + 'px'
|
? ctrl.getBoundingClientRect().width + 'px'
|
||||||
: 'auto'
|
: 'auto';
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
syncLayouts.forEach(([el, handler]) => {
|
syncLayouts.forEach(([el, handler]) => {
|
||||||
handler()
|
handler();
|
||||||
el.addEventListener('DOMSubtreeModified', handler)
|
el.addEventListener('DOMSubtreeModified', handler);
|
||||||
})
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
syncLayouts.forEach(([el, handler]) => {
|
syncLayouts.forEach(([el, handler]) => {
|
||||||
el.removeEventListener('DOMSubtreeModified', handler)
|
el.removeEventListener('DOMSubtreeModified', handler);
|
||||||
})
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}, []);
|
||||||
}, [])
|
|
||||||
const newChildren = split.reduce((buf, item, key) => {
|
const newChildren = split.reduce((buf, item, key) => {
|
||||||
return buf.concat(
|
return buf.concat(
|
||||||
item ? (
|
item ? (
|
||||||
@ -68,7 +68,7 @@ export const FormTextBox = createControllerBox<IFormTextBox & ItemProps>(
|
|||||||
style={{
|
style={{
|
||||||
marginRight: gutter / 2,
|
marginRight: gutter / 2,
|
||||||
marginLeft: gutter / 2,
|
marginLeft: gutter / 2,
|
||||||
...style
|
...style,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item}
|
{item}
|
||||||
@ -78,29 +78,29 @@ export const FormTextBox = createControllerBox<IFormTextBox & ItemProps>(
|
|||||||
<div key={index++} className="text-box-field">
|
<div key={index++} className="text-box-field">
|
||||||
{arrChildren[key]}
|
{arrChildren[key]}
|
||||||
</div>
|
</div>
|
||||||
) : null
|
) : null,
|
||||||
)
|
);
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
const textChildren = (
|
const textChildren = (
|
||||||
<div
|
<div
|
||||||
className={`${className} ${mergeProps.className}`}
|
className={`${className} ${mergeProps.className}`}
|
||||||
style={{
|
style={{
|
||||||
marginRight: -gutter / 2,
|
marginRight: -gutter / 2,
|
||||||
marginLeft: -gutter / 2
|
marginLeft: -gutter / 2,
|
||||||
}}
|
}}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
{newChildren}
|
{newChildren}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
|
|
||||||
if (!title && !label) return textChildren
|
if (!title && !label) return textChildren;
|
||||||
return (
|
return (
|
||||||
<AntdSchemaFieldAdaptor {...formItemProps}>
|
<AntdSchemaFieldAdaptor {...formItemProps}>
|
||||||
{textChildren}
|
{textChildren}
|
||||||
</AntdSchemaFieldAdaptor>
|
</AntdSchemaFieldAdaptor>
|
||||||
)
|
);
|
||||||
})`
|
})`
|
||||||
display: flex;
|
display: flex;
|
||||||
.text-box-words:nth-child(1) {
|
.text-box-words:nth-child(1) {
|
||||||
@ -122,7 +122,7 @@ export const FormTextBox = createControllerBox<IFormTextBox & ItemProps>(
|
|||||||
.preview-text {
|
.preview-text {
|
||||||
text-align: center !important;
|
text-align: center !important;
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
)
|
);
|
||||||
|
|
||||||
export default FormTextBox
|
export default FormTextBox;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { Popover, Button } from 'antd'
|
import { Popover, Button } from 'antd';
|
||||||
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared'
|
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared';
|
||||||
import { icons, hasIcon, Icon as IconComponent } from '@/components/icons';
|
import { icons, hasIcon, Icon as IconComponent } from '@/components/icons';
|
||||||
|
|
||||||
function IconField(props: any) {
|
function IconField(props: any) {
|
||||||
@ -9,19 +9,33 @@ function IconField(props: any) {
|
|||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Popover placement={'bottom'} visible={visible} onVisibleChange={(val) => {
|
<Popover
|
||||||
setVisible(val)
|
placement={'bottom'}
|
||||||
}} content={(
|
visible={visible}
|
||||||
|
onVisibleChange={val => {
|
||||||
|
setVisible(val);
|
||||||
|
}}
|
||||||
|
content={
|
||||||
<div>
|
<div>
|
||||||
{[...icons.keys()].map(key => (
|
{[...icons.keys()].map(key => (
|
||||||
<span style={{fontSize: 18, marginRight: 10, cursor: 'pointer'}} onClick={() => {
|
<span
|
||||||
|
style={{ fontSize: 18, marginRight: 10, cursor: 'pointer' }}
|
||||||
|
onClick={() => {
|
||||||
onChange(key);
|
onChange(key);
|
||||||
setVisible(false)
|
setVisible(false);
|
||||||
}}><IconComponent type={key}/></span>
|
}}
|
||||||
|
>
|
||||||
|
<IconComponent type={key} />
|
||||||
|
</span>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)} title="图标" trigger="click">
|
}
|
||||||
<Button>{ hasIcon(value) ? <IconComponent type={value}/> : '选择图标'}</Button>
|
title="图标"
|
||||||
|
trigger="click"
|
||||||
|
>
|
||||||
|
<Button>
|
||||||
|
{hasIcon(value) ? <IconComponent type={value} /> : '选择图标'}
|
||||||
|
</Button>
|
||||||
</Popover>
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -29,7 +43,7 @@ function IconField(props: any) {
|
|||||||
|
|
||||||
export const Icon = connect({
|
export const Icon = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(IconField)
|
})(IconField);
|
||||||
|
|
||||||
export default Icon
|
export default Icon;
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
export * from './text-button'
|
export * from './text-button';
|
||||||
export * from './time-picker'
|
export * from './time-picker';
|
||||||
export * from './transfer'
|
export * from './transfer';
|
||||||
export * from './switch'
|
export * from './switch';
|
||||||
export * from './array-cards'
|
export * from './array-cards';
|
||||||
export * from './array-table'
|
export * from './array-table';
|
||||||
export * from './checkbox'
|
export * from './checkbox';
|
||||||
export * from './circle-button'
|
export * from './circle-button';
|
||||||
export * from './date-picker'
|
export * from './date-picker';
|
||||||
export * from './form-block'
|
export * from './form-block';
|
||||||
export * from './form-card'
|
export * from './form-card';
|
||||||
export * from './form-tab'
|
export * from './form-tab';
|
||||||
export * from './form-grid-col'
|
export * from './form-grid-col';
|
||||||
export * from './form-grid-row'
|
export * from './form-grid-row';
|
||||||
export * from './form-item-grid'
|
export * from './form-item-grid';
|
||||||
export * from './form-layout'
|
export * from './form-layout';
|
||||||
export * from './form-mega-layout'
|
export * from './form-mega-layout';
|
||||||
export * from './form-description'
|
export * from './form-description';
|
||||||
export * from './form-step'
|
export * from './form-step';
|
||||||
export * from './form-text-box'
|
export * from './form-text-box';
|
||||||
export * from './form-slot'
|
export * from './form-slot';
|
||||||
export * from './input'
|
export * from './input';
|
||||||
export * from './select'
|
export * from './select';
|
||||||
export * from './number-picker'
|
export * from './number-picker';
|
||||||
export * from './password'
|
export * from './password';
|
||||||
export * from './radio'
|
export * from './radio';
|
||||||
export * from './range'
|
export * from './range';
|
||||||
export * from './rating'
|
export * from './rating';
|
||||||
export * from './upload'
|
export * from './upload';
|
||||||
export * from './registry'
|
export * from './registry';
|
||||||
|
@ -1,25 +1,31 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Input as AntdInput } from 'antd'
|
import { Input as AntdInput } from 'antd';
|
||||||
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared'
|
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared';
|
||||||
|
|
||||||
export const Input = connect<'TextArea'>({
|
export const Input = connect<'TextArea'>({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(acceptEnum(({onChange, ...restProps}) => (
|
})(
|
||||||
|
acceptEnum(({ onChange, ...restProps }) => (
|
||||||
<AntdInput
|
<AntdInput
|
||||||
autoComplete={'off'}
|
autoComplete={'off'}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
onChange={(e) => {
|
onChange={e => {
|
||||||
// 文本字段,如果空要 null 处理
|
// 文本字段,如果空要 null 处理
|
||||||
onChange(e.target.value ? e : null);
|
onChange(e.target.value ? e : null);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)))
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
Input.TextArea = connect({
|
Input.TextArea = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(acceptEnum((props) => <AntdInput.TextArea autoSize={{minRows: 2, maxRows: 12}} {...props}/>))
|
})(
|
||||||
|
acceptEnum(props => (
|
||||||
|
<AntdInput.TextArea autoSize={{ minRows: 2, maxRows: 12 }} {...props} />
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
export default Input
|
export default Input;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/input/style/index'
|
import 'antd/lib/input/style/index';
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Input as AntdInput } from 'antd'
|
import { Input as AntdInput } from 'antd';
|
||||||
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared'
|
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared';
|
||||||
|
|
||||||
export const Markdown = connect({
|
export const Markdown = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(acceptEnum((props) => <AntdInput.TextArea autoSize={{minRows: 2, maxRows: 12}} {...props}/>))
|
})(
|
||||||
|
acceptEnum(props => (
|
||||||
|
<AntdInput.TextArea autoSize={{ minRows: 2, maxRows: 12 }} {...props} />
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
export default Markdown
|
export default Markdown;
|
||||||
|
@ -1,22 +1,24 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { InputNumber } from 'antd'
|
import { InputNumber } from 'antd';
|
||||||
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared'
|
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared';
|
||||||
|
|
||||||
export const NumberPicker = connect({
|
export const NumberPicker = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(acceptEnum(InputNumber))
|
})(acceptEnum(InputNumber));
|
||||||
|
|
||||||
export const Percent = connect({
|
export const Percent = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(acceptEnum((props) => (
|
})(
|
||||||
|
acceptEnum(props => (
|
||||||
<InputNumber
|
<InputNumber
|
||||||
formatter={value => value ? `${value}%` : ''}
|
formatter={value => (value ? `${value}%` : '')}
|
||||||
parser={value => value.replace('%', '')}
|
parser={value => value.replace('%', '')}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)))
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
export default NumberPicker
|
export default NumberPicker;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/input-number/style/index'
|
import 'antd/lib/input-number/style/index';
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { Input } from 'antd'
|
import { Input } from 'antd';
|
||||||
import { PasswordProps } from 'antd/lib/input'
|
import { PasswordProps } from 'antd/lib/input';
|
||||||
import { PasswordStrength } from '@formily/react-shared-components'
|
import { PasswordStrength } from '@formily/react-shared-components';
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
import { mapStyledProps } from '../shared'
|
import { mapStyledProps } from '../shared';
|
||||||
|
|
||||||
export interface IPasswordProps extends PasswordProps {
|
export interface IPasswordProps extends PasswordProps {
|
||||||
checkStrength: boolean
|
checkStrength: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Password = connect({
|
export const Password = connect({
|
||||||
getProps: mapStyledProps
|
getProps: mapStyledProps,
|
||||||
})(styled((props: IPasswordProps) => {
|
})(styled((props: IPasswordProps) => {
|
||||||
const { value, className, checkStrength, onChange, ...others } = props
|
const { value, className, checkStrength, onChange, ...others } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={className}>
|
<span className={className}>
|
||||||
@ -21,7 +21,7 @@ export const Password = connect({
|
|||||||
autoComplete={'new-password'}
|
autoComplete={'new-password'}
|
||||||
{...others}
|
{...others}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => {
|
onChange={e => {
|
||||||
// 密码字段,如果没有设置不处理
|
// 密码字段,如果没有设置不处理
|
||||||
onChange(e.target.value ? e : undefined);
|
onChange(e.target.value ? e : undefined);
|
||||||
}}
|
}}
|
||||||
@ -38,16 +38,16 @@ export const Password = connect({
|
|||||||
<div
|
<div
|
||||||
className="password-strength-bar"
|
className="password-strength-bar"
|
||||||
style={{
|
style={{
|
||||||
clipPath: `polygon(0 0,${score}% 0,${score}% 100%,0 100%)`
|
clipPath: `polygon(0 0,${score}% 0,${score}% 100%,0 100%)`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}}
|
}}
|
||||||
</PasswordStrength>
|
</PasswordStrength>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
})`
|
})`
|
||||||
.password-strength-wrapper {
|
.password-strength-wrapper {
|
||||||
background: #e0e0e0;
|
background: #e0e0e0;
|
||||||
@ -83,6 +83,6 @@ export const Password = connect({
|
|||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`)
|
`);
|
||||||
|
|
||||||
export default Password
|
export default Password;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/input/style/index'
|
import 'antd/lib/input/style/index';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Input as AntdInput, Table, Checkbox, Select, Tag } from 'antd'
|
import { Input as AntdInput, Table, Checkbox, Select, Tag } from 'antd';
|
||||||
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared'
|
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import { useRequest } from 'umi';
|
import { useRequest } from 'umi';
|
||||||
import { useDynamicList } from 'ahooks';
|
import { useDynamicList } from 'ahooks';
|
||||||
@ -10,22 +10,30 @@ import get from 'lodash/get';
|
|||||||
import set from 'lodash/set';
|
import set from 'lodash/set';
|
||||||
import { DrawerSelectComponent } from '../drawer-select';
|
import { DrawerSelectComponent } from '../drawer-select';
|
||||||
|
|
||||||
export const Permissions = {} as {Actions: any, Fields: any, Tabs: any};
|
export const Permissions = {} as { Actions: any; Fields: any; Tabs: any };
|
||||||
|
|
||||||
Permissions.Actions = connect({
|
Permissions.Actions = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(({ onChange, value = [], resourceKey, ...restProps }) => {
|
})(({ onChange, value = [], resourceKey, ...restProps }) => {
|
||||||
const { data = [], loading = true } = useRequest(() => {
|
const { data = [], loading = true } = useRequest(
|
||||||
|
() => {
|
||||||
return api.resource('collections.actions').list({
|
return api.resource('collections.actions').list({
|
||||||
associatedKey: resourceKey,
|
associatedKey: resourceKey,
|
||||||
perPage: -1,
|
perPage: -1,
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
refreshDeps: [resourceKey]
|
{
|
||||||
});
|
refreshDeps: [resourceKey],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return <Table size={'small'} pagination={false} dataSource={data} columns={[
|
return (
|
||||||
|
<Table
|
||||||
|
size={'small'}
|
||||||
|
pagination={false}
|
||||||
|
dataSource={data}
|
||||||
|
columns={[
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
dataIndex: ['title'],
|
dataIndex: ['title'],
|
||||||
@ -33,19 +41,29 @@ Permissions.Actions = connect({
|
|||||||
{
|
{
|
||||||
title: '类型',
|
title: '类型',
|
||||||
dataIndex: ['type'],
|
dataIndex: ['type'],
|
||||||
render: (type) => {
|
render: type => {
|
||||||
return type === 'create' ? <Tag color={'green'}>对新数据操作</Tag> : <Tag color={'blue'}>对已有数据操作</Tag>;
|
return type === 'create' ? (
|
||||||
}
|
<Tag color={'green'}>对新数据操作</Tag>
|
||||||
|
) : (
|
||||||
|
<Tag color={'blue'}>对已有数据操作</Tag>
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '允许操作',
|
title: '允许操作',
|
||||||
dataIndex: ['name'],
|
dataIndex: ['name'],
|
||||||
render: (val, record) => {
|
render: (val, record) => {
|
||||||
const values = [...value||[]];
|
const values = [...(value || [])];
|
||||||
const index = findIndex(values, (item: any) => item && item.name === `${resourceKey}:${record.name}`);
|
const index = findIndex(
|
||||||
|
values,
|
||||||
|
(item: any) =>
|
||||||
|
item && item.name === `${resourceKey}:${record.name}`,
|
||||||
|
);
|
||||||
console.log(values);
|
console.log(values);
|
||||||
return (
|
return (
|
||||||
<Checkbox defaultChecked={index >= 0} onChange={(e) => {
|
<Checkbox
|
||||||
|
defaultChecked={index >= 0}
|
||||||
|
onChange={e => {
|
||||||
// const index = findIndex(values, (item: any) => item && item.name === `${resourceKey}:${record.name}`);
|
// const index = findIndex(values, (item: any) => item && item.name === `${resourceKey}:${record.name}`);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
if (!e.target.checked) {
|
if (!e.target.checked) {
|
||||||
@ -57,9 +75,10 @@ Permissions.Actions = connect({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
onChange(values);
|
onChange(values);
|
||||||
}}/>
|
}}
|
||||||
)
|
/>
|
||||||
}
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '可操作的数据范围',
|
title: '可操作的数据范围',
|
||||||
@ -68,9 +87,18 @@ Permissions.Actions = connect({
|
|||||||
if (['filter', 'create'].indexOf(record.type) !== -1) {
|
if (['filter', 'create'].indexOf(record.type) !== -1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const values = [...value||[]];
|
const values = [...(value || [])];
|
||||||
const index = findIndex(values, (item: any) => item && item.name === `${resourceKey}:${record.name}`);
|
const index = findIndex(
|
||||||
console.log(values, index, `${resourceKey}:${record.name}`, get(values, [index, 'scope']));
|
values,
|
||||||
|
(item: any) =>
|
||||||
|
item && item.name === `${resourceKey}:${record.name}`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
values,
|
||||||
|
index,
|
||||||
|
`${resourceKey}:${record.name}`,
|
||||||
|
get(values, [index, 'scope']),
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<DrawerSelectComponent
|
<DrawerSelectComponent
|
||||||
schema={{
|
schema={{
|
||||||
@ -84,9 +112,13 @@ Permissions.Actions = connect({
|
|||||||
labelField={'title'}
|
labelField={'title'}
|
||||||
valueField={'id'}
|
valueField={'id'}
|
||||||
value={get(values, [index, 'scope'])}
|
value={get(values, [index, 'scope'])}
|
||||||
onChange={(data) => {
|
onChange={data => {
|
||||||
const values = [...value||[]];
|
const values = [...(value || [])];
|
||||||
const index = findIndex(values, (item: any) => item && item.name === `${resourceKey}:${record.name}`);
|
const index = findIndex(
|
||||||
|
values,
|
||||||
|
(item: any) =>
|
||||||
|
item && item.name === `${resourceKey}:${record.name}`,
|
||||||
|
);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
values.push({
|
values.push({
|
||||||
name: `${resourceKey}:${record.name}`,
|
name: `${resourceKey}:${record.name}`,
|
||||||
@ -95,7 +127,7 @@ Permissions.Actions = connect({
|
|||||||
} else {
|
} else {
|
||||||
set(values, [index, 'scope_id'], data.id);
|
set(values, [index, 'scope_id'], data.id);
|
||||||
}
|
}
|
||||||
console.log('valvalvalvalval', {values})
|
console.log('valvalvalvalval', { values });
|
||||||
onChange(values);
|
onChange(values);
|
||||||
console.log('valvalvalvalval', data);
|
console.log('valvalvalvalval', data);
|
||||||
}}
|
}}
|
||||||
@ -125,17 +157,19 @@ Permissions.Actions = connect({
|
|||||||
// console.log('valvalvalvalval', data);
|
// console.log('valvalvalvalval', data);
|
||||||
// }}
|
// }}
|
||||||
// />
|
// />
|
||||||
)
|
);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
]} loading={loading}/>
|
},
|
||||||
})
|
]}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
Permissions.Fields = connect<'TextArea'>({
|
Permissions.Fields = connect<'TextArea'>({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(({ onChange, value = [], resourceKey, ...restProps }) => {
|
})(({ onChange, value = [], resourceKey, ...restProps }) => {
|
||||||
|
|
||||||
const actions = {};
|
const actions = {};
|
||||||
value.forEach(item => {
|
value.forEach(item => {
|
||||||
actions[item.field_id] = item.actions;
|
actions[item.field_id] = item.actions;
|
||||||
@ -145,22 +179,26 @@ Permissions.Fields = connect<'TextArea'>({
|
|||||||
|
|
||||||
const [fields, setFields] = useState(value || []);
|
const [fields, setFields] = useState(value || []);
|
||||||
|
|
||||||
const { data = [], loading = true } = useRequest(() => {
|
const { data = [], loading = true } = useRequest(
|
||||||
|
() => {
|
||||||
return api.resource('collections.fields').list({
|
return api.resource('collections.fields').list({
|
||||||
associatedKey: resourceKey,
|
associatedKey: resourceKey,
|
||||||
perPage: -1,
|
perPage: -1,
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
refreshDeps: [resourceKey]
|
{
|
||||||
});
|
refreshDeps: [resourceKey],
|
||||||
|
},
|
||||||
|
);
|
||||||
console.log({ resourceKey, data });
|
console.log({ resourceKey, data });
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '字段名称',
|
title: '字段名称',
|
||||||
dataIndex: ['title'],
|
dataIndex: ['title'],
|
||||||
}
|
},
|
||||||
].concat([
|
].concat(
|
||||||
|
[
|
||||||
{
|
{
|
||||||
title: '查看',
|
title: '查看',
|
||||||
action: `${resourceKey}:list`,
|
action: `${resourceKey}:list`,
|
||||||
@ -174,9 +212,15 @@ Permissions.Fields = connect<'TextArea'>({
|
|||||||
action: `${resourceKey}:create`,
|
action: `${resourceKey}:create`,
|
||||||
},
|
},
|
||||||
].map(({ title, action }) => {
|
].map(({ title, action }) => {
|
||||||
let checked = value.filter(({ actions = [] }) => actions.indexOf(action) !== -1).length === data.length;
|
let checked =
|
||||||
|
value.filter(({ actions = [] }) => actions.indexOf(action) !== -1)
|
||||||
|
.length === data.length;
|
||||||
return {
|
return {
|
||||||
title: <><Checkbox checked={checked} onChange={(e) => {
|
title: (
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
checked={checked}
|
||||||
|
onChange={e => {
|
||||||
const values = data.map(field => {
|
const values = data.map(field => {
|
||||||
const items = actions[field.id] || [];
|
const items = actions[field.id] || [];
|
||||||
const index = items.indexOf(action);
|
const index = items.indexOf(action);
|
||||||
@ -192,22 +236,31 @@ Permissions.Fields = connect<'TextArea'>({
|
|||||||
return {
|
return {
|
||||||
field_id: field.id,
|
field_id: field.id,
|
||||||
actions: items,
|
actions: items,
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
// console.log(values);
|
// console.log(values);
|
||||||
setFields([...values]);
|
setFields([...values]);
|
||||||
onChange([...values]);
|
onChange([...values]);
|
||||||
}}/> {title}</>,
|
}}
|
||||||
|
/>{' '}
|
||||||
|
{title}
|
||||||
|
</>
|
||||||
|
),
|
||||||
dataIndex: ['id'],
|
dataIndex: ['id'],
|
||||||
render: (val, record) => {
|
render: (val, record) => {
|
||||||
const items = actions[record.id]||[]
|
const items = actions[record.id] || [];
|
||||||
// console.log({items}, items.indexOf(action));
|
// console.log({items}, items.indexOf(action));
|
||||||
return (
|
return (
|
||||||
<Checkbox checked={items.indexOf(action) !== -1} onChange={e => {
|
<Checkbox
|
||||||
|
checked={items.indexOf(action) !== -1}
|
||||||
|
onChange={e => {
|
||||||
const values = [...value];
|
const values = [...value];
|
||||||
const index = findIndex(values, ({field_id, actions = []}) => {
|
const index = findIndex(
|
||||||
|
values,
|
||||||
|
({ field_id, actions = [] }) => {
|
||||||
return field_id === record.id;
|
return field_id === record.id;
|
||||||
});
|
},
|
||||||
|
);
|
||||||
if (e.target.checked && index === -1) {
|
if (e.target.checked && index === -1) {
|
||||||
values.push({
|
values.push({
|
||||||
field_id: record.id,
|
field_id: record.id,
|
||||||
@ -225,28 +278,40 @@ Permissions.Fields = connect<'TextArea'>({
|
|||||||
}
|
}
|
||||||
onChange(values);
|
onChange(values);
|
||||||
setFields(values);
|
setFields(values);
|
||||||
}}/>
|
}}
|
||||||
)
|
/>
|
||||||
}
|
);
|
||||||
}
|
},
|
||||||
}) as any)
|
};
|
||||||
|
}) as any,
|
||||||
|
);
|
||||||
|
|
||||||
return <Table size={'small'} loading={loading} pagination={false} dataSource={data} columns={columns}/>
|
return (
|
||||||
})
|
<Table
|
||||||
|
size={'small'}
|
||||||
|
loading={loading}
|
||||||
|
pagination={false}
|
||||||
|
dataSource={data}
|
||||||
|
columns={columns}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
Permissions.Tabs = connect<'TextArea'>({
|
Permissions.Tabs = connect<'TextArea'>({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(({ onChange, value = [], resourceKey, ...restProps }) => {
|
})(({ onChange, value = [], resourceKey, ...restProps }) => {
|
||||||
|
const { data = [], loading = true, mutate } = useRequest(
|
||||||
const { data = [], loading = true, mutate } = useRequest(() => {
|
() => {
|
||||||
return api.resource('collections.tabs').list({
|
return api.resource('collections.tabs').list({
|
||||||
associatedKey: resourceKey,
|
associatedKey: resourceKey,
|
||||||
perPage: -1,
|
perPage: -1,
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
refreshDeps: [resourceKey]
|
{
|
||||||
});
|
refreshDeps: [resourceKey],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// const [checked, setChecked] = useState(false);
|
// const [checked, setChecked] = useState(false);
|
||||||
|
|
||||||
@ -259,7 +324,12 @@ Permissions.Tabs = connect<'TextArea'>({
|
|||||||
// data,
|
// data,
|
||||||
// ]);
|
// ]);
|
||||||
|
|
||||||
return <Table size={'small'} pagination={false} dataSource={data} columns={[
|
return (
|
||||||
|
<Table
|
||||||
|
size={'small'}
|
||||||
|
pagination={false}
|
||||||
|
dataSource={data}
|
||||||
|
columns={[
|
||||||
{
|
{
|
||||||
title: '标签页',
|
title: '标签页',
|
||||||
dataIndex: ['title'],
|
dataIndex: ['title'],
|
||||||
@ -267,16 +337,24 @@ Permissions.Tabs = connect<'TextArea'>({
|
|||||||
{
|
{
|
||||||
title: (
|
title: (
|
||||||
<>
|
<>
|
||||||
<Checkbox checked={data.length === value.length} onChange={(e) => {
|
<Checkbox
|
||||||
onChange(e.target.checked ? data.map(record => record.id) : []);
|
checked={data.length === value.length}
|
||||||
}}/> 查看
|
onChange={e => {
|
||||||
|
onChange(
|
||||||
|
e.target.checked ? data.map(record => record.id) : [],
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
查看
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
dataIndex: ['id'],
|
dataIndex: ['id'],
|
||||||
render: (val, record) => {
|
render: (val, record) => {
|
||||||
const values = [...value];
|
const values = [...value];
|
||||||
return (
|
return (
|
||||||
<Checkbox checked={values.indexOf(record.id) !== -1} onChange={(e) => {
|
<Checkbox
|
||||||
|
checked={values.indexOf(record.id) !== -1}
|
||||||
|
onChange={e => {
|
||||||
const index = values.indexOf(record.id);
|
const index = values.indexOf(record.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
if (!e.target.checked) {
|
if (!e.target.checked) {
|
||||||
@ -286,9 +364,13 @@ Permissions.Tabs = connect<'TextArea'>({
|
|||||||
values.push(record.id);
|
values.push(record.id);
|
||||||
}
|
}
|
||||||
onChange(values);
|
onChange(values);
|
||||||
}}/>
|
}}
|
||||||
)
|
/>
|
||||||
}
|
);
|
||||||
},
|
},
|
||||||
]} loading={loading}/>
|
},
|
||||||
|
]}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { Radio as AntdRadio } from 'antd'
|
import { Radio as AntdRadio } from 'antd';
|
||||||
import {
|
import {
|
||||||
transformDataSourceKey,
|
transformDataSourceKey,
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent
|
mapTextComponent,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
|
|
||||||
export const Radio = connect<'Group'>({
|
export const Radio = connect<'Group'>({
|
||||||
valueName: 'checked',
|
valueName: 'checked',
|
||||||
getProps: mapStyledProps
|
getProps: mapStyledProps,
|
||||||
})(AntdRadio)
|
})(AntdRadio);
|
||||||
|
|
||||||
Radio.Group = connect({
|
Radio.Group = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(transformDataSourceKey(AntdRadio.Group, 'options'))
|
})(transformDataSourceKey(AntdRadio.Group, 'options'));
|
||||||
|
|
||||||
export default Radio
|
export default Radio;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/radio/style/index'
|
import 'antd/lib/radio/style/index';
|
||||||
|
@ -1,47 +1,47 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { Slider } from 'antd'
|
import { Slider } from 'antd';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { mapStyledProps } from '../shared'
|
import { mapStyledProps } from '../shared';
|
||||||
|
|
||||||
export interface ISliderMarks {
|
export interface ISliderMarks {
|
||||||
[key: number]:
|
[key: number]:
|
||||||
| React.ReactNode
|
| React.ReactNode
|
||||||
| {
|
| {
|
||||||
style: React.CSSProperties
|
style: React.CSSProperties;
|
||||||
label: React.ReactNode
|
label: React.ReactNode;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare type SliderValue = number | [number, number]
|
export declare type SliderValue = number | [number, number];
|
||||||
|
|
||||||
// TODO 并不是方法,最好能引用组件的 typescript 接口定义
|
// TODO 并不是方法,最好能引用组件的 typescript 接口定义
|
||||||
export interface ISliderProps {
|
export interface ISliderProps {
|
||||||
min?: number
|
min?: number;
|
||||||
max?: number
|
max?: number;
|
||||||
marks?: ISliderMarks
|
marks?: ISliderMarks;
|
||||||
value?: SliderValue
|
value?: SliderValue;
|
||||||
defaultValue?: SliderValue
|
defaultValue?: SliderValue;
|
||||||
onChange?: (value: SliderValue) => void
|
onChange?: (value: SliderValue) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Range = connect({
|
export const Range = connect({
|
||||||
defaultProps: {
|
defaultProps: {
|
||||||
style: {
|
style: {
|
||||||
width: 320
|
width: 320,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
getProps: mapStyledProps
|
},
|
||||||
|
getProps: mapStyledProps,
|
||||||
})(
|
})(
|
||||||
class Component extends React.Component<ISliderProps> {
|
class Component extends React.Component<ISliderProps> {
|
||||||
public render() {
|
public render() {
|
||||||
const { onChange, value, min, max, marks, ...rest } = this.props
|
const { onChange, value, min, max, marks, ...rest } = this.props;
|
||||||
let newMarks = {}
|
let newMarks = {};
|
||||||
if (Array.isArray(marks)) {
|
if (Array.isArray(marks)) {
|
||||||
marks.forEach(mark => {
|
marks.forEach(mark => {
|
||||||
newMarks[mark] = mark
|
newMarks[mark] = mark;
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
newMarks = marks
|
newMarks = marks;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Slider
|
<Slider
|
||||||
@ -52,9 +52,9 @@ export const Range = connect({
|
|||||||
max={max}
|
max={max}
|
||||||
marks={newMarks}
|
marks={newMarks}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
export default Range
|
export default Range;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/slider/style/index'
|
import 'antd/lib/slider/style/index';
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { Rate } from 'antd'
|
import { Rate } from 'antd';
|
||||||
import { mapStyledProps } from '../shared'
|
import { mapStyledProps } from '../shared';
|
||||||
|
|
||||||
export const Rating = connect({
|
export const Rating = connect({
|
||||||
getProps: mapStyledProps
|
getProps: mapStyledProps,
|
||||||
})(Rate)
|
})(Rate);
|
||||||
|
|
||||||
export default Rating
|
export default Rating;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/rate/style/index'
|
import 'antd/lib/rate/style/index';
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
import { registerFormFields } from '@formily/antd'
|
import { registerFormFields } from '@formily/antd';
|
||||||
import { TimePicker } from './time-picker'
|
import { TimePicker } from './time-picker';
|
||||||
import { Transfer } from './transfer'
|
import { Transfer } from './transfer';
|
||||||
import { Switch } from './switch'
|
import { Switch } from './switch';
|
||||||
import { ArrayCards } from './array-cards'
|
import { ArrayCards } from './array-cards';
|
||||||
import { ArrayTable } from './array-table'
|
import { ArrayTable } from './array-table';
|
||||||
import { Checkbox } from './checkbox'
|
import { Checkbox } from './checkbox';
|
||||||
import { DatePicker } from './date-picker'
|
import { DatePicker } from './date-picker';
|
||||||
import { Input } from './input'
|
import { Input } from './input';
|
||||||
import { NumberPicker, Percent } from './number-picker'
|
import { NumberPicker, Percent } from './number-picker';
|
||||||
import { Password } from './password'
|
import { Password } from './password';
|
||||||
import { Radio } from './radio'
|
import { Radio } from './radio';
|
||||||
import { Range } from './range'
|
import { Range } from './range';
|
||||||
import { Rating } from './rating'
|
import { Rating } from './rating';
|
||||||
import { Upload } from './upload'
|
import { Upload } from './upload';
|
||||||
import { Filter } from './filter'
|
import { Filter } from './filter';
|
||||||
import { RemoteSelect } from './remote-select'
|
import { RemoteSelect } from './remote-select';
|
||||||
import { DrawerSelect } from './drawer-select'
|
import { DrawerSelect } from './drawer-select';
|
||||||
import { SubTable } from './sub-table'
|
import { SubTable } from './sub-table';
|
||||||
import { Cascader } from './cascader'
|
import { Cascader } from './cascader';
|
||||||
import { Icon } from './icons'
|
import { Icon } from './icons';
|
||||||
import { ColorSelect } from './color-select'
|
import { ColorSelect } from './color-select';
|
||||||
import { Permissions } from './permissions'
|
import { Permissions } from './permissions';
|
||||||
import { DraggableTable } from './draggable-table'
|
import { DraggableTable } from './draggable-table';
|
||||||
import { Values } from './values'
|
import { Values } from './values';
|
||||||
import { Automations } from './automations'
|
import { Automations } from './automations';
|
||||||
import { Wysiwyg } from './wysiwyg'
|
import { Wysiwyg } from './wysiwyg';
|
||||||
import { Markdown } from './markdown'
|
import { Markdown } from './markdown';
|
||||||
|
|
||||||
export const setup = () => {
|
export const setup = () => {
|
||||||
registerFormFields({
|
registerFormFields({
|
||||||
@ -72,4 +72,4 @@ export const setup = () => {
|
|||||||
'automations.endmode': Automations.EndMode,
|
'automations.endmode': Automations.EndMode,
|
||||||
'automations.cron': Automations.Cron,
|
'automations.cron': Automations.Cron,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
@ -1,21 +1,34 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import moment from 'moment'
|
import moment from 'moment';
|
||||||
import { Select } from 'antd'
|
import { Select } from 'antd';
|
||||||
import {
|
import {
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent,
|
mapTextComponent,
|
||||||
compose,
|
compose,
|
||||||
isStr,
|
isStr,
|
||||||
isArr
|
isArr,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
import { useRequest } from 'umi';
|
import { useRequest } from 'umi';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import { Spin } from '@nocobase/client'
|
import { Spin } from '@nocobase/client';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
|
|
||||||
function RemoteSelectComponent(props) {
|
function RemoteSelectComponent(props) {
|
||||||
let { schema = {}, value, onChange, disabled, resourceName, associatedKey, filter, labelField, valueField, objectValue, placeholder, multiple } = props;
|
let {
|
||||||
|
schema = {},
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
disabled,
|
||||||
|
resourceName,
|
||||||
|
associatedKey,
|
||||||
|
filter,
|
||||||
|
labelField,
|
||||||
|
valueField,
|
||||||
|
objectValue,
|
||||||
|
placeholder,
|
||||||
|
multiple,
|
||||||
|
} = props;
|
||||||
console.log({ schema });
|
console.log({ schema });
|
||||||
if (!resourceName) {
|
if (!resourceName) {
|
||||||
resourceName = get(schema, 'component.resourceName');
|
resourceName = get(schema, 'component.resourceName');
|
||||||
@ -32,19 +45,22 @@ function RemoteSelectComponent(props) {
|
|||||||
if (!valueField) {
|
if (!valueField) {
|
||||||
valueField = 'id';
|
valueField = 'id';
|
||||||
}
|
}
|
||||||
const { data = [], loading = true } = useRequest(() => {
|
const { data = [], loading = true } = useRequest(
|
||||||
|
() => {
|
||||||
return api.resource(resourceName).list({
|
return api.resource(resourceName).list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
filter,
|
filter,
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
refreshDeps: [resourceName, associatedKey]
|
{
|
||||||
});
|
refreshDeps: [resourceName, associatedKey],
|
||||||
|
},
|
||||||
|
);
|
||||||
const selectProps: any = {};
|
const selectProps: any = {};
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
selectProps.mode = 'multiple'
|
selectProps.mode = 'multiple';
|
||||||
}
|
}
|
||||||
console.log({ data, props, associatedKey })
|
console.log({ data, props, associatedKey });
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Select
|
<Select
|
||||||
@ -65,7 +81,12 @@ function RemoteSelectComponent(props) {
|
|||||||
onChange(objectValue ? item : value);
|
onChange(objectValue ? item : value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!loading && data.map(item => (<Select.Option item={item} value={item[valueField]}>{item[labelField]}</Select.Option>))}
|
{!loading &&
|
||||||
|
data.map(item => (
|
||||||
|
<Select.Option item={item} value={item[valueField]}>
|
||||||
|
{item[labelField]}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@ -74,6 +95,6 @@ function RemoteSelectComponent(props) {
|
|||||||
export const RemoteSelect = connect({
|
export const RemoteSelect = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})(RemoteSelectComponent)
|
})(RemoteSelectComponent);
|
||||||
|
|
||||||
export default RemoteSelect
|
export default RemoteSelect;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import {
|
import {
|
||||||
Select as AntdSelect,
|
Select as AntdSelect,
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent
|
mapTextComponent,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
|
|
||||||
export const Select = connect({
|
export const Select = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})(AntdSelect)
|
})(AntdSelect);
|
||||||
|
|
||||||
export default Select
|
export default Select;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/select/style/index'
|
import 'antd/lib/select/style/index';
|
||||||
|
@ -1,47 +1,47 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { mapTextComponent, mapStyledProps, normalizeCol } from '@formily/antd'
|
import { mapTextComponent, mapStyledProps, normalizeCol } from '@formily/antd';
|
||||||
import { Select as AntSelect } from 'antd'
|
import { Select as AntSelect } from 'antd';
|
||||||
import { SelectProps as AntSelectProps } from 'antd/lib/select'
|
import { SelectProps as AntSelectProps } from 'antd/lib/select';
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
import { isArr, FormPath } from '@formily/shared'
|
import { isArr, FormPath } from '@formily/shared';
|
||||||
export * from '@formily/shared'
|
export * from '@formily/shared';
|
||||||
|
|
||||||
export const compose = (...args: any[]) => {
|
export const compose = (...args: any[]) => {
|
||||||
return (payload: any, ...extra: any[]) => {
|
return (payload: any, ...extra: any[]) => {
|
||||||
return args.reduce((buf, fn) => {
|
return args.reduce((buf, fn) => {
|
||||||
return buf !== undefined ? fn(buf, ...extra) : fn(payload, ...extra)
|
return buf !== undefined ? fn(buf, ...extra) : fn(payload, ...extra);
|
||||||
}, payload)
|
}, payload);
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
interface SelectOption {
|
interface SelectOption {
|
||||||
label: React.ReactText
|
label: React.ReactText;
|
||||||
value: any
|
value: any;
|
||||||
[key: string]: any
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
type SelectProps = AntSelectProps & {
|
type SelectProps = AntSelectProps & {
|
||||||
dataSource?: SelectOption[]
|
dataSource?: SelectOption[];
|
||||||
}
|
};
|
||||||
|
|
||||||
const createEnum = (enums: any) => {
|
const createEnum = (enums: any) => {
|
||||||
if (isArr(enums)) {
|
if (isArr(enums)) {
|
||||||
return enums.map(item => {
|
return enums.map(item => {
|
||||||
if (typeof item === 'object') {
|
if (typeof item === 'object') {
|
||||||
return {
|
return {
|
||||||
...item
|
...item,
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
label: item,
|
label: item,
|
||||||
value: item
|
value: item,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return []
|
return [];
|
||||||
}
|
};
|
||||||
|
|
||||||
export const Select: React.FC<SelectProps> = styled((props: SelectProps) => {
|
export const Select: React.FC<SelectProps> = styled((props: SelectProps) => {
|
||||||
const { dataSource = [], onChange, value, ...others } = props;
|
const { dataSource = [], onChange, value, ...others } = props;
|
||||||
@ -72,8 +72,8 @@ export const Select: React.FC<SelectProps> = styled((props: SelectProps) => {
|
|||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</AntSelect.Option>
|
</AntSelect.Option>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
return (
|
return (
|
||||||
<AntSelect
|
<AntSelect
|
||||||
className={props.className}
|
className={props.className}
|
||||||
@ -85,59 +85,59 @@ export const Select: React.FC<SelectProps> = styled((props: SelectProps) => {
|
|||||||
isArr(options)
|
isArr(options)
|
||||||
? options.map(item => ({
|
? options.map(item => ({
|
||||||
...item,
|
...item,
|
||||||
props: undefined
|
props: undefined,
|
||||||
}))
|
}))
|
||||||
: {
|
: {
|
||||||
...options,
|
...options,
|
||||||
props: undefined //干掉循环引用
|
props: undefined, //干掉循环引用
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</AntSelect>
|
</AntSelect>
|
||||||
)
|
);
|
||||||
})`
|
})`
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
`
|
`;
|
||||||
export const acceptEnum = (component: React.JSXElementConstructor<any>) => {
|
export const acceptEnum = (component: React.JSXElementConstructor<any>) => {
|
||||||
return ({ dataSource, ...others }) => {
|
return ({ dataSource, ...others }) => {
|
||||||
if (dataSource) {
|
if (dataSource) {
|
||||||
return React.createElement(Select, { dataSource, ...others })
|
return React.createElement(Select, { dataSource, ...others });
|
||||||
} else {
|
} else {
|
||||||
return React.createElement(component, others)
|
return React.createElement(component, others);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const transformDataSourceKey = (component, dataSourceKey) => {
|
export const transformDataSourceKey = (component, dataSourceKey) => {
|
||||||
return ({ dataSource, ...others }) => {
|
return ({ dataSource, ...others }) => {
|
||||||
return React.createElement(component, {
|
return React.createElement(component, {
|
||||||
[dataSourceKey]: dataSource,
|
[dataSourceKey]: dataSource,
|
||||||
...others
|
...others,
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const createMatchUpdate = (name: string, path: string) => (
|
export const createMatchUpdate = (name: string, path: string) => (
|
||||||
targetName: string,
|
targetName: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
callback: () => void
|
callback: () => void,
|
||||||
) => {
|
) => {
|
||||||
if (targetName || targetPath) {
|
if (targetName || targetPath) {
|
||||||
if (targetName) {
|
if (targetName) {
|
||||||
if (FormPath.parse(targetName).matchAliasGroup(name, path)) {
|
if (FormPath.parse(targetName).matchAliasGroup(name, path)) {
|
||||||
callback()
|
callback();
|
||||||
}
|
}
|
||||||
} else if (targetPath) {
|
} else if (targetPath) {
|
||||||
if (FormPath.parse(targetPath).matchAliasGroup(name, path)) {
|
if (FormPath.parse(targetPath).matchAliasGroup(name, path)) {
|
||||||
callback()
|
callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callback()
|
callback();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export { mapTextComponent, mapStyledProps, normalizeCol }
|
export { mapTextComponent, mapStyledProps, normalizeCol };
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
import React, { useState, useEffect, useImperativeHandle, forwardRef, useRef } from 'react';
|
import React, {
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useImperativeHandle,
|
||||||
|
forwardRef,
|
||||||
|
useRef,
|
||||||
|
} from 'react';
|
||||||
import { Button, Drawer } from 'antd';
|
import { Button, Drawer } from 'antd';
|
||||||
import { Tooltip, Input, Space, Modal } from 'antd';
|
import { Tooltip, Input, Space, Modal } from 'antd';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
@ -27,13 +33,12 @@ const actions = createFormActions();
|
|||||||
|
|
||||||
export default forwardRef((props: any, ref) => {
|
export default forwardRef((props: any, ref) => {
|
||||||
console.log(props);
|
console.log(props);
|
||||||
const {
|
const { target, onFinish } = props;
|
||||||
target,
|
const { data: schema = {}, loading } = useRequest(() =>
|
||||||
onFinish,
|
api.resource(target).getView({
|
||||||
} = props;
|
resourceKey: 'form',
|
||||||
const { data: schema = {}, loading } = useRequest(() => api.resource(target).getView({
|
}),
|
||||||
resourceKey: 'form'
|
);
|
||||||
}));
|
|
||||||
const [state, setState] = useState<any>({});
|
const [state, setState] = useState<any>({});
|
||||||
const [form, setForm] = useState<any>({});
|
const [form, setForm] = useState<any>({});
|
||||||
const [changed, setChanged] = useState(false);
|
const [changed, setChanged] = useState(false);
|
||||||
@ -66,7 +71,7 @@ export default forwardRef((props: any, ref) => {
|
|||||||
onOk() {
|
onOk() {
|
||||||
setChanged(false);
|
setChanged(false);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setChanged(false);
|
setChanged(false);
|
||||||
@ -74,35 +79,44 @@ export default forwardRef((props: any, ref) => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
title={title}
|
title={title}
|
||||||
footer={(
|
footer={
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Space>
|
<Space>
|
||||||
<Button onClick={() => {
|
<Button
|
||||||
|
onClick={() => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
setChanged(false);
|
setChanged(false);
|
||||||
}}>取消</Button>
|
}}
|
||||||
<Button type={'primary'} onClick={async () => {
|
>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type={'primary'}
|
||||||
|
onClick={async () => {
|
||||||
await form.submit();
|
await form.submit();
|
||||||
// const { values = {} } = await actions.submit();
|
// const { values = {} } = await actions.submit();
|
||||||
// setVisible(false);
|
// setVisible(false);
|
||||||
// onFinish && onFinish(values, index);
|
// onFinish && onFinish(values, index);
|
||||||
}}>提交</Button>
|
}}
|
||||||
|
>
|
||||||
|
提交
|
||||||
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
)}
|
}
|
||||||
>
|
>
|
||||||
<SchemaForm
|
<SchemaForm
|
||||||
colon={true}
|
colon={true}
|
||||||
layout={'vertical'}
|
layout={'vertical'}
|
||||||
initialValues={data}
|
initialValues={data}
|
||||||
onChange={(values) => {
|
onChange={values => {
|
||||||
setChanged(true);
|
setChanged(true);
|
||||||
}}
|
}}
|
||||||
onSubmit={async (values) => {
|
onSubmit={async values => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
setChanged(false);
|
setChanged(false);
|
||||||
onFinish && onFinish(values, index);
|
onFinish && onFinish(values, index);
|
||||||
@ -118,29 +132,29 @@ export default forwardRef((props: any, ref) => {
|
|||||||
selector={[
|
selector={[
|
||||||
LifeCycleTypes.ON_FORM_MOUNT,
|
LifeCycleTypes.ON_FORM_MOUNT,
|
||||||
LifeCycleTypes.ON_FORM_SUBMIT_START,
|
LifeCycleTypes.ON_FORM_SUBMIT_START,
|
||||||
LifeCycleTypes.ON_FORM_SUBMIT_END
|
LifeCycleTypes.ON_FORM_SUBMIT_END,
|
||||||
]}
|
]}
|
||||||
reducer={(state, action) => {
|
reducer={(state, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case LifeCycleTypes.ON_FORM_SUBMIT_START:
|
case LifeCycleTypes.ON_FORM_SUBMIT_START:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
submitting: true
|
submitting: true,
|
||||||
}
|
};
|
||||||
case LifeCycleTypes.ON_FORM_SUBMIT_END:
|
case LifeCycleTypes.ON_FORM_SUBMIT_END:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
submitting: false
|
submitting: false,
|
||||||
}
|
};
|
||||||
default:
|
default:
|
||||||
return state
|
return state;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ state, form }) => {
|
{({ state, form }) => {
|
||||||
setState(state)
|
setState(state);
|
||||||
setForm(form);
|
setForm(form);
|
||||||
return <div/>
|
return <div />;
|
||||||
}}
|
}}
|
||||||
</FormSpy>
|
</FormSpy>
|
||||||
</SchemaForm>
|
</SchemaForm>
|
||||||
|
@ -21,14 +21,18 @@ export interface SimpleTableProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function generateIndex(): string {
|
export function generateIndex(): string {
|
||||||
return `${Math.random().toString(36).replace('0.', '').slice(-4).padStart(4, '0')}`;
|
return `${Math.random()
|
||||||
|
.toString(36)
|
||||||
|
.replace('0.', '')
|
||||||
|
.slice(-4)
|
||||||
|
.padStart(4, '0')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Table(props: SimpleTableProps) {
|
export default function Table(props: SimpleTableProps) {
|
||||||
const { schema = {}, associatedKey, value, onChange, __index } = props;
|
const { schema = {}, associatedKey, value, onChange, __index } = props;
|
||||||
const { collection_name, name } = schema;
|
const { collection_name, name } = schema;
|
||||||
const viewName = `${collection_name}.${name}.${schema.viewName || 'table'}`;
|
const viewName = `${collection_name}.${name}.${schema.viewName || 'table'}`;
|
||||||
console.log({props, associatedKey, schema, __index, viewName, schema})
|
console.log({ props, associatedKey, schema, __index, viewName, schema });
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View
|
<View
|
||||||
@ -40,5 +44,5 @@ export default function Table(props: SimpleTableProps) {
|
|||||||
type={'subTable'}
|
type={'subTable'}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import React, { useRef } from 'react'
|
import React, { useRef } from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import moment from 'moment'
|
import moment from 'moment';
|
||||||
import { Select, Button, Table as AntdTable } from 'antd'
|
import { Select, Button, Table as AntdTable } from 'antd';
|
||||||
import {
|
import {
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent,
|
mapTextComponent,
|
||||||
compose,
|
compose,
|
||||||
isStr,
|
isStr,
|
||||||
isArr
|
isArr,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
import ViewFactory from '@/components/views';
|
import ViewFactory from '@/components/views';
|
||||||
import Table from './Table';
|
import Table from './Table';
|
||||||
|
|
||||||
export const SubTable = connect({
|
export const SubTable = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})(Table)
|
})(Table);
|
||||||
|
|
||||||
export default SubTable
|
export default SubTable;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { Switch as AntdSwitch } from 'antd'
|
import { Switch as AntdSwitch } from 'antd';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { acceptEnum, mapStyledProps } from '../shared'
|
import { acceptEnum, mapStyledProps } from '../shared';
|
||||||
|
|
||||||
export const Switch = connect({
|
export const Switch = connect({
|
||||||
valueName: 'checked',
|
valueName: 'checked',
|
||||||
getProps: mapStyledProps
|
getProps: mapStyledProps,
|
||||||
})(acceptEnum(AntdSwitch))
|
})(acceptEnum(AntdSwitch));
|
||||||
|
|
||||||
export default Switch;
|
export default Switch;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/switch/style/index'
|
import 'antd/lib/switch/style/index';
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { Button } from 'antd'
|
import { Button } from 'antd';
|
||||||
import { ButtonProps } from 'antd/lib/button'
|
import { ButtonProps } from 'antd/lib/button';
|
||||||
|
|
||||||
export const TextButton: React.FC<ButtonProps> = props => (
|
export const TextButton: React.FC<ButtonProps> = props => (
|
||||||
<Button type="link" {...props} />
|
<Button type="link" {...props} />
|
||||||
)
|
);
|
||||||
|
|
||||||
export default TextButton
|
export default TextButton;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/button/style/index'
|
import 'antd/lib/button/style/index';
|
||||||
|
@ -1,50 +1,48 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import moment from 'moment'
|
import moment from 'moment';
|
||||||
import { TimePicker as AntdTimePicker } from 'antd'
|
import { TimePicker as AntdTimePicker } from 'antd';
|
||||||
import {
|
import {
|
||||||
mapStyledProps,
|
mapStyledProps,
|
||||||
mapTextComponent,
|
mapTextComponent,
|
||||||
compose,
|
compose,
|
||||||
isStr,
|
isStr,
|
||||||
isArr,
|
isArr,
|
||||||
} from '../shared'
|
} from '../shared';
|
||||||
|
|
||||||
const transformMoment = (value) => {
|
const transformMoment = value => {
|
||||||
if (value === '') return undefined
|
if (value === '') return undefined;
|
||||||
return value
|
return value;
|
||||||
}
|
};
|
||||||
|
|
||||||
const mapMomentValue = (props: any, fieldProps: any) => {
|
const mapMomentValue = (props: any, fieldProps: any) => {
|
||||||
const { value } = props
|
const { value } = props;
|
||||||
if (!fieldProps.editable) return props
|
if (!fieldProps.editable) return props;
|
||||||
try {
|
try {
|
||||||
if (isStr(value) && value) {
|
if (isStr(value) && value) {
|
||||||
props.value = moment(value, 'HH:mm:ss')
|
props.value = moment(value, 'HH:mm:ss');
|
||||||
} else if (isArr(value) && value.length) {
|
} else if (isArr(value) && value.length) {
|
||||||
props.value = value.map(
|
props.value = value.map(item => (item && moment(item, 'HH:mm:ss')) || '');
|
||||||
(item) => (item && moment(item, 'HH:mm:ss')) || ''
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(e)
|
throw new Error(e);
|
||||||
}
|
|
||||||
return props
|
|
||||||
}
|
}
|
||||||
|
return props;
|
||||||
|
};
|
||||||
|
|
||||||
export const TimePicker = connect<'RangePicker'>({
|
export const TimePicker = connect<'RangePicker'>({
|
||||||
getValueFromEvent(_, value) {
|
getValueFromEvent(_, value) {
|
||||||
return transformMoment(value)
|
return transformMoment(value);
|
||||||
},
|
},
|
||||||
getProps: compose(mapStyledProps, mapMomentValue),
|
getProps: compose(mapStyledProps, mapMomentValue),
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})(AntdTimePicker)
|
})(AntdTimePicker);
|
||||||
|
|
||||||
TimePicker.RangePicker = connect({
|
TimePicker.RangePicker = connect({
|
||||||
getValueFromEvent(_, [startDate, endDate]) {
|
getValueFromEvent(_, [startDate, endDate]) {
|
||||||
return [transformMoment(startDate), transformMoment(endDate)]
|
return [transformMoment(startDate), transformMoment(endDate)];
|
||||||
},
|
},
|
||||||
getProps: compose(mapStyledProps, mapMomentValue),
|
getProps: compose(mapStyledProps, mapMomentValue),
|
||||||
getComponent: mapTextComponent,
|
getComponent: mapTextComponent,
|
||||||
})(AntdTimePicker.RangePicker)
|
})(AntdTimePicker.RangePicker);
|
||||||
|
|
||||||
export default TimePicker
|
export default TimePicker;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/time-picker/style/index'
|
import 'antd/lib/time-picker/style/index';
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { Transfer as AntdTransfer } from 'antd'
|
import { Transfer as AntdTransfer } from 'antd';
|
||||||
import { mapStyledProps } from '../shared'
|
import { mapStyledProps } from '../shared';
|
||||||
|
|
||||||
export const Transfer = connect({
|
export const Transfer = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
valueName: 'targetKeys'
|
valueName: 'targetKeys',
|
||||||
})(AntdTransfer)
|
})(AntdTransfer);
|
||||||
|
|
||||||
export default Transfer
|
export default Transfer;
|
||||||
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/transfer/style/index'
|
import 'antd/lib/transfer/style/index';
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import { ButtonProps } from 'antd/lib/button'
|
import { ButtonProps } from 'antd/lib/button';
|
||||||
import { FormProps, FormItemProps as ItemProps } from 'antd/lib/form'
|
import { FormProps, FormItemProps as ItemProps } from 'antd/lib/form';
|
||||||
import {
|
import {
|
||||||
StepsProps as StepProps,
|
StepsProps as StepProps,
|
||||||
StepProps as StepItemProps
|
StepProps as StepItemProps,
|
||||||
} from 'antd/lib/steps'
|
} from 'antd/lib/steps';
|
||||||
import { TabsProps } from 'antd/lib/tabs'
|
import { TabsProps } from 'antd/lib/tabs';
|
||||||
import {
|
import {
|
||||||
ISchemaFormProps,
|
ISchemaFormProps,
|
||||||
IMarkupSchemaFieldProps,
|
IMarkupSchemaFieldProps,
|
||||||
ISchemaFieldComponentProps,
|
ISchemaFieldComponentProps,
|
||||||
FormPathPattern
|
FormPathPattern,
|
||||||
} from '@formily/react-schema-renderer'
|
} from '@formily/react-schema-renderer';
|
||||||
import { PreviewTextConfigProps } from '@formily/react-shared-components'
|
import { PreviewTextConfigProps } from '@formily/react-shared-components';
|
||||||
import { StyledComponent } from 'styled-components'
|
import { StyledComponent } from 'styled-components';
|
||||||
|
|
||||||
type ColSpanType = number | string
|
type ColSpanType = number | string;
|
||||||
|
|
||||||
export type IAntdSchemaFormProps = Omit<
|
export type IAntdSchemaFormProps = Omit<
|
||||||
FormProps,
|
FormProps,
|
||||||
@ -22,18 +22,18 @@ export type IAntdSchemaFormProps = Omit<
|
|||||||
> &
|
> &
|
||||||
IFormItemTopProps &
|
IFormItemTopProps &
|
||||||
PreviewTextConfigProps &
|
PreviewTextConfigProps &
|
||||||
ISchemaFormProps
|
ISchemaFormProps;
|
||||||
|
|
||||||
export type IAntdSchemaFieldProps = IMarkupSchemaFieldProps
|
export type IAntdSchemaFieldProps = IMarkupSchemaFieldProps;
|
||||||
|
|
||||||
export interface ISubmitProps extends ButtonProps {
|
export interface ISubmitProps extends ButtonProps {
|
||||||
onSubmit?: ISchemaFormProps['onSubmit']
|
onSubmit?: ISchemaFormProps['onSubmit'];
|
||||||
showLoading?: boolean
|
showLoading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IResetProps extends ButtonProps {
|
export interface IResetProps extends ButtonProps {
|
||||||
forceClear?: boolean
|
forceClear?: boolean;
|
||||||
validate?: boolean
|
validate?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IFormItemTopProps = React.PropsWithChildren<
|
export type IFormItemTopProps = React.PropsWithChildren<
|
||||||
@ -41,63 +41,63 @@ export type IFormItemTopProps = React.PropsWithChildren<
|
|||||||
Pick<ItemProps, 'prefixCls' | 'labelCol' | 'wrapperCol' | 'labelAlign'>,
|
Pick<ItemProps, 'prefixCls' | 'labelCol' | 'wrapperCol' | 'labelAlign'>,
|
||||||
'labelCol' | 'wrapperCol'
|
'labelCol' | 'wrapperCol'
|
||||||
> & {
|
> & {
|
||||||
inline?: boolean
|
inline?: boolean;
|
||||||
className?: string
|
className?: string;
|
||||||
style?: React.CSSProperties
|
style?: React.CSSProperties;
|
||||||
labelCol?: number | { span: number; offset?: number }
|
labelCol?: number | { span: number; offset?: number };
|
||||||
wrapperCol?: number | { span: number; offset?: number }
|
wrapperCol?: number | { span: number; offset?: number };
|
||||||
}
|
}
|
||||||
>
|
>;
|
||||||
|
|
||||||
export type ISchemaFieldAdaptorProps = Omit<
|
export type ISchemaFieldAdaptorProps = Omit<
|
||||||
ItemProps,
|
ItemProps,
|
||||||
'labelCol' | 'wrapperCol'
|
'labelCol' | 'wrapperCol'
|
||||||
> &
|
> &
|
||||||
Partial<ISchemaFieldComponentProps> & {
|
Partial<ISchemaFieldComponentProps> & {
|
||||||
labelCol?: number | { span: number; offset?: number }
|
labelCol?: number | { span: number; offset?: number };
|
||||||
wrapperCol?: number | { span: number; offset?: number }
|
wrapperCol?: number | { span: number; offset?: number };
|
||||||
}
|
};
|
||||||
|
|
||||||
export type StyledCP<P extends {}> = StyledComponent<
|
export type StyledCP<P extends {}> = StyledComponent<
|
||||||
(props: React.PropsWithChildren<P>) => React.ReactElement,
|
(props: React.PropsWithChildren<P>) => React.ReactElement,
|
||||||
any,
|
any,
|
||||||
{},
|
{},
|
||||||
never
|
never
|
||||||
>
|
>;
|
||||||
|
|
||||||
export type StyledCC<Props, Statics = {}> = StyledCP<Props> & Statics
|
export type StyledCC<Props, Statics = {}> = StyledCP<Props> & Statics;
|
||||||
|
|
||||||
export interface IFormButtonGroupProps {
|
export interface IFormButtonGroupProps {
|
||||||
sticky?: boolean
|
sticky?: boolean;
|
||||||
style?: React.CSSProperties
|
style?: React.CSSProperties;
|
||||||
itemStyle?: React.CSSProperties
|
itemStyle?: React.CSSProperties;
|
||||||
className?: string
|
className?: string;
|
||||||
align?: 'left' | 'right' | 'start' | 'end' | 'top' | 'bottom' | 'center'
|
align?: 'left' | 'right' | 'start' | 'end' | 'top' | 'bottom' | 'center';
|
||||||
triggerDistance?: number
|
triggerDistance?: number;
|
||||||
zIndex?: number
|
zIndex?: number;
|
||||||
span?: ColSpanType
|
span?: ColSpanType;
|
||||||
offset?: ColSpanType
|
offset?: ColSpanType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IItemProps {
|
export interface IItemProps {
|
||||||
title?: React.ReactText
|
title?: React.ReactText;
|
||||||
description?: React.ReactText
|
description?: React.ReactText;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFormItemGridProps extends IItemProps {
|
export interface IFormItemGridProps extends IItemProps {
|
||||||
cols?: Array<number | { span: number; offset: number }>
|
cols?: Array<number | { span: number; offset: number }>;
|
||||||
gutter?: number
|
gutter?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFormTextBox extends IItemProps {
|
export interface IFormTextBox extends IItemProps {
|
||||||
text?: string
|
text?: string;
|
||||||
gutter?: number
|
gutter?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFormStep extends StepProps {
|
export interface IFormStep extends StepProps {
|
||||||
dataSource: Array<StepItemProps & { name: FormPathPattern }>
|
dataSource: Array<StepItemProps & { name: FormPathPattern }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFormTab extends TabsProps {
|
export interface IFormTab extends TabsProps {
|
||||||
hiddenKeys?: string[]
|
hiddenKeys?: string[];
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { Button, Upload as AntdUpload, Popconfirm } from 'antd'
|
import { Button, Upload as AntdUpload, Popconfirm } from 'antd';
|
||||||
import { toArr, isArr, isEqual, mapStyledProps } from '../shared'
|
import { toArr, isArr, isEqual, mapStyledProps } from '../shared';
|
||||||
import {
|
import {
|
||||||
LoadingOutlined,
|
LoadingOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
UploadOutlined,
|
UploadOutlined,
|
||||||
InboxOutlined
|
InboxOutlined,
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons';
|
||||||
const { Dragger: UploadDragger } = AntdUpload
|
const { Dragger: UploadDragger } = AntdUpload;
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import findIndex from 'lodash/findIndex';
|
import findIndex from 'lodash/findIndex';
|
||||||
import Lightbox from 'react-image-lightbox';
|
import Lightbox from 'react-image-lightbox';
|
||||||
@ -16,77 +16,77 @@ import Lightbox from 'react-image-lightbox';
|
|||||||
const exts = [
|
const exts = [
|
||||||
{
|
{
|
||||||
ext: /\.docx?$/i,
|
ext: /\.docx?$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1n8jfr1uSBuNjy1XcXXcYjFXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1n8jfr1uSBuNjy1XcXXcYjFXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.pptx?$/i,
|
ext: /\.pptx?$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1ItgWr_tYBeNjy1XdXXXXyVXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1ItgWr_tYBeNjy1XdXXXXyVXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.jpe?g$/i,
|
ext: /\.jpe?g$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1wrT5r9BYBeNjy0FeXXbnmFXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1wrT5r9BYBeNjy0FeXXbnmFXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.pdf$/i,
|
ext: /\.pdf$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1GwD8r9BYBeNjy0FeXXbnmFXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1GwD8r9BYBeNjy0FeXXbnmFXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.png$/i,
|
ext: /\.png$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1BHT5r9BYBeNjy0FeXXbnmFXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1BHT5r9BYBeNjy0FeXXbnmFXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.eps$/i,
|
ext: /\.eps$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1G_iGrVOWBuNjy0FiXXXFxVXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1G_iGrVOWBuNjy0FiXXXFxVXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.ai$/i,
|
ext: /\.ai$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1B2cVr_tYBeNjy1XdXXXXyVXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1B2cVr_tYBeNjy1XdXXXXyVXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.gif$/i,
|
ext: /\.gif$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1DTiGrVOWBuNjy0FiXXXFxVXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1DTiGrVOWBuNjy0FiXXXFxVXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.svg$/i,
|
ext: /\.svg$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1uUm9rY9YBuNjy0FgXXcxcXXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1uUm9rY9YBuNjy0FgXXcxcXXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.xlsx?$/i,
|
ext: /\.xlsx?$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1any1r1OSBuNjy0FdXXbDnVXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1any1r1OSBuNjy0FdXXbDnVXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.psd?$/i,
|
ext: /\.psd?$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1_nu1r1OSBuNjy0FdXXbDnVXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1_nu1r1OSBuNjy0FdXXbDnVXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.(wav|aif|aiff|au|mp1|mp2|mp3|ra|rm|ram|mid|rmi)$/i,
|
ext: /\.(wav|aif|aiff|au|mp1|mp2|mp3|ra|rm|ram|mid|rmi)$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1jPvwr49YBuNjy0FfXXXIsVXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1jPvwr49YBuNjy0FfXXXIsVXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.(avi|wmv|mpg|mpeg|vob|dat|3gp|mp4|mkv|rm|rmvb|mov|flv)$/i,
|
ext: /\.(avi|wmv|mpg|mpeg|vob|dat|3gp|mp4|mkv|rm|rmvb|mov|flv)$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB1FrT5r9BYBeNjy0FeXXbnmFXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB1FrT5r9BYBeNjy0FeXXbnmFXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.(zip|rar|arj|z|gz|iso|jar|ace|tar|uue|dmg|pkg|lzh|cab)$/i,
|
ext: /\.(zip|rar|arj|z|gz|iso|jar|ace|tar|uue|dmg|pkg|lzh|cab)$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB10jmfr29TBuNjy0FcXXbeiFXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB10jmfr29TBuNjy0FcXXbeiFXa-200-200.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ext: /\.[^.]+$/i,
|
ext: /\.[^.]+$/i,
|
||||||
icon: '//img.alicdn.com/tfs/TB10.R4r3mTBuNjy1XbXXaMrVXa-200-200.png'
|
icon: '//img.alicdn.com/tfs/TB10.R4r3mTBuNjy1XbXXaMrVXa-200-200.png',
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
const testOpts = (ext, options) => {
|
const testOpts = (ext, options) => {
|
||||||
if (options && isArr(options.include)) {
|
if (options && isArr(options.include)) {
|
||||||
return options.include.some(url => ext.test(url))
|
return options.include.some(url => ext.test(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options && isArr(options.exclude)) {
|
if (options && isArr(options.exclude)) {
|
||||||
return !options.exclude.some(url => ext.test(url))
|
return !options.exclude.some(url => ext.test(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const testUrl = (url, options) => {
|
export const testUrl = (url, options) => {
|
||||||
for (let i = 0; i < exts.length; i++) {
|
for (let i = 0; i < exts.length; i++) {
|
||||||
@ -96,24 +96,24 @@ export const testUrl = (url, options) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getImageByUrl = (url, options) => {
|
export const getImageByUrl = (url, options) => {
|
||||||
for (let i = 0; i < exts.length; i++) {
|
for (let i = 0; i < exts.length; i++) {
|
||||||
if (exts[i].ext.test(url) && testOpts(exts[i].ext, options)) {
|
if (exts[i].ext.test(url) && testOpts(exts[i].ext, options)) {
|
||||||
return exts[i].icon || url
|
return exts[i].icon || url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return url
|
return url;
|
||||||
}
|
};
|
||||||
|
|
||||||
function toFileObject(item) {
|
function toFileObject(item) {
|
||||||
console.log(item);
|
console.log(item);
|
||||||
if (typeof item === 'number') {
|
if (typeof item === 'number') {
|
||||||
return {
|
return {
|
||||||
id: item,
|
id: item,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
if (item.id && item.uid && item.url) {
|
if (item.id && item.uid && item.url) {
|
||||||
return item;
|
return item;
|
||||||
@ -145,7 +145,7 @@ function toValue(item) {
|
|||||||
if (typeof item === 'number') {
|
if (typeof item === 'number') {
|
||||||
return {
|
return {
|
||||||
id: item,
|
id: item,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
if (item.id && item.uid && item.url) {
|
if (item.id && item.uid && item.url) {
|
||||||
return item;
|
return item;
|
||||||
@ -176,14 +176,18 @@ function toValues(fileList) {
|
|||||||
|
|
||||||
export function getImgUrls(value) {
|
export function getImgUrls(value) {
|
||||||
const values = Array.isArray(value) ? value : [value];
|
const values = Array.isArray(value) ? value : [value];
|
||||||
return values.filter(item => testUrl(item.url, {
|
return values
|
||||||
exclude: ['.png', '.jpg', '.jpeg', '.gif']
|
.filter(item =>
|
||||||
})).map(item => toValue(item));
|
testUrl(item.url, {
|
||||||
|
exclude: ['.png', '.jpg', '.jpeg', '.gif'],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.map(item => toValue(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Upload = connect({
|
export const Upload = connect({
|
||||||
getProps: mapStyledProps
|
getProps: mapStyledProps,
|
||||||
})((props) => {
|
})(props => {
|
||||||
const { multiple = true, value, onChange } = props;
|
const { multiple = true, value, onChange } = props;
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [imgIndex, setImgIndex] = useState(0);
|
const [imgIndex, setImgIndex] = useState(0);
|
||||||
@ -193,9 +197,9 @@ export const Upload = connect({
|
|||||||
action: `${process.env.API}/attachments:upload`,
|
action: `${process.env.API}/attachments:upload`,
|
||||||
onChange({ fileList }) {
|
onChange({ fileList }) {
|
||||||
console.log(fileList);
|
console.log(fileList);
|
||||||
setFileList((fileList));
|
setFileList(fileList);
|
||||||
const list = toValues(fileList);
|
const list = toValues(fileList);
|
||||||
onChange(multiple ? list : (list.shift()||null));
|
onChange(multiple ? list : list.shift() || null);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const images = getImgUrls(fileList);
|
const images = getImgUrls(fileList);
|
||||||
@ -207,14 +211,14 @@ export const Upload = connect({
|
|||||||
{...uploadProps}
|
{...uploadProps}
|
||||||
fileList={fileList}
|
fileList={fileList}
|
||||||
multiple={true}
|
multiple={true}
|
||||||
onPreview={(file) => {
|
onPreview={file => {
|
||||||
const value = toValue(file) || {};
|
const value = toValue(file) || {};
|
||||||
const index = findIndex(images, image => image.id === value.id);
|
const index = findIndex(images, image => image.id === value.id);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
setImgIndex(index);
|
setImgIndex(index);
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
window.open(value.url)
|
window.open(value.url);
|
||||||
// window.location.href = value.url;
|
// window.location.href = value.url;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -237,7 +241,8 @@ export const Upload = connect({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</AntdUpload>
|
</AntdUpload>
|
||||||
{visible && <Lightbox
|
{visible && (
|
||||||
|
<Lightbox
|
||||||
mainSrc={get(images, [imgIndex, 'url'])}
|
mainSrc={get(images, [imgIndex, 'url'])}
|
||||||
nextSrc={get(images, [imgIndex + 1, 'url'])}
|
nextSrc={get(images, [imgIndex + 1, 'url'])}
|
||||||
prevSrc={get(images, [imgIndex - 1, 'url'])}
|
prevSrc={get(images, [imgIndex - 1, 'url'])}
|
||||||
@ -248,9 +253,10 @@ export const Upload = connect({
|
|||||||
onMoveNextRequest={() => {
|
onMoveNextRequest={() => {
|
||||||
setImgIndex((imgIndex + 1) % images.length);
|
setImgIndex((imgIndex + 1) % images.length);
|
||||||
}}
|
}}
|
||||||
/>}
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Upload;
|
export default Upload;
|
@ -1 +1 @@
|
|||||||
import 'antd/lib/upload/style/index'
|
import 'antd/lib/upload/style/index';
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { Button, Select, Input, Space, Form, InputNumber, DatePicker, TimePicker, Radio } from 'antd';
|
import {
|
||||||
|
Button,
|
||||||
|
Select,
|
||||||
|
Input,
|
||||||
|
Space,
|
||||||
|
Form,
|
||||||
|
InputNumber,
|
||||||
|
DatePicker,
|
||||||
|
TimePicker,
|
||||||
|
Radio,
|
||||||
|
} from 'antd';
|
||||||
import { PlusCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
|
import { PlusCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
|
||||||
import useDynamicList from './useDynamicList';
|
import useDynamicList from './useDynamicList';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import { mapStyledProps } from '../shared'
|
import { mapStyledProps } from '../shared';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
@ -11,8 +21,17 @@ import api from '@/api-client';
|
|||||||
import { useRequest } from 'umi';
|
import { useRequest } from 'umi';
|
||||||
|
|
||||||
export function FilterGroup(props: any) {
|
export function FilterGroup(props: any) {
|
||||||
const { fields = [], sourceFields = [], onDelete, onChange, onAdd, dataSource = [] } = props;
|
const {
|
||||||
const { list, getKey, push, remove, replace } = useDynamicList<any>(dataSource);
|
fields = [],
|
||||||
|
sourceFields = [],
|
||||||
|
onDelete,
|
||||||
|
onChange,
|
||||||
|
onAdd,
|
||||||
|
dataSource = [],
|
||||||
|
} = props;
|
||||||
|
const { list, getKey, push, remove, replace } = useDynamicList<any>(
|
||||||
|
dataSource,
|
||||||
|
);
|
||||||
let style: any = {
|
let style: any = {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
};
|
};
|
||||||
@ -24,12 +43,13 @@ export function FilterGroup(props: any) {
|
|||||||
// const Component = item.type === 'group' ? FilterGroup : FilterItem;
|
// const Component = item.type === 'group' ? FilterGroup : FilterItem;
|
||||||
return (
|
return (
|
||||||
<div style={{ marginBottom: 8 }}>
|
<div style={{ marginBottom: 8 }}>
|
||||||
{<FilterItem
|
{
|
||||||
|
<FilterItem
|
||||||
fields={fields}
|
fields={fields}
|
||||||
sourceFields={sourceFields}
|
sourceFields={sourceFields}
|
||||||
dataSource={item}
|
dataSource={item}
|
||||||
// showDeleteButton={list.length > 1}
|
// showDeleteButton={list.length > 1}
|
||||||
onChange={(value) => {
|
onChange={value => {
|
||||||
replace(index, value);
|
replace(index, value);
|
||||||
const newList = [...list];
|
const newList = [...list];
|
||||||
newList[index] = value;
|
newList[index] = value;
|
||||||
@ -43,20 +63,25 @@ export function FilterGroup(props: any) {
|
|||||||
onChange(newList);
|
onChange(newList);
|
||||||
// console.log(list, index);
|
// console.log(list, index);
|
||||||
}}
|
}}
|
||||||
/>}
|
/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Space>
|
<Space>
|
||||||
<Button style={{padding: 0}} type={'link'} onClick={() => {
|
<Button
|
||||||
|
style={{ padding: 0 }}
|
||||||
|
type={'link'}
|
||||||
|
onClick={() => {
|
||||||
const data = {};
|
const data = {};
|
||||||
push(data);
|
push(data);
|
||||||
const newList = [...list];
|
const newList = [...list];
|
||||||
newList.push(data);
|
newList.push(data);
|
||||||
onChange(newList);
|
onChange(newList);
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<PlusCircleOutlined /> 新增一个字段赋值
|
<PlusCircleOutlined /> 新增一个字段赋值
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
@ -175,22 +200,26 @@ const op = {
|
|||||||
attachment: OP_MAP.file,
|
attachment: OP_MAP.file,
|
||||||
};
|
};
|
||||||
|
|
||||||
const StringInput = (props) => {
|
const StringInput = props => {
|
||||||
const { value, onChange, ...restProps } = props;
|
const { value, onChange, ...restProps } = props;
|
||||||
return (
|
return (
|
||||||
<Input {...restProps} defaultValue={value} onChange={(e) => {
|
<Input
|
||||||
|
{...restProps}
|
||||||
|
defaultValue={value}
|
||||||
|
onChange={e => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}/>
|
}}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const controls = {
|
const controls = {
|
||||||
string: StringInput,
|
string: StringInput,
|
||||||
textarea: StringInput,
|
textarea: StringInput,
|
||||||
number: InputNumber,
|
number: InputNumber,
|
||||||
percent: (props) => (
|
percent: props => (
|
||||||
<InputNumber
|
<InputNumber
|
||||||
formatter={value => value ? `${value}%` : ''}
|
formatter={value => (value ? `${value}%` : '')}
|
||||||
parser={value => value.replace('%', '')}
|
parser={value => value.replace('%', '')}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
@ -213,9 +242,13 @@ function DateControl(props: any) {
|
|||||||
// }
|
// }
|
||||||
const m = moment(value, format);
|
const m = moment(value, format);
|
||||||
return (
|
return (
|
||||||
<DatePicker format={format} value={m.isValid() ? m : null} onChange={(value) => {
|
<DatePicker
|
||||||
onChange(value ? value.format('YYYY-MM-DD') : null)
|
format={format}
|
||||||
}}/>
|
value={m.isValid() ? m : null}
|
||||||
|
onChange={value => {
|
||||||
|
onChange(value ? value.format('YYYY-MM-DD') : null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
// return (
|
// return (
|
||||||
// <DatePicker format={format} showTime={field.showTime} value={m.isValid() ? m : null} onChange={(value) => {
|
// <DatePicker format={format} showTime={field.showTime} value={m.isValid() ? m : null} onChange={(value) => {
|
||||||
@ -228,13 +261,15 @@ function TimeControl(props: any) {
|
|||||||
const { field, value, onChange, ...restProps } = props;
|
const { field, value, onChange, ...restProps } = props;
|
||||||
let format = field.timeFormat;
|
let format = field.timeFormat;
|
||||||
const m = moment(value, format);
|
const m = moment(value, format);
|
||||||
return <TimePicker
|
return (
|
||||||
|
<TimePicker
|
||||||
value={m.isValid() ? m : null}
|
value={m.isValid() ? m : null}
|
||||||
format={field.timeFormat}
|
format={field.timeFormat}
|
||||||
onChange={(value) => {
|
onChange={value => {
|
||||||
onChange(value ? value.format('HH:mm:ss') : null)
|
onChange(value ? value.format('HH:mm:ss') : null);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function OptionControl(props) {
|
function OptionControl(props) {
|
||||||
@ -244,19 +279,27 @@ function OptionControl(props) {
|
|||||||
mode = undefined;
|
mode = undefined;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Select style={{ minWidth: 120 }} mode={mode} value={value} onChange={(value) => {
|
<Select
|
||||||
|
style={{ minWidth: 120 }}
|
||||||
|
mode={mode}
|
||||||
|
value={value}
|
||||||
|
onChange={value => {
|
||||||
onChange(value);
|
onChange(value);
|
||||||
}} options={options}>
|
}}
|
||||||
</Select>
|
options={options}
|
||||||
|
></Select>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function BooleanControl(props) {
|
function BooleanControl(props) {
|
||||||
const { value, onChange, ...restProps } = props;
|
const { value, onChange, ...restProps } = props;
|
||||||
return (
|
return (
|
||||||
<Radio.Group value={value} onChange={(e) => {
|
<Radio.Group
|
||||||
|
value={value}
|
||||||
|
onChange={e => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<Radio value={true}>是</Radio>
|
<Radio value={true}>是</Radio>
|
||||||
<Radio value={false}>否</Radio>
|
<Radio value={false}>否</Radio>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
@ -268,7 +311,14 @@ function NullControl(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function FilterItem(props: FilterItemProps) {
|
export function FilterItem(props: FilterItemProps) {
|
||||||
const { index, fields = [], sourceFields = [], showDeleteButton = true, onDelete, onChange } = props;
|
const {
|
||||||
|
index,
|
||||||
|
fields = [],
|
||||||
|
sourceFields = [],
|
||||||
|
showDeleteButton = true,
|
||||||
|
onDelete,
|
||||||
|
onChange,
|
||||||
|
} = props;
|
||||||
const [type, setType] = useState('string');
|
const [type, setType] = useState('string');
|
||||||
const [field, setField] = useState<any>({});
|
const [field, setField] = useState<any>({});
|
||||||
const [dataSource, setDataSource] = useState(props.dataSource || {});
|
const [dataSource, setDataSource] = useState(props.dataSource || {});
|
||||||
@ -283,27 +333,27 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
setType(componentType);
|
setType(componentType);
|
||||||
}
|
}
|
||||||
setDataSource({ ...props.dataSource });
|
setDataSource({ ...props.dataSource });
|
||||||
}, [
|
}, [props.dataSource, type]);
|
||||||
props.dataSource, type,
|
|
||||||
]);
|
|
||||||
let ValueControl = controls[type] || controls.string;
|
let ValueControl = controls[type] || controls.string;
|
||||||
if (['truncate'].indexOf(dataSource.op) !== -1) {
|
if (['truncate'].indexOf(dataSource.op) !== -1) {
|
||||||
ValueControl = NullControl;
|
ValueControl = NullControl;
|
||||||
} else if (dataSource.op === 'ref') {
|
} else if (dataSource.op === 'ref') {
|
||||||
ValueControl = () => {
|
ValueControl = () => {
|
||||||
return (
|
return (
|
||||||
<Select value={dataSource.value}
|
<Select
|
||||||
onChange={(value) => {
|
value={dataSource.value}
|
||||||
|
onChange={value => {
|
||||||
onChange({ ...dataSource, value: value });
|
onChange({ ...dataSource, value: value });
|
||||||
}}
|
}}
|
||||||
style={{ width: 120 }}
|
style={{ width: 120 }}
|
||||||
placeholder={'选择字段'}>
|
placeholder={'选择字段'}
|
||||||
|
>
|
||||||
{sourceFields.map(field => (
|
{sourceFields.map(field => (
|
||||||
<Select.Option value={field.name}>{field.title}</Select.Option>
|
<Select.Option value={field.name}>{field.title}</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
// let multiple = true;
|
// let multiple = true;
|
||||||
// if ()
|
// if ()
|
||||||
@ -316,24 +366,33 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
console.log({ field, dataSource, type, ValueControl });
|
console.log({ field, dataSource, type, ValueControl });
|
||||||
return (
|
return (
|
||||||
<Space>
|
<Space>
|
||||||
<Select value={dataSource.column}
|
<Select
|
||||||
onChange={(value) => {
|
value={dataSource.column}
|
||||||
|
onChange={value => {
|
||||||
const field = fields.find(field => field.name === value);
|
const field = fields.find(field => field.name === value);
|
||||||
let componentType = field.component.type;
|
let componentType = field.component.type;
|
||||||
if (field.component.type === 'select' && field.multiple) {
|
if (field.component.type === 'select' && field.multiple) {
|
||||||
componentType = 'multipleSelect';
|
componentType = 'multipleSelect';
|
||||||
}
|
}
|
||||||
setType(componentType);
|
setType(componentType);
|
||||||
onChange({...dataSource, column: value, op: get(opOptions, [0, 'value']), value: undefined});
|
onChange({
|
||||||
|
...dataSource,
|
||||||
|
column: value,
|
||||||
|
op: get(opOptions, [0, 'value']),
|
||||||
|
value: undefined,
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
style={{ width: 120 }}
|
style={{ width: 120 }}
|
||||||
placeholder={'选择字段'}>
|
placeholder={'选择字段'}
|
||||||
|
>
|
||||||
{fields.map(field => (
|
{fields.map(field => (
|
||||||
<Select.Option value={field.name}>{field.title}</Select.Option>
|
<Select.Option value={field.name}>{field.title}</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<Select value={dataSource.column ? dataSource.op : null} style={{ minWidth: 130 }}
|
<Select
|
||||||
onChange={(value) => {
|
value={dataSource.column ? dataSource.op : null}
|
||||||
|
style={{ minWidth: 130 }}
|
||||||
|
onChange={value => {
|
||||||
onChange({ ...dataSource, op: value, value: undefined });
|
onChange({ ...dataSource, op: value, value: undefined });
|
||||||
}}
|
}}
|
||||||
defaultValue={get(opOptions, [0, 'value'])}
|
defaultValue={get(opOptions, [0, 'value'])}
|
||||||
@ -349,15 +408,22 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
op={dataSource.op}
|
op={dataSource.op}
|
||||||
options={field.dataSource}
|
options={field.dataSource}
|
||||||
value={dataSource.value}
|
value={dataSource.value}
|
||||||
onChange={(value) => {
|
onChange={value => {
|
||||||
onChange({ ...dataSource, value: value });
|
onChange({ ...dataSource, value: value });
|
||||||
}}
|
}}
|
||||||
style={{ width: 180 }}
|
style={{ width: 180 }}
|
||||||
/>
|
/>
|
||||||
{showDeleteButton && (
|
{showDeleteButton && (
|
||||||
<Button className={'filter-remove-link filter-item'} type={'link'} style={{padding: 0}} onClick={(e) => {
|
<Button
|
||||||
|
className={'filter-remove-link filter-item'}
|
||||||
|
type={'link'}
|
||||||
|
style={{ padding: 0 }}
|
||||||
|
onClick={e => {
|
||||||
onDelete && onDelete(e);
|
onDelete && onDelete(e);
|
||||||
}}><CloseCircleOutlined /></Button>
|
}}
|
||||||
|
>
|
||||||
|
<CloseCircleOutlined />
|
||||||
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
@ -365,35 +431,65 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
|
|
||||||
export const Values = connect({
|
export const Values = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
})((props) => {
|
})(props => {
|
||||||
|
const {
|
||||||
|
value = [],
|
||||||
|
onChange,
|
||||||
|
associatedKey,
|
||||||
|
sourceName,
|
||||||
|
sourceFilter = {},
|
||||||
|
filter = {},
|
||||||
|
fields = [],
|
||||||
|
...restProps
|
||||||
|
} = props;
|
||||||
|
|
||||||
const { value = [], onChange, associatedKey, sourceName, sourceFilter = {}, filter = {}, fields = [], ...restProps } = props;
|
const { data = [], loading = true } = useRequest(
|
||||||
|
() => {
|
||||||
const { data = [], loading = true } = useRequest(() => {
|
return associatedKey
|
||||||
return associatedKey ? api.resource(`collections.fields`).list({
|
? api.resource(`collections.fields`).list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
filter,
|
filter,
|
||||||
}) : Promise.resolve({
|
})
|
||||||
|
: Promise.resolve({
|
||||||
data: fields,
|
data: fields,
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
refreshDeps: [associatedKey]
|
{
|
||||||
});
|
refreshDeps: [associatedKey],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const { data: sourceFields = [] } = useRequest(() => {
|
const { data: sourceFields = [] } = useRequest(
|
||||||
return sourceName ? api.resource(`collections.fields`).list({
|
() => {
|
||||||
|
return sourceName
|
||||||
|
? api.resource(`collections.fields`).list({
|
||||||
associatedKey: sourceName,
|
associatedKey: sourceName,
|
||||||
filter: sourceFilter,
|
filter: sourceFilter,
|
||||||
}) : Promise.resolve({
|
})
|
||||||
|
: Promise.resolve({
|
||||||
data: [],
|
data: [],
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
refreshDeps: [sourceName]
|
{
|
||||||
});
|
refreshDeps: [sourceName],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return <FilterGroup dataSource={Array.isArray(value) ? value.filter(item => Object.keys(item).length) : []} onChange={(values) => {
|
return (
|
||||||
|
<FilterGroup
|
||||||
|
dataSource={
|
||||||
|
Array.isArray(value)
|
||||||
|
? value.filter(item => Object.keys(item).length)
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
onChange={values => {
|
||||||
onChange(values.filter(item => Object.keys(item).length));
|
onChange(values.filter(item => Object.keys(item).length));
|
||||||
}} {...restProps} fields={data} sourceFields={sourceFields}/>
|
}}
|
||||||
|
{...restProps}
|
||||||
|
fields={data}
|
||||||
|
sourceFields={sourceFields}
|
||||||
|
/>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Values;
|
export default Values;
|
||||||
|
@ -30,7 +30,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const insert = (index: number, obj: T) => {
|
const insert = (index: number, obj: T) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const temp = [...l];
|
const temp = [...l];
|
||||||
temp.splice(index, 0, obj);
|
temp.splice(index, 0, obj);
|
||||||
setKey(index);
|
setKey(index);
|
||||||
@ -40,10 +40,11 @@ export default <T>(initialValue: T[]) => {
|
|||||||
|
|
||||||
const getAll = () => list;
|
const getAll = () => list;
|
||||||
const getKey = (index: number) => keyList.current[index];
|
const getKey = (index: number) => keyList.current[index];
|
||||||
const getIndex = (index: number) => keyList.current.findIndex((ele) => ele === index);
|
const getIndex = (index: number) =>
|
||||||
|
keyList.current.findIndex(ele => ele === index);
|
||||||
|
|
||||||
const merge = (index: number, obj: T[]) => {
|
const merge = (index: number, obj: T[]) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const temp = [...l];
|
const temp = [...l];
|
||||||
obj.forEach((_, i) => {
|
obj.forEach((_, i) => {
|
||||||
setKey(index + i);
|
setKey(index + i);
|
||||||
@ -54,7 +55,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const replace = (index: number, obj: T) => {
|
const replace = (index: number, obj: T) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const temp = [...l];
|
const temp = [...l];
|
||||||
temp[index] = obj;
|
temp[index] = obj;
|
||||||
return temp;
|
return temp;
|
||||||
@ -62,7 +63,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const remove = (index: number) => {
|
const remove = (index: number) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const temp = [...l];
|
const temp = [...l];
|
||||||
temp.splice(index, 1);
|
temp.splice(index, 1);
|
||||||
|
|
||||||
@ -80,14 +81,16 @@ export default <T>(initialValue: T[]) => {
|
|||||||
if (oldIndex === newIndex) {
|
if (oldIndex === newIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
const newList = [...l];
|
const newList = [...l];
|
||||||
const temp = newList.filter((_: {}, index: number) => index !== oldIndex);
|
const temp = newList.filter((_: {}, index: number) => index !== oldIndex);
|
||||||
temp.splice(newIndex, 0, newList[oldIndex]);
|
temp.splice(newIndex, 0, newList[oldIndex]);
|
||||||
|
|
||||||
// move keys if necessary
|
// move keys if necessary
|
||||||
try {
|
try {
|
||||||
const keyTemp = keyList.current.filter((_: {}, index: number) => index !== oldIndex);
|
const keyTemp = keyList.current.filter(
|
||||||
|
(_: {}, index: number) => index !== oldIndex,
|
||||||
|
);
|
||||||
keyTemp.splice(newIndex, 0, keyList.current[oldIndex]);
|
keyTemp.splice(newIndex, 0, keyList.current[oldIndex]);
|
||||||
keyList.current = keyTemp;
|
keyList.current = keyTemp;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -99,7 +102,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const push = (obj: T) => {
|
const push = (obj: T) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
setKey(l.length);
|
setKey(l.length);
|
||||||
return l.concat([obj]);
|
return l.concat([obj]);
|
||||||
});
|
});
|
||||||
@ -113,11 +116,11 @@ export default <T>(initialValue: T[]) => {
|
|||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
setList((l) => l.slice(0, l.length - 1));
|
setList(l => l.slice(0, l.length - 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
const unshift = (obj: T) => {
|
const unshift = (obj: T) => {
|
||||||
setList((l) => {
|
setList(l => {
|
||||||
setKey(0);
|
setKey(0);
|
||||||
return [obj].concat(l);
|
return [obj].concat(l);
|
||||||
});
|
});
|
||||||
@ -127,8 +130,8 @@ export default <T>(initialValue: T[]) => {
|
|||||||
result
|
result
|
||||||
.map((item, index) => ({ key: index, item })) // add index into obj
|
.map((item, index) => ({ key: index, item })) // add index into obj
|
||||||
.sort((a, b) => getIndex(a.key) - getIndex(b.key)) // sort based on the index of table
|
.sort((a, b) => getIndex(a.key) - getIndex(b.key)) // sort based on the index of table
|
||||||
.filter((item) => !!item.item) // remove undefined(s)
|
.filter(item => !!item.item) // remove undefined(s)
|
||||||
.map((item) => item.item); // retrive the data
|
.map(item => item.item); // retrive the data
|
||||||
|
|
||||||
const shift = () => {
|
const shift = () => {
|
||||||
// remove keys if necessary
|
// remove keys if necessary
|
||||||
@ -137,7 +140,7 @@ export default <T>(initialValue: T[]) => {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
setList((l) => l.slice(1, l.length));
|
setList(l => l.slice(1, l.length));
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Input as AntdInput } from 'antd'
|
import { Input as AntdInput } from 'antd';
|
||||||
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared'
|
import { acceptEnum, mapStyledProps, mapTextComponent } from '../shared';
|
||||||
|
|
||||||
export const Wysiwyg = connect({
|
export const Wysiwyg = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
getComponent: mapTextComponent
|
getComponent: mapTextComponent,
|
||||||
})(acceptEnum((props) => <AntdInput.TextArea autoSize={{minRows: 2, maxRows: 12}} {...props}/>))
|
})(
|
||||||
|
acceptEnum(props => (
|
||||||
|
<AntdInput.TextArea autoSize={{ minRows: 2, maxRows: 12 }} {...props} />
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
export default Wysiwyg
|
export default Wysiwyg;
|
||||||
|
@ -13,9 +13,7 @@ import {
|
|||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
|
|
||||||
export const IconFont = createFromIconfontCN({
|
export const IconFont = createFromIconfontCN({
|
||||||
scriptUrl: [
|
scriptUrl: ['//at.alicdn.com/t/font_2261954_u9jzwc44ug.js'],
|
||||||
'//at.alicdn.com/t/font_2261954_u9jzwc44ug.js',
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const icons = new Map<string, any>();
|
export const icons = new Map<string, any>();
|
||||||
|
@ -20,8 +20,12 @@ export default (props: any) => {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Menu
|
<Menu
|
||||||
defaultSelectedKeys={paths.filter(path => pathcamp(location.pathname, path)).concat(location.pathname)}
|
defaultSelectedKeys={paths
|
||||||
defaultOpenKeys={paths.filter(path => pathcamp(location.pathname, path)).concat(location.pathname)}
|
.filter(path => pathcamp(location.pathname, path))
|
||||||
|
.concat(location.pathname)}
|
||||||
|
defaultOpenKeys={paths
|
||||||
|
.filter(path => pathcamp(location.pathname, path))
|
||||||
|
.concat(location.pathname)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{items.map(item => {
|
{items.map(item => {
|
||||||
@ -32,20 +36,24 @@ export default (props: any) => {
|
|||||||
const subItems = children.filter(child => child.showInMenu);
|
const subItems = children.filter(child => child.showInMenu);
|
||||||
if (!hideChildren && subItems.length > 1) {
|
if (!hideChildren && subItems.length > 1) {
|
||||||
return (
|
return (
|
||||||
<Menu.SubMenu key={`${item.path}`} icon={<Icon type={item.icon}/>} title={<>{item.title}</>}>
|
<Menu.SubMenu
|
||||||
|
key={`${item.path}`}
|
||||||
|
icon={<Icon type={item.icon} />}
|
||||||
|
title={<>{item.title}</>}
|
||||||
|
>
|
||||||
{subItems.map((child: any) => (
|
{subItems.map((child: any) => (
|
||||||
<Menu.Item key={child.path}>
|
<Menu.Item key={child.path}>
|
||||||
<Link to={child.path}>{child.title}</Link>
|
<Link to={child.path}>{child.title}</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
))}
|
))}
|
||||||
</Menu.SubMenu>
|
</Menu.SubMenu>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Menu.Item icon={<Icon type={item.icon} />} key={item.path}>
|
<Menu.Item icon={<Icon type={item.icon} />} key={item.path}>
|
||||||
<Link to={item.path}>{item.title}</Link>
|
<Link to={item.path}>{item.title}</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Space, Button, Popconfirm, Popover } from 'antd';
|
import { Space, Button, Popconfirm, Popover } from 'antd';
|
||||||
import { FilterOutlined, PlusOutlined, SelectOutlined, DeleteOutlined } from '@ant-design/icons';
|
import {
|
||||||
|
FilterOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
SelectOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
||||||
import View from '@/components/pages/AdminLoader/View';
|
import View from '@/components/pages/AdminLoader/View';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
@ -26,25 +31,29 @@ export function Create(props) {
|
|||||||
associatedKey={associatedKey}
|
associatedKey={associatedKey}
|
||||||
viewName={viewName}
|
viewName={viewName}
|
||||||
onReset={resolve}
|
onReset={resolve}
|
||||||
onDraft={async (item) => {
|
onDraft={async item => {
|
||||||
const values = transform ? {} : item;
|
const values = transform ? {} : item;
|
||||||
for (const [sourceKey, targetKey] of Object.entries<string>(transform || {})) {
|
for (const [sourceKey, targetKey] of Object.entries<string>(
|
||||||
|
transform || {},
|
||||||
|
)) {
|
||||||
const value = get({ data: item }, sourceKey);
|
const value = get({ data: item }, sourceKey);
|
||||||
set(values, targetKey, value);
|
set(values, targetKey, value);
|
||||||
}
|
}
|
||||||
await resolve();
|
await resolve();
|
||||||
console.log('onFinish', values);
|
console.log('onFinish', values);
|
||||||
onFinish && await onFinish(values);
|
onFinish && (await onFinish(values));
|
||||||
}}
|
}}
|
||||||
onFinish={async (item) => {
|
onFinish={async item => {
|
||||||
const values = transform ? {} : item;
|
const values = transform ? {} : item;
|
||||||
for (const [sourceKey, targetKey] of Object.entries<string>(transform || {})) {
|
for (const [sourceKey, targetKey] of Object.entries<string>(
|
||||||
|
transform || {},
|
||||||
|
)) {
|
||||||
const value = get({ data: item }, sourceKey);
|
const value = get({ data: item }, sourceKey);
|
||||||
set(values, targetKey, value);
|
set(values, targetKey, value);
|
||||||
}
|
}
|
||||||
await resolve();
|
await resolve();
|
||||||
console.log('onFinish', values);
|
console.log('onFinish', values);
|
||||||
onFinish && await onFinish(values);
|
onFinish && (await onFinish(values));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -54,9 +63,11 @@ export function Create(props) {
|
|||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
type={'primary'}
|
type={'primary'}
|
||||||
{...componentProps}
|
{...componentProps}
|
||||||
>{ title }</Button>
|
>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Update(props) {
|
export function Update(props) {
|
||||||
@ -76,16 +87,16 @@ export function Update(props) {
|
|||||||
data={data}
|
data={data}
|
||||||
viewName={viewName}
|
viewName={viewName}
|
||||||
onReset={resolve}
|
onReset={resolve}
|
||||||
onDraft={async (values) => {
|
onDraft={async values => {
|
||||||
await resolve();
|
await resolve();
|
||||||
onFinish && await onFinish(values);
|
onFinish && (await onFinish(values));
|
||||||
}}
|
}}
|
||||||
onValueChange={() => {
|
onValueChange={() => {
|
||||||
closeWithConfirm && closeWithConfirm(true);
|
closeWithConfirm && closeWithConfirm(true);
|
||||||
}}
|
}}
|
||||||
onFinish={async (values) => {
|
onFinish={async values => {
|
||||||
await resolve();
|
await resolve();
|
||||||
onFinish && await onFinish(values);
|
onFinish && (await onFinish(values));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -94,9 +105,11 @@ export function Update(props) {
|
|||||||
}}
|
}}
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
type={'primary'}
|
type={'primary'}
|
||||||
>{ title }</Button>
|
>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Add(props) {
|
export function Add(props) {
|
||||||
@ -119,29 +132,38 @@ export function Add(props) {
|
|||||||
defaultFilter={filter}
|
defaultFilter={filter}
|
||||||
viewName={viewName}
|
viewName={viewName}
|
||||||
associatedKey={associatedKey}
|
associatedKey={associatedKey}
|
||||||
onSelected={(values) => {
|
onSelected={values => {
|
||||||
console.log(values);
|
console.log(values);
|
||||||
setSelectedRows(values.map( item => {
|
setSelectedRows(
|
||||||
|
values.map(item => {
|
||||||
if (!transform) {
|
if (!transform) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const data = {};
|
const data = {};
|
||||||
for (const [sourceKey, targetKey] of Object.entries<string>(transform)) {
|
for (const [sourceKey, targetKey] of Object.entries<
|
||||||
|
string
|
||||||
|
>(transform)) {
|
||||||
const value = get({ data: item }, sourceKey);
|
const value = get({ data: item }, sourceKey);
|
||||||
set(data, targetKey, value);
|
set(data, targetKey, value);
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Drawer.Footer>
|
<Drawer.Footer>
|
||||||
<Space>
|
<Space>
|
||||||
<Button onClick={resolve}>取消</Button>
|
<Button onClick={resolve}>取消</Button>
|
||||||
<Button type={'primary'} onClick={async () => {
|
<Button
|
||||||
|
type={'primary'}
|
||||||
|
onClick={async () => {
|
||||||
console.log({ schema, onFinish });
|
console.log({ schema, onFinish });
|
||||||
onFinish && await onFinish(selectedRows);
|
onFinish && (await onFinish(selectedRows));
|
||||||
resolve();
|
resolve();
|
||||||
}}>确定</Button>
|
}}
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Drawer.Footer>
|
</Drawer.Footer>
|
||||||
</div>
|
</div>
|
||||||
@ -151,27 +173,34 @@ export function Add(props) {
|
|||||||
}}
|
}}
|
||||||
icon={<SelectOutlined />}
|
icon={<SelectOutlined />}
|
||||||
{...componentProps}
|
{...componentProps}
|
||||||
>{ title }</Button>
|
>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Destroy(props) {
|
export function Destroy(props) {
|
||||||
const { size, schema = {}, onFinish } = props;
|
const { size, schema = {}, onFinish } = props;
|
||||||
const { title, componentProps = {} } = schema;
|
const { title, componentProps = {} } = schema;
|
||||||
return (
|
return (
|
||||||
<Popconfirm title="确认删除吗?" onConfirm={async (e) => {
|
<Popconfirm
|
||||||
onFinish && await onFinish();
|
title="确认删除吗?"
|
||||||
}}>
|
onConfirm={async e => {
|
||||||
|
onFinish && (await onFinish());
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
size={size}
|
size={size}
|
||||||
danger
|
danger
|
||||||
type={'ghost'}
|
type={'ghost'}
|
||||||
icon={<DeleteOutlined />}
|
icon={<DeleteOutlined />}
|
||||||
{...componentProps}
|
{...componentProps}
|
||||||
>{ title }</Button>
|
>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Filter(props) {
|
export function Filter(props) {
|
||||||
@ -205,52 +234,60 @@ export function Filter(props) {
|
|||||||
defaultVisible={visible}
|
defaultVisible={visible}
|
||||||
placement={'bottomLeft'}
|
placement={'bottomLeft'}
|
||||||
destroyTooltipOnHide
|
destroyTooltipOnHide
|
||||||
onVisibleChange={(visible) => {
|
onVisibleChange={visible => {
|
||||||
setVisible(visible);
|
setVisible(visible);
|
||||||
}}
|
}}
|
||||||
className={'filters-popover'}
|
className={'filters-popover'}
|
||||||
style={{
|
style={{}}
|
||||||
}}
|
|
||||||
overlayStyle={{
|
overlayStyle={{
|
||||||
minWidth: 500
|
minWidth: 500,
|
||||||
}}
|
}}
|
||||||
content={(
|
content={
|
||||||
<>
|
<>
|
||||||
<View data={data} onFinish={async (values) => {
|
<View
|
||||||
|
data={data}
|
||||||
|
onFinish={async values => {
|
||||||
if (values) {
|
if (values) {
|
||||||
const items = values.filter.and || values.filter.or;
|
const items = values.filter.and || values.filter.or;
|
||||||
setFilterCount(Object.keys(items).length);
|
setFilterCount(Object.keys(items).length);
|
||||||
setData(values);
|
setData(values);
|
||||||
onFinish && await onFinish(values);
|
onFinish && (await onFinish(values));
|
||||||
}
|
}
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}} schema={{
|
}}
|
||||||
"type": "filterForm",
|
schema={{
|
||||||
"fields": [{
|
type: 'filterForm',
|
||||||
"dataIndex": ["filter"],
|
fields: [
|
||||||
"name": "filter",
|
{
|
||||||
"interface": "json",
|
dataIndex: ['filter'],
|
||||||
"type": "json",
|
name: 'filter',
|
||||||
"component": {
|
interface: 'json',
|
||||||
"type": "filter",
|
type: 'json',
|
||||||
|
component: {
|
||||||
|
type: 'filter',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
fields,
|
fields,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}],
|
},
|
||||||
}}/>
|
},
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
}
|
||||||
>
|
>
|
||||||
<Button icon={<FilterOutlined />} >{filterCount ? `${filterCount} 个${title}项` : title}</Button>
|
<Button icon={<FilterOutlined />}>
|
||||||
|
{filterCount ? `${filterCount} 个${title}项` : title}
|
||||||
|
</Button>
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Actions(props) {
|
export function Actions(props) {
|
||||||
const { onTrigger = {}, actions = [], style, ...restProps } = props;
|
const { onTrigger = {}, actions = [], style, ...restProps } = props;
|
||||||
return actions.length > 0 && (
|
return (
|
||||||
|
actions.length > 0 && (
|
||||||
<div className={'action-buttons'} style={style}>
|
<div className={'action-buttons'} style={style}>
|
||||||
{actions.map(action => (
|
{actions.map(action => (
|
||||||
<div className={`${action.type}-action-button action-button`}>
|
<div className={`${action.type}-action-button action-button`}>
|
||||||
@ -262,6 +299,7 @@ export function Actions(props) {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
import React, { Fragment, useLayoutEffect, useRef, useState } from 'react'
|
import React, { Fragment, useLayoutEffect, useRef, useState } from 'react';
|
||||||
import ReactDOM, { createPortal } from 'react-dom'
|
import ReactDOM, { createPortal } from 'react-dom';
|
||||||
import { createForm } from '@formily/core'
|
import { createForm } from '@formily/core';
|
||||||
// import { FormProvider } from '@formily/react'
|
// import { FormProvider } from '@formily/react'
|
||||||
import { isNum, isStr, isBool, isFn } from '@formily/shared'
|
import { isNum, isStr, isBool, isFn } from '@formily/shared';
|
||||||
import { Modal, Drawer } from 'antd'
|
import { Modal, Drawer } from 'antd';
|
||||||
import { DrawerProps } from 'antd/lib/drawer'
|
import { DrawerProps } from 'antd/lib/drawer';
|
||||||
import { useContext } from 'react'
|
import { useContext } from 'react';
|
||||||
import { ConfigProvider } from 'antd'
|
import { ConfigProvider } from 'antd';
|
||||||
import zhCN from 'antd/lib/locale/zh_CN';
|
import zhCN from 'antd/lib/locale/zh_CN';
|
||||||
|
|
||||||
export const usePrefixCls = (
|
export const usePrefixCls = (
|
||||||
tag?: string,
|
tag?: string,
|
||||||
props?: {
|
props?: {
|
||||||
prefixCls?: string
|
prefixCls?: string;
|
||||||
}
|
},
|
||||||
) => {
|
) => {
|
||||||
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext)
|
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
|
||||||
return getPrefixCls(tag, props?.prefixCls)
|
return getPrefixCls(tag, props?.prefixCls);
|
||||||
}
|
};
|
||||||
|
|
||||||
type DrawerTitle = string | number | React.ReactElement
|
type DrawerTitle = string | number | React.ReactElement;
|
||||||
|
|
||||||
const isDrawerTitle = (props: any): props is DrawerTitle => {
|
const isDrawerTitle = (props: any): props is DrawerTitle => {
|
||||||
return (
|
return (
|
||||||
isNum(props) || isStr(props) || isBool(props) || React.isValidElement(props)
|
isNum(props) || isStr(props) || isBool(props) || React.isValidElement(props)
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const getDrawerProps = (props: any): DrawerProps => {
|
const getDrawerProps = (props: any): DrawerProps => {
|
||||||
if (isDrawerTitle(props)) {
|
if (isDrawerTitle(props)) {
|
||||||
return {
|
return {
|
||||||
title: props,
|
title: props,
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
return props
|
return props;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const createElement = (content, props?: any) => {
|
const createElement = (content, props?: any) => {
|
||||||
if (!content) {
|
if (!content) {
|
||||||
@ -48,21 +48,15 @@ const createElement = (content, props?: any) => {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
return React.createElement(content, props);
|
return React.createElement(content, props);
|
||||||
}
|
};
|
||||||
|
|
||||||
export interface IFormDrawer {
|
export interface IFormDrawer {
|
||||||
open(props?: any): void
|
open(props?: any): void;
|
||||||
close(): void
|
close(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FormDrawer(
|
export function FormDrawer(title: DrawerProps, content: any): IFormDrawer;
|
||||||
title: DrawerProps,
|
export function FormDrawer(title: DrawerTitle, content: any): IFormDrawer;
|
||||||
content: any,
|
|
||||||
): IFormDrawer
|
|
||||||
export function FormDrawer(
|
|
||||||
title: DrawerTitle,
|
|
||||||
content: any,
|
|
||||||
): IFormDrawer
|
|
||||||
export function FormDrawer(title: any, content: any): IFormDrawer {
|
export function FormDrawer(title: any, content: any): IFormDrawer {
|
||||||
document.querySelectorAll('.env-root').forEach(el => {
|
document.querySelectorAll('.env-root').forEach(el => {
|
||||||
el.className = 'env-root env-root-push';
|
el.className = 'env-root env-root-push';
|
||||||
@ -70,24 +64,24 @@ export function FormDrawer(title: any, content: any): IFormDrawer {
|
|||||||
const env = {
|
const env = {
|
||||||
root: document.createElement('div'),
|
root: document.createElement('div'),
|
||||||
promise: null,
|
promise: null,
|
||||||
}
|
};
|
||||||
env.root.className = 'env-root';
|
env.root.className = 'env-root';
|
||||||
const props = getDrawerProps(title)
|
const props = getDrawerProps(title);
|
||||||
const drawer = {
|
const drawer = {
|
||||||
width: '75%',
|
width: '75%',
|
||||||
...props,
|
...props,
|
||||||
onClose: (e: any) => {
|
onClose: (e: any) => {
|
||||||
props?.onClose?.(e);
|
props?.onClose?.(e);
|
||||||
formDrawer.close()
|
formDrawer.close();
|
||||||
},
|
},
|
||||||
afterVisibleChange: (visible: boolean) => {
|
afterVisibleChange: (visible: boolean) => {
|
||||||
props?.afterVisibleChange?.(visible)
|
props?.afterVisibleChange?.(visible);
|
||||||
if (visible) return
|
if (visible) return;
|
||||||
ReactDOM.unmountComponentAtNode(env.root)
|
ReactDOM.unmountComponentAtNode(env.root);
|
||||||
env.root?.parentNode?.removeChild(env.root)
|
env.root?.parentNode?.removeChild(env.root);
|
||||||
env.root = undefined
|
env.root = undefined;
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const formDrawer = {
|
const formDrawer = {
|
||||||
open: (props: any) => {
|
open: (props: any) => {
|
||||||
@ -95,27 +89,27 @@ export function FormDrawer(title: any, content: any): IFormDrawer {
|
|||||||
false,
|
false,
|
||||||
() => {
|
() => {
|
||||||
formDrawer.closeWithConfirm = false;
|
formDrawer.closeWithConfirm = false;
|
||||||
formDrawer.close()
|
formDrawer.close();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
formDrawer.close()
|
formDrawer.close();
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
render(
|
render(
|
||||||
true,
|
true,
|
||||||
() => {
|
() => {
|
||||||
formDrawer.closeWithConfirm = false;
|
formDrawer.closeWithConfirm = false;
|
||||||
formDrawer.close()
|
formDrawer.close();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
formDrawer.close()
|
formDrawer.close();
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
close: () => {
|
close: () => {
|
||||||
if (!env.root) return
|
if (!env.root) return;
|
||||||
if (formDrawer.closeWithConfirm) {
|
if (formDrawer.closeWithConfirm) {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '表单内容发生变化,确定不保存吗?',
|
title: '表单内容发生变化,确定不保存吗?',
|
||||||
@ -128,7 +122,7 @@ export function FormDrawer(title: any, content: any): IFormDrawer {
|
|||||||
const last = els[els.length - 1];
|
const last = els[els.length - 1];
|
||||||
last.className = 'env-root';
|
last.className = 'env-root';
|
||||||
}
|
}
|
||||||
render(false)
|
render(false);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -137,15 +131,15 @@ export function FormDrawer(title: any, content: any): IFormDrawer {
|
|||||||
const last = els[els.length - 1];
|
const last = els[els.length - 1];
|
||||||
last.className = 'env-root';
|
last.className = 'env-root';
|
||||||
}
|
}
|
||||||
render(false)
|
render(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
closeWithConfirm: false,
|
closeWithConfirm: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
const closeWithConfirm = (bool) => {
|
const closeWithConfirm = bool => {
|
||||||
formDrawer.closeWithConfirm = bool;
|
formDrawer.closeWithConfirm = bool;
|
||||||
}
|
};
|
||||||
|
|
||||||
const render = (visible = true, resolve?: () => any, reject?: () => any) => {
|
const render = (visible = true, resolve?: () => any, reject?: () => any) => {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
@ -158,48 +152,48 @@ export function FormDrawer(title: any, content: any): IFormDrawer {
|
|||||||
})}
|
})}
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</ConfigProvider>,
|
</ConfigProvider>,
|
||||||
env.root
|
env.root,
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
document.body.appendChild(env.root)
|
document.body.appendChild(env.root);
|
||||||
|
|
||||||
return formDrawer
|
return formDrawer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DrawerFooter: React.FC = (props) => {
|
const DrawerFooter: React.FC = props => {
|
||||||
const ref = useRef<HTMLDivElement>()
|
const ref = useRef<HTMLDivElement>();
|
||||||
const [footer, setFooter] = useState<HTMLDivElement>()
|
const [footer, setFooter] = useState<HTMLDivElement>();
|
||||||
const footerRef = useRef<HTMLDivElement>()
|
const footerRef = useRef<HTMLDivElement>();
|
||||||
const prefixCls = usePrefixCls('drawer')
|
const prefixCls = usePrefixCls('drawer');
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const content = ref.current?.closest(`.${prefixCls}-wrapper-body`)
|
const content = ref.current?.closest(`.${prefixCls}-wrapper-body`);
|
||||||
if (content) {
|
if (content) {
|
||||||
if (!footerRef.current) {
|
if (!footerRef.current) {
|
||||||
footerRef.current = content.querySelector(`.${prefixCls}-footer`)
|
footerRef.current = content.querySelector(`.${prefixCls}-footer`);
|
||||||
if (!footerRef.current) {
|
if (!footerRef.current) {
|
||||||
footerRef.current = document.createElement('div')
|
footerRef.current = document.createElement('div');
|
||||||
footerRef.current.classList.add(`${prefixCls}-footer`)
|
footerRef.current.classList.add(`${prefixCls}-footer`);
|
||||||
content.appendChild(footerRef.current)
|
content.appendChild(footerRef.current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setFooter(footerRef.current)
|
setFooter(footerRef.current);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
footerRef.current = footer
|
footerRef.current = footer;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} style={{ display: 'none' }}>
|
<div ref={ref} style={{ display: 'none' }}>
|
||||||
{footer && createPortal(props.children, footer)}
|
{footer && createPortal(props.children, footer)}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
FormDrawer.open = (props) => {
|
FormDrawer.open = props => {
|
||||||
const { content, visible, ...rest } = props;
|
const { content, visible, ...rest } = props;
|
||||||
return FormDrawer(rest, content).open({ visible });
|
return FormDrawer(rest, content).open({ visible });
|
||||||
}
|
};
|
||||||
|
|
||||||
FormDrawer.Footer = DrawerFooter
|
FormDrawer.Footer = DrawerFooter;
|
||||||
|
|
||||||
export default FormDrawer
|
export default FormDrawer;
|
||||||
|
@ -11,14 +11,20 @@ import { markdown } from '@/components/views/Field';
|
|||||||
|
|
||||||
export function Page(props: any) {
|
export function Page(props: any) {
|
||||||
const { currentRowId, pageName, children, ...restProps } = props;
|
const { currentRowId, pageName, children, ...restProps } = props;
|
||||||
const { initialState = {}, refresh, setInitialState } = useModel('@@initialState');
|
const { initialState = {}, refresh, setInitialState } = useModel(
|
||||||
|
'@@initialState',
|
||||||
|
);
|
||||||
const siteTitle = get(initialState, 'systemSettings.title') || 'NocoBase';
|
const siteTitle = get(initialState, 'systemSettings.title') || 'NocoBase';
|
||||||
|
|
||||||
const { data = {}, loading, error } = useRequest(() => api.resource('menus').getInfo({
|
const { data = {}, loading, error } = useRequest(
|
||||||
|
() =>
|
||||||
|
api.resource('menus').getInfo({
|
||||||
resourceKey: pageName,
|
resourceKey: pageName,
|
||||||
}), {
|
}),
|
||||||
|
{
|
||||||
refreshDeps: [pageName],
|
refreshDeps: [pageName],
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
@ -27,7 +33,7 @@ export function Page(props: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Spin/>
|
return <Spin />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const views = data.views || [];
|
const views = data.views || [];
|
||||||
@ -35,13 +41,11 @@ export function Page(props: any) {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{data.title} - {siteTitle}</title>
|
<title>
|
||||||
|
{data.title} - {siteTitle}
|
||||||
|
</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<PageHeader
|
<PageHeader title={data.title} ghost={false} {...restProps} />
|
||||||
title={data.title}
|
|
||||||
ghost={false}
|
|
||||||
{...restProps}
|
|
||||||
/>
|
|
||||||
<div className={'page-content'}>
|
<div className={'page-content'}>
|
||||||
<Row className={'nb-row'} gutter={24}>
|
<Row className={'nb-row'} gutter={24}>
|
||||||
{views.map(view => {
|
{views.map(view => {
|
||||||
@ -49,7 +53,8 @@ export function Page(props: any) {
|
|||||||
let span = 24;
|
let span = 24;
|
||||||
if (typeof view === 'string') {
|
if (typeof view === 'string') {
|
||||||
viewName = view;
|
viewName = view;
|
||||||
} if (typeof view === 'object') {
|
}
|
||||||
|
if (typeof view === 'object') {
|
||||||
viewName = `${view.name}`;
|
viewName = `${view.name}`;
|
||||||
if (view.width === '50%') {
|
if (view.width === '50%') {
|
||||||
span = 12;
|
span = 12;
|
||||||
@ -67,10 +72,19 @@ export function Page(props: any) {
|
|||||||
message.success('草稿保存成功');
|
message.success('草稿保存成功');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (view.draft.returnType === 'message' && view.draft.message) {
|
if (
|
||||||
|
view.draft.returnType === 'message' &&
|
||||||
|
view.draft.message
|
||||||
|
) {
|
||||||
Modal.success({
|
Modal.success({
|
||||||
title: '草稿保存成功',
|
title: '草稿保存成功',
|
||||||
content: <div dangerouslySetInnerHTML={{__html: markdown(view.draft.message)}}/>,
|
content: (
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: markdown(view.draft.message),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
} else if (view.draft.returnType === 'redirect') {
|
} else if (view.draft.returnType === 'redirect') {
|
||||||
const path = get(view, 'draft.redirect.name');
|
const path = get(view, 'draft.redirect.name');
|
||||||
@ -81,7 +95,13 @@ export function Page(props: any) {
|
|||||||
if (view.returnType === 'message' && view.message) {
|
if (view.returnType === 'message' && view.message) {
|
||||||
Modal.success({
|
Modal.success({
|
||||||
title: '提交成功',
|
title: '提交成功',
|
||||||
content: <div dangerouslySetInnerHTML={{__html: markdown(view.message)}}/>,
|
content: (
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: markdown(view.message),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
} else if (view.returnType === 'redirect') {
|
} else if (view.returnType === 'redirect') {
|
||||||
const path = get(view, 'redirect.name');
|
const path = get(view, 'redirect.name');
|
||||||
@ -98,6 +118,6 @@ export function Page(props: any) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
@ -11,49 +11,90 @@ export function SideMenuLayout(props: any) {
|
|||||||
const { currentPageName, menu = [], menuId } = props;
|
const { currentPageName, menu = [], menuId } = props;
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
// console.log(menu);
|
// console.log(menu);
|
||||||
const [collapsed, setCollapsed] = useLocalStorageState(`nocobase-menu-collapsed-${menuId}`, false);
|
const [collapsed, setCollapsed] = useLocalStorageState(
|
||||||
|
`nocobase-menu-collapsed-${menuId}`,
|
||||||
|
false,
|
||||||
|
);
|
||||||
const responsive = useResponsive();
|
const responsive = useResponsive();
|
||||||
const isMobile = responsive.small && !responsive.middle && !responsive.large;
|
const isMobile = responsive.small && !responsive.middle && !responsive.large;
|
||||||
document.body.className = collapsed ? 'collapsed' : '';
|
document.body.className = collapsed ? 'collapsed' : '';
|
||||||
return (
|
return (
|
||||||
<Layout style={{ height: 'calc(100vh - 48px)' }}>
|
<Layout style={{ height: 'calc(100vh - 48px)' }}>
|
||||||
{!isMobile && <Layout.Sider className={`nb-sider${collapsed ? ' collapsed' : ''}`} theme={'light'}>
|
{!isMobile && (
|
||||||
<Menu menuId={menuId} currentPageName={currentPageName} items={menu} mode={'inline'}/>
|
<Layout.Sider
|
||||||
<div onClick={() => {
|
className={`nb-sider${collapsed ? ' collapsed' : ''}`}
|
||||||
|
theme={'light'}
|
||||||
|
>
|
||||||
|
<Menu
|
||||||
|
menuId={menuId}
|
||||||
|
currentPageName={currentPageName}
|
||||||
|
items={menu}
|
||||||
|
mode={'inline'}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
setCollapsed(!collapsed);
|
setCollapsed(!collapsed);
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
document.body.className = collapsed ? 'collapsed' : '';
|
document.body.className = collapsed ? 'collapsed' : '';
|
||||||
}} className={'menu-toggle'}>
|
}}
|
||||||
{React.createElement(collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
|
className={'menu-toggle'}
|
||||||
|
>
|
||||||
|
{React.createElement(
|
||||||
|
collapsed ? MenuUnfoldOutlined : MenuFoldOutlined,
|
||||||
|
{
|
||||||
style: { fontSize: 16 },
|
style: { fontSize: 16 },
|
||||||
})}
|
},
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Layout.Sider>}
|
</Layout.Sider>
|
||||||
|
)}
|
||||||
<Layout.Content id={'content'}>
|
<Layout.Content id={'content'}>
|
||||||
{props.children}
|
{props.children}
|
||||||
{isMobile && <Drawer visible={visible} onClose={() => {
|
{isMobile && (
|
||||||
|
<Drawer
|
||||||
|
visible={visible}
|
||||||
|
onClose={() => {
|
||||||
setCollapsed(!collapsed);
|
setCollapsed(!collapsed);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
document.body.className = collapsed ? 'collapsed' : '';
|
document.body.className = collapsed ? 'collapsed' : '';
|
||||||
}} placement={'left'} closable={false} bodyStyle={{padding: 0}}>
|
}}
|
||||||
<Menu onSelect={() => {
|
placement={'left'}
|
||||||
|
closable={false}
|
||||||
|
bodyStyle={{ padding: 0 }}
|
||||||
|
>
|
||||||
|
<Menu
|
||||||
|
onSelect={() => {
|
||||||
setCollapsed(false);
|
setCollapsed(false);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
document.body.className = collapsed ? 'collapsed' : '';
|
document.body.className = collapsed ? 'collapsed' : '';
|
||||||
}} currentPageName={currentPageName} menuId={menuId} items={menu} mode={'inline'}/>
|
}}
|
||||||
</Drawer>}
|
currentPageName={currentPageName}
|
||||||
{isMobile && <div onClick={() => {
|
menuId={menuId}
|
||||||
|
items={menu}
|
||||||
|
mode={'inline'}
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
)}
|
||||||
|
{isMobile && (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
setCollapsed(!collapsed);
|
setCollapsed(!collapsed);
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
document.body.className = collapsed ? 'collapsed' : '';
|
document.body.className = collapsed ? 'collapsed' : '';
|
||||||
}} className={'menu-toggle'}>
|
}}
|
||||||
{React.createElement(collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
|
className={'menu-toggle'}
|
||||||
|
>
|
||||||
|
{React.createElement(
|
||||||
|
collapsed ? MenuUnfoldOutlined : MenuFoldOutlined,
|
||||||
|
{
|
||||||
style: { fontSize: 16 },
|
style: { fontSize: 16 },
|
||||||
})}
|
},
|
||||||
</div>}
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default SideMenuLayout;
|
export default SideMenuLayout;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
box-shadow: 2px 0 8px 0 rgba(29,35,41,.05);
|
box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
|
||||||
&.collapsed {
|
&.collapsed {
|
||||||
margin-left: -200px;
|
margin-left: -200px;
|
||||||
}
|
}
|
||||||
|
@ -11,45 +11,87 @@ import get from 'lodash/get';
|
|||||||
|
|
||||||
export function TopMenuLayout(props: any) {
|
export function TopMenuLayout(props: any) {
|
||||||
const { currentPageName, menu = [] } = props;
|
const { currentPageName, menu = [] } = props;
|
||||||
console.log({menu})
|
console.log({ menu });
|
||||||
// const [visible, setVisible] = useState(false);
|
// const [visible, setVisible] = useState(false);
|
||||||
const [visible, setVisible] = useLocalStorageState(`nocobase-nav-visible`, false);
|
const [visible, setVisible] = useLocalStorageState(
|
||||||
|
`nocobase-nav-visible`,
|
||||||
|
false,
|
||||||
|
);
|
||||||
const responsive = useResponsive();
|
const responsive = useResponsive();
|
||||||
const isMobile = responsive.small && !responsive.middle && !responsive.large;
|
const isMobile = responsive.small && !responsive.middle && !responsive.large;
|
||||||
const { initialState = {}, loading, error, refresh, setInitialState } = useModel('@@initialState');
|
const {
|
||||||
|
initialState = {},
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
refresh,
|
||||||
|
setInitialState,
|
||||||
|
} = useModel('@@initialState');
|
||||||
const logoUrl = get(initialState, 'systemSettings.logo.url');
|
const logoUrl = get(initialState, 'systemSettings.logo.url');
|
||||||
console.log({ logoUrl });
|
console.log({ logoUrl });
|
||||||
return (
|
return (
|
||||||
<Layout style={{ height: '100vh' }}>
|
<Layout style={{ height: '100vh' }}>
|
||||||
<Layout.Header style={{height: 48, lineHeight: '48px', padding: 0}} className="nb-header">
|
<Layout.Header
|
||||||
|
style={{ height: 48, lineHeight: '48px', padding: 0 }}
|
||||||
|
className="nb-header"
|
||||||
|
>
|
||||||
<div className="logo" style={{ width: 200, height: 48, float: 'left' }}>
|
<div className="logo" style={{ width: 200, height: 48, float: 'left' }}>
|
||||||
{!logoUrl ? <Logo /> : <img src={logoUrl} />}
|
{!logoUrl ? <Logo /> : <img src={logoUrl} />}
|
||||||
</div>
|
</div>
|
||||||
{!isMobile && <Menu currentPageName={currentPageName} hideChildren={true} items={menu} className={'noco-top-menu'} style={{float: 'left'}} theme="dark" mode="horizontal"/>}
|
{!isMobile && (
|
||||||
|
<Menu
|
||||||
|
currentPageName={currentPageName}
|
||||||
|
hideChildren={true}
|
||||||
|
items={menu}
|
||||||
|
className={'noco-top-menu'}
|
||||||
|
style={{ float: 'left' }}
|
||||||
|
theme="dark"
|
||||||
|
mode="horizontal"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{!isMobile && <AvatarDropdown />}
|
{!isMobile && <AvatarDropdown />}
|
||||||
{isMobile && <MenuOutlined onClick={() => {
|
{isMobile && (
|
||||||
|
<MenuOutlined
|
||||||
|
onClick={() => {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}} style={{
|
}}
|
||||||
|
style={{
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
right: 16,
|
right: 16,
|
||||||
top: 16,
|
top: 16,
|
||||||
}}/>}
|
}}
|
||||||
{isMobile && <Drawer visible={visible} onClose={() => {
|
/>
|
||||||
|
)}
|
||||||
|
{isMobile && (
|
||||||
|
<Drawer
|
||||||
|
visible={visible}
|
||||||
|
onClose={() => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}} placement={'right'} closable={false} bodyStyle={{background: '#001529', padding: 0}}>
|
}}
|
||||||
<Menu currentPageName={currentPageName} onSelect={() => {
|
placement={'right'}
|
||||||
|
closable={false}
|
||||||
|
bodyStyle={{ background: '#001529', padding: 0 }}
|
||||||
|
>
|
||||||
|
<Menu
|
||||||
|
currentPageName={currentPageName}
|
||||||
|
onSelect={() => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}} mode={'inline'} hideChildren={true} items={menu} className={'noco-top-menu'} style={{float: 'left'}} theme="dark"/>
|
}}
|
||||||
|
mode={'inline'}
|
||||||
|
hideChildren={true}
|
||||||
|
items={menu}
|
||||||
|
className={'noco-top-menu'}
|
||||||
|
style={{ float: 'left' }}
|
||||||
|
theme="dark"
|
||||||
|
/>
|
||||||
<AvatarDropdown />
|
<AvatarDropdown />
|
||||||
</Drawer>}
|
</Drawer>
|
||||||
|
)}
|
||||||
</Layout.Header>
|
</Layout.Header>
|
||||||
<Layout.Content>
|
<Layout.Content>{props.children}</Layout.Content>
|
||||||
{props.children}
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default TopMenuLayout;
|
export default TopMenuLayout;
|
||||||
|
@ -5,7 +5,15 @@ import { Spin } from '@nocobase/client';
|
|||||||
import { useRequest, useLocation } from 'umi';
|
import { useRequest, useLocation } from 'umi';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import { Actions } from '../Actions';
|
import { Actions } from '../Actions';
|
||||||
import { Table as AntdTable, Card, Pagination, Button, Tabs, Descriptions, Tooltip } from 'antd';
|
import {
|
||||||
|
Table as AntdTable,
|
||||||
|
Card,
|
||||||
|
Pagination,
|
||||||
|
Button,
|
||||||
|
Tabs,
|
||||||
|
Descriptions,
|
||||||
|
Tooltip,
|
||||||
|
} from 'antd';
|
||||||
import { LoadingOutlined } from '@ant-design/icons';
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
import { components, fields2columns } from '@/components/views/SortableTable';
|
import { components, fields2columns } from '@/components/views/SortableTable';
|
||||||
import ReactDragListView from 'react-drag-listview';
|
import ReactDragListView from 'react-drag-listview';
|
||||||
@ -21,7 +29,11 @@ export function Association(props) {
|
|||||||
const { targetViewName } = schema;
|
const { targetViewName } = schema;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<View {...restProps} associationSchema={schema} viewName={targetViewName}/>
|
<View
|
||||||
|
{...restProps}
|
||||||
|
associationSchema={schema}
|
||||||
|
viewName={targetViewName}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -2,12 +2,16 @@ import React, { useEffect, useRef, useState } from 'react';
|
|||||||
import { Table as AntdTable, Card, Pagination } from 'antd';
|
import { Table as AntdTable, Card, Pagination } from 'antd';
|
||||||
import { useRequest, useHistory } from 'umi';
|
import { useRequest, useHistory } from 'umi';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import { LoadingOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons';
|
import {
|
||||||
|
LoadingOutlined,
|
||||||
|
LeftOutlined,
|
||||||
|
RightOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import { Calendar as BigCalendar, momentLocalizer } from 'react-big-calendar'
|
import { Calendar as BigCalendar, momentLocalizer } from 'react-big-calendar';
|
||||||
import * as dates from 'react-big-calendar/lib/utils/dates';
|
import * as dates from 'react-big-calendar/lib/utils/dates';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
const localizer = momentLocalizer(moment) // or globalizeLocalizer
|
const localizer = momentLocalizer(moment); // or globalizeLocalizer
|
||||||
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
||||||
import { Details, DetailsPage } from '../Table';
|
import { Details, DetailsPage } from '../Table';
|
||||||
import { Actions } from '../../Actions';
|
import { Actions } from '../../Actions';
|
||||||
@ -37,21 +41,22 @@ function toEvents(data, options: any = {}) {
|
|||||||
id: item[idField],
|
id: item[idField],
|
||||||
title: item[labelField],
|
title: item[labelField],
|
||||||
allDay: true,
|
allDay: true,
|
||||||
start: moment(item[startDateField||'createdAt'] || item.created_at).toDate(),
|
start: moment(
|
||||||
end: moment(item[endDateField || startDateField || 'createdAt'] || item.created_at).toDate(),
|
item[startDateField || 'createdAt'] || item.created_at,
|
||||||
|
).toDate(),
|
||||||
|
end: moment(
|
||||||
|
item[endDateField || startDateField || 'createdAt'] || item.created_at,
|
||||||
|
).toDate(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Calendar(props: CalendarProps) {
|
export function Calendar(props: CalendarProps) {
|
||||||
const {
|
const { schema = {}, associatedKey, defaultFilter } = props;
|
||||||
schema = {},
|
|
||||||
associatedKey,
|
|
||||||
defaultFilter,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const paginated = false;
|
const paginated = false;
|
||||||
|
|
||||||
const { rowKey = 'id',
|
const {
|
||||||
|
rowKey = 'id',
|
||||||
filter: schemaFilter,
|
filter: schemaFilter,
|
||||||
sort,
|
sort,
|
||||||
appends,
|
appends,
|
||||||
@ -64,16 +69,19 @@ export function Calendar(props: CalendarProps) {
|
|||||||
actions = [],
|
actions = [],
|
||||||
} = schema;
|
} = schema;
|
||||||
|
|
||||||
console.log({schema})
|
console.log({ schema });
|
||||||
|
|
||||||
const [calendarView, setCalendarView] = useState('month');
|
const [calendarView, setCalendarView] = useState('month');
|
||||||
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const { data, loading, mutate, refresh, run, params } = useRequest((params = {}, ...args) => {
|
const { data, loading, mutate, refresh, run, params } = useRequest(
|
||||||
|
(params = {}, ...args) => {
|
||||||
const { current, pageSize, sorter, filter, ...restParams } = params;
|
const { current, pageSize, sorter, filter, ...restParams } = params;
|
||||||
console.log('paramsparamsparamsparamsparams', params, args);
|
console.log('paramsparamsparamsparamsparams', params, args);
|
||||||
return api.resource(resourceName).list({
|
return api
|
||||||
|
.resource(resourceName)
|
||||||
|
.list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
page: paginated ? current : 1,
|
page: paginated ? current : 1,
|
||||||
perPage: paginated ? pageSize : -1,
|
perPage: paginated ? pageSize : -1,
|
||||||
@ -90,8 +98,8 @@ export function Calendar(props: CalendarProps) {
|
|||||||
// __parent ? {
|
// __parent ? {
|
||||||
// collection_name: __parent,
|
// collection_name: __parent,
|
||||||
// } : null,
|
// } : null,
|
||||||
].filter(obj => obj && Object.keys(obj).length)
|
].filter(obj => obj && Object.keys(obj).length),
|
||||||
}
|
},
|
||||||
// ...args2,
|
// ...args2,
|
||||||
})
|
})
|
||||||
.then(({ data = [], meta = {} }) => {
|
.then(({ data = [], meta = {} }) => {
|
||||||
@ -102,9 +110,11 @@ export function Calendar(props: CalendarProps) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
paginated,
|
paginated,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const events = toEvents(data?.list, {
|
const events = toEvents(data?.list, {
|
||||||
idField: rowKey,
|
idField: rowKey,
|
||||||
@ -115,8 +125,16 @@ export function Calendar(props: CalendarProps) {
|
|||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
allDay: '',
|
allDay: '',
|
||||||
previous: <div><LeftOutlined /></div>,
|
previous: (
|
||||||
next: <div><RightOutlined/></div>,
|
<div>
|
||||||
|
<LeftOutlined />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
next: (
|
||||||
|
<div>
|
||||||
|
<RightOutlined />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
today: '今天',
|
today: '今天',
|
||||||
month: '月',
|
month: '月',
|
||||||
week: '周',
|
week: '周',
|
||||||
@ -126,14 +144,15 @@ export function Calendar(props: CalendarProps) {
|
|||||||
time: '时间',
|
time: '时间',
|
||||||
event: '事件',
|
event: '事件',
|
||||||
noEventsInRange: '无',
|
noEventsInRange: '无',
|
||||||
showMore: (count) => `还有 ${count} 项`
|
showMore: count => `还有 ${count} 项`,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
console.log('events', data);
|
||||||
console.log('events', data)
|
|
||||||
return (
|
return (
|
||||||
<Card bordered={false}>
|
<Card bordered={false}>
|
||||||
<Actions associatedKey={associatedKey} onTrigger={{
|
<Actions
|
||||||
|
associatedKey={associatedKey}
|
||||||
|
onTrigger={{
|
||||||
async create(values) {
|
async create(values) {
|
||||||
await refresh();
|
await refresh();
|
||||||
},
|
},
|
||||||
@ -143,12 +162,15 @@ export function Calendar(props: CalendarProps) {
|
|||||||
run({ ...params[0], filter: values.filter });
|
run({ ...params[0], filter: values.filter });
|
||||||
// refresh();
|
// refresh();
|
||||||
},
|
},
|
||||||
}} actions={actions} style={{
|
}}
|
||||||
|
actions={actions}
|
||||||
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: '157px',
|
left: '157px',
|
||||||
right: '168px',
|
right: '168px',
|
||||||
marginBottom: 14
|
marginBottom: 14,
|
||||||
}}/>
|
}}
|
||||||
|
/>
|
||||||
<BigCalendar
|
<BigCalendar
|
||||||
popup
|
popup
|
||||||
selectable
|
selectable
|
||||||
@ -162,20 +184,24 @@ export function Calendar(props: CalendarProps) {
|
|||||||
if (dates.eq(start, end, 'month')) {
|
if (dates.eq(start, end, 'month')) {
|
||||||
return local.format(start, 'Y年M月', culture);
|
return local.format(start, 'Y年M月', culture);
|
||||||
}
|
}
|
||||||
return `${local.format(start, 'Y年M月', culture)} - ${local.format(end, 'Y年M月', culture)}`;
|
return `${local.format(start, 'Y年M月', culture)} - ${local.format(
|
||||||
}
|
end,
|
||||||
|
'Y年M月',
|
||||||
|
culture,
|
||||||
|
)}`;
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
events={events}
|
events={events}
|
||||||
onSelectSlot={(slotInfo) => {
|
onSelectSlot={slotInfo => {
|
||||||
// setFormMode('create');
|
// setFormMode('create');
|
||||||
// drawerRef.current.setVisible(true);
|
// drawerRef.current.setVisible(true);
|
||||||
// console.log('onSelectSlot', slotInfo)
|
// console.log('onSelectSlot', slotInfo)
|
||||||
}}
|
}}
|
||||||
onView={(view) => {
|
onView={view => {
|
||||||
setCalendarView(view);
|
setCalendarView(view);
|
||||||
console.log(view)
|
console.log(view);
|
||||||
}}
|
}}
|
||||||
onSelectEvent={(data) => {
|
onSelectEvent={data => {
|
||||||
console.log({ data });
|
console.log({ data });
|
||||||
if (!detailsOpenMode || !details.length) {
|
if (!detailsOpenMode || !details.length) {
|
||||||
return;
|
return;
|
||||||
@ -185,12 +211,15 @@ export function Calendar(props: CalendarProps) {
|
|||||||
history.push(`/admin/${paths[2]}/${data[rowKey]}/0`);
|
history.push(`/admin/${paths[2]}/${data[rowKey]}/0`);
|
||||||
} else {
|
} else {
|
||||||
Drawer.open({
|
Drawer.open({
|
||||||
headerStyle: details.length > 1 ? {
|
headerStyle:
|
||||||
|
details.length > 1
|
||||||
|
? {
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
borderBottom: 0,
|
borderBottom: 0,
|
||||||
// paddingTop: 16,
|
// paddingTop: 16,
|
||||||
// marginBottom: -4,
|
// marginBottom: -4,
|
||||||
} : {},
|
}
|
||||||
|
: {},
|
||||||
// title: details.length > 1 ? undefined : data[labelField],
|
// title: details.length > 1 ? undefined : data[labelField],
|
||||||
title: data.title,
|
title: data.title,
|
||||||
bodyStyle: {
|
bodyStyle: {
|
||||||
@ -225,8 +254,8 @@ export function Calendar(props: CalendarProps) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onRangeChange={(range) => {
|
onRangeChange={range => {
|
||||||
console.log({range})
|
console.log({ range });
|
||||||
}}
|
}}
|
||||||
views={['month', 'week', 'day']}
|
views={['month', 'week', 'day']}
|
||||||
// step={120}
|
// step={120}
|
||||||
|
@ -2,52 +2,66 @@
|
|||||||
.rbc-btn {
|
.rbc-btn {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
font: inherit;
|
font: inherit;
|
||||||
margin: 0; }
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
button.rbc-btn {
|
button.rbc-btn {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
-webkit-appearance: button;
|
-webkit-appearance: button;
|
||||||
cursor: pointer; }
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
button[disabled].rbc-btn {
|
button[disabled].rbc-btn {
|
||||||
cursor: not-allowed; }
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
button.rbc-input::-moz-focus-inner {
|
button.rbc-input::-moz-focus-inner {
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0; }
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-calendar {
|
.rbc-calendar {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
// height: 75vh;
|
// height: 75vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: stretch; }
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-calendar *,
|
.rbc-calendar *,
|
||||||
.rbc-calendar *:before,
|
.rbc-calendar *:before,
|
||||||
.rbc-calendar *:after {
|
.rbc-calendar *:after {
|
||||||
box-sizing: inherit; }
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-abs-full, .rbc-row-bg {
|
.rbc-abs-full,
|
||||||
|
.rbc-row-bg {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0; }
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-ellipsis, .rbc-event-label, .rbc-row-segment .rbc-event-content, .rbc-show-more {
|
.rbc-ellipsis,
|
||||||
|
.rbc-event-label,
|
||||||
|
.rbc-row-segment .rbc-event-content,
|
||||||
|
.rbc-show-more {
|
||||||
display: block;
|
display: block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap; }
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-rtl {
|
.rbc-rtl {
|
||||||
direction: rtl; }
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-off-range {
|
.rbc-off-range {
|
||||||
color: rgba(0,0,0,.25); }
|
color: rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-off-range-bg {
|
.rbc-off-range-bg {
|
||||||
// background: #e6e6e6;
|
// background: #e6e6e6;
|
||||||
@ -64,7 +78,7 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
// font-weight: 500;
|
// font-weight: 500;
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
color: rgba(0,0,0,.85);
|
color: rgba(0, 0, 0, 0.85);
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
border-bottom: 2px solid #f0f0f0;
|
border-bottom: 2px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
@ -73,21 +87,27 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
}
|
}
|
||||||
.rbc-rtl .rbc-header + .rbc-header {
|
.rbc-rtl .rbc-header + .rbc-header {
|
||||||
border-left-width: 0;
|
border-left-width: 0;
|
||||||
border-right: 1px solid #f0f0f0; }
|
border-right: 1px solid #f0f0f0;
|
||||||
.rbc-header > a, .rbc-header > a:active, .rbc-header > a:visited {
|
}
|
||||||
|
.rbc-header > a,
|
||||||
|
.rbc-header > a:active,
|
||||||
|
.rbc-header > a:visited {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration: none; }
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-row-content {
|
.rbc-row-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
z-index: 4; }
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-row-content-scrollable {
|
.rbc-row-content-scrollable {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%; }
|
height: 100%;
|
||||||
|
}
|
||||||
.rbc-row-content-scrollable .rbc-row-content-scroll-container {
|
.rbc-row-content-scrollable .rbc-row-content-scroll-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
@ -95,10 +115,12 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
/* IE and Edge */
|
/* IE and Edge */
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
/* Firefox */ }
|
/* Firefox */
|
||||||
.rbc-row-content-scrollable .rbc-row-content-scroll-container::-webkit-scrollbar {
|
}
|
||||||
display: none; }
|
.rbc-row-content-scrollable
|
||||||
|
.rbc-row-content-scroll-container::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-toolbar {
|
.rbc-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -106,11 +128,13 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
font-size: 16px; }
|
font-size: 16px;
|
||||||
|
}
|
||||||
.rbc-toolbar .rbc-toolbar-label {
|
.rbc-toolbar .rbc-toolbar-label {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
text-align: center; }
|
text-align: center;
|
||||||
|
}
|
||||||
.rbc-toolbar button {
|
.rbc-toolbar button {
|
||||||
outline: none;
|
outline: none;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@ -129,15 +153,21 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
padding: 4px 15px;
|
padding: 4px 15px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
white-space: nowrap; }
|
white-space: nowrap;
|
||||||
.rbc-toolbar button:active, .rbc-toolbar button.rbc-active {
|
}
|
||||||
|
.rbc-toolbar button:active,
|
||||||
|
.rbc-toolbar button.rbc-active {
|
||||||
// background-image: none;
|
// background-image: none;
|
||||||
// box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
// box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||||
// background-color: #e6e6e6;
|
// background-color: #e6e6e6;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
border-color: #1890ff; }
|
border-color: #1890ff;
|
||||||
.rbc-toolbar button:active:hover, .rbc-toolbar button:active:focus, .rbc-toolbar button.rbc-active:hover, .rbc-toolbar button.rbc-active:focus {
|
}
|
||||||
|
.rbc-toolbar button:active:hover,
|
||||||
|
.rbc-toolbar button:active:focus,
|
||||||
|
.rbc-toolbar button.rbc-active:hover,
|
||||||
|
.rbc-toolbar button.rbc-active:focus {
|
||||||
// color: #373a3c;
|
// color: #373a3c;
|
||||||
// background-color: #d4d4d4;
|
// background-color: #d4d4d4;
|
||||||
// border-color: #8c8c8c;
|
// border-color: #8c8c8c;
|
||||||
@ -159,31 +189,40 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
|
|
||||||
.rbc-btn-group {
|
.rbc-btn-group {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
white-space: nowrap; }
|
white-space: nowrap;
|
||||||
|
}
|
||||||
.rbc-btn-group > button:first-child:not(:last-child) {
|
.rbc-btn-group > button:first-child:not(:last-child) {
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-right-radius: 0; }
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
.rbc-btn-group > button:last-child:not(:first-child) {
|
.rbc-btn-group > button:last-child:not(:first-child) {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0; }
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
.rbc-rtl .rbc-btn-group > button:first-child:not(:last-child) {
|
.rbc-rtl .rbc-btn-group > button:first-child:not(:last-child) {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0; }
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
.rbc-rtl .rbc-btn-group > button:last-child:not(:first-child) {
|
.rbc-rtl .rbc-btn-group > button:last-child:not(:first-child) {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-right-radius: 0; }
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
.rbc-btn-group > button:not(:first-child):not(:last-child) {
|
.rbc-btn-group > button:not(:first-child):not(:last-child) {
|
||||||
border-radius: 0; }
|
border-radius: 0;
|
||||||
|
}
|
||||||
.rbc-btn-group button + button {
|
.rbc-btn-group button + button {
|
||||||
margin-left: -1px; }
|
margin-left: -1px;
|
||||||
|
}
|
||||||
.rbc-rtl .rbc-btn-group button + button {
|
.rbc-rtl .rbc-btn-group button + button {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: -1px; }
|
margin-right: -1px;
|
||||||
|
}
|
||||||
.rbc-btn-group + .rbc-btn-group,
|
.rbc-btn-group + .rbc-btn-group,
|
||||||
.rbc-btn-group + button {
|
.rbc-btn-group + button {
|
||||||
margin-left: 10px; }
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-event {
|
.rbc-event {
|
||||||
border: none;
|
border: none;
|
||||||
@ -205,7 +244,8 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
}
|
}
|
||||||
.rbc-slot-selecting .rbc-event {
|
.rbc-slot-selecting .rbc-event {
|
||||||
cursor: inherit;
|
cursor: inherit;
|
||||||
pointer-events: none; }
|
pointer-events: none;
|
||||||
|
}
|
||||||
.rbc-event.rbc-selected {
|
.rbc-event.rbc-selected {
|
||||||
background-color: #e6f7ff;
|
background-color: #e6f7ff;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
@ -215,36 +255,45 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rbc-event-label {
|
.rbc-event-label {
|
||||||
font-size: 80%; }
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-event-overlaps {
|
.rbc-event-overlaps {
|
||||||
box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5); }
|
box-shadow: -1px 1px 5px 0px rgba(51, 51, 51, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-event-continues-prior {
|
.rbc-event-continues-prior {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0; }
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-event-continues-after {
|
.rbc-event-continues-after {
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-right-radius: 0; }
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-event-continues-earlier {
|
.rbc-event-continues-earlier {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-top-right-radius: 0; }
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-event-continues-later {
|
.rbc-event-continues-later {
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-bottom-right-radius: 0; }
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-row {
|
.rbc-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row; }
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-row-segment {
|
.rbc-row-segment {
|
||||||
padding: 0 4px 1px 4px; }
|
padding: 0 4px 1px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-selected-cell {
|
.rbc-selected-cell {
|
||||||
background-color: rgba(0, 0, 0, 0.1); }
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-show-more {
|
.rbc-show-more {
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
@ -265,11 +314,13 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
height: 68vh; }
|
height: 68vh;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-month-header {
|
.rbc-month-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row; }
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-month-row {
|
.rbc-month-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -278,7 +329,8 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
flex: 1 0 0;
|
flex: 1 0 0;
|
||||||
flex-basis: 0px;
|
flex-basis: 0px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100%; }
|
height: 100%;
|
||||||
|
}
|
||||||
.rbc-month-row + .rbc-month-row {
|
.rbc-month-row + .rbc-month-row {
|
||||||
// border-top: 1px solid #f0f0f0;
|
// border-top: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
@ -289,12 +341,15 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
text-align: right; }
|
text-align: right;
|
||||||
|
}
|
||||||
.rbc-date-cell.rbc-now a {
|
.rbc-date-cell.rbc-now a {
|
||||||
// font-weight: bold;
|
// font-weight: bold;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
}
|
}
|
||||||
.rbc-date-cell > a, .rbc-date-cell > a:active, .rbc-date-cell > a:visited {
|
.rbc-date-cell > a,
|
||||||
|
.rbc-date-cell > a:active,
|
||||||
|
.rbc-date-cell > a:visited {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
@ -306,9 +361,8 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex: 1 0 0;
|
flex: 1 0 0;
|
||||||
overflow: hidden; }
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.rbc-day-bg {
|
.rbc-day-bg {
|
||||||
flex: 1 0 0%;
|
flex: 1 0 0%;
|
||||||
@ -349,69 +403,89 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
// border: 1px solid #e5e5e5;
|
// border: 1px solid #e5e5e5;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
box-shadow: 0 3px 6px -4px rgba(0,0,0,.12), 0 6px 16px 0 rgba(0,0,0,.08), 0 9px 28px 8px rgba(0,0,0,.05);
|
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12),
|
||||||
padding: 12px 16px; }
|
0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
.rbc-overlay > * + * {
|
.rbc-overlay > * + * {
|
||||||
margin-top: 1px; }
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-overlay-header {
|
.rbc-overlay-header {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
margin: -12px -16px 12px -16px;
|
margin: -12px -16px 12px -16px;
|
||||||
padding: 5px 16px 4px; }
|
padding: 5px 16px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-agenda-view {
|
.rbc-agenda-view {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1 0 0;
|
flex: 1 0 0;
|
||||||
overflow: auto; }
|
overflow: auto;
|
||||||
|
}
|
||||||
.rbc-agenda-view table.rbc-agenda-table {
|
.rbc-agenda-view table.rbc-agenda-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
border-collapse: collapse; }
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
.rbc-agenda-view table.rbc-agenda-table tbody > tr > td {
|
.rbc-agenda-view table.rbc-agenda-table tbody > tr > td {
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
vertical-align: top; }
|
vertical-align: top;
|
||||||
|
}
|
||||||
.rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell {
|
.rbc-agenda-view table.rbc-agenda-table .rbc-agenda-time-cell {
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
text-transform: lowercase; }
|
text-transform: lowercase;
|
||||||
|
}
|
||||||
.rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
|
.rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
|
||||||
border-left: 1px solid #f0f0f0; }
|
border-left: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
|
.rbc-rtl .rbc-agenda-view table.rbc-agenda-table tbody > tr > td + td {
|
||||||
border-left-width: 0;
|
border-left-width: 0;
|
||||||
border-right: 1px solid #f0f0f0; }
|
border-right: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-agenda-view table.rbc-agenda-table tbody > tr + tr {
|
.rbc-agenda-view table.rbc-agenda-table tbody > tr + tr {
|
||||||
border-top: 1px solid #f0f0f0; }
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-agenda-view table.rbc-agenda-table thead > tr > th {
|
.rbc-agenda-view table.rbc-agenda-table thead > tr > th {
|
||||||
padding: 3px 5px;
|
padding: 3px 5px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-bottom: 1px solid #f0f0f0; }
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th {
|
.rbc-rtl .rbc-agenda-view table.rbc-agenda-table thead > tr > th {
|
||||||
text-align: right; }
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-agenda-time-cell {
|
.rbc-agenda-time-cell {
|
||||||
text-transform: lowercase; }
|
text-transform: lowercase;
|
||||||
|
}
|
||||||
.rbc-agenda-time-cell .rbc-continues-after:after {
|
.rbc-agenda-time-cell .rbc-continues-after:after {
|
||||||
content: ' »'; }
|
content: ' »';
|
||||||
|
}
|
||||||
.rbc-agenda-time-cell .rbc-continues-prior:before {
|
.rbc-agenda-time-cell .rbc-continues-prior:before {
|
||||||
content: '« '; }
|
content: '« ';
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-agenda-date-cell,
|
.rbc-agenda-date-cell,
|
||||||
.rbc-agenda-time-cell {
|
.rbc-agenda-time-cell {
|
||||||
white-space: nowrap; }
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-agenda-event-cell {
|
.rbc-agenda-event-cell {
|
||||||
width: 100%; }
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-column {
|
.rbc-time-column {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100%; }
|
min-height: 100%;
|
||||||
|
}
|
||||||
.rbc-time-column .rbc-timeslot-group {
|
.rbc-time-column .rbc-timeslot-group {
|
||||||
flex: 1; }
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-timeslot-group {
|
.rbc-timeslot-group {
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
@ -427,23 +501,28 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
|
|
||||||
.rbc-time-gutter,
|
.rbc-time-gutter,
|
||||||
.rbc-header-gutter {
|
.rbc-header-gutter {
|
||||||
flex: none; }
|
flex: none;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-label {
|
.rbc-label {
|
||||||
padding: 0 5px; }
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-day-slot {
|
.rbc-day-slot {
|
||||||
position: relative; }
|
position: relative;
|
||||||
|
}
|
||||||
.rbc-day-slot .rbc-events-container {
|
.rbc-day-slot .rbc-events-container {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
top: 0; }
|
top: 0;
|
||||||
|
}
|
||||||
.rbc-day-slot .rbc-events-container.rbc-rtl {
|
.rbc-day-slot .rbc-events-container.rbc-rtl {
|
||||||
left: 10px;
|
left: 10px;
|
||||||
right: 0; }
|
right: 0;
|
||||||
|
}
|
||||||
.rbc-day-slot .rbc-event {
|
.rbc-day-slot .rbc-event {
|
||||||
border: 1px solid #265985;
|
border: 1px solid #265985;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -452,18 +531,21 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
flex-flow: column wrap;
|
flex-flow: column wrap;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: absolute; }
|
position: absolute;
|
||||||
|
}
|
||||||
.rbc-day-slot .rbc-event-label {
|
.rbc-day-slot .rbc-event-label {
|
||||||
flex: none;
|
flex: none;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
width: auto; }
|
width: auto;
|
||||||
|
}
|
||||||
.rbc-day-slot .rbc-event-content {
|
.rbc-day-slot .rbc-event-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 1em; }
|
min-height: 1em;
|
||||||
|
}
|
||||||
.rbc-day-slot .rbc-time-slot {
|
.rbc-day-slot .rbc-time-slot {
|
||||||
// border-top: 1px solid #f7f7f7;
|
// border-top: 1px solid #f7f7f7;
|
||||||
}
|
}
|
||||||
@ -504,38 +586,48 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
background-color: white;
|
background-color: white;
|
||||||
border-right: 1px solid #f0f0f0;
|
border-right: 1px solid #f0f0f0;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
margin-right: -1px; }
|
margin-right: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-view-resources .rbc-time-header {
|
.rbc-time-view-resources .rbc-time-header {
|
||||||
overflow: hidden; }
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-view-resources .rbc-time-header-content {
|
.rbc-time-view-resources .rbc-time-header-content {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
flex: 1 0 0;
|
flex: 1 0 0;
|
||||||
flex-basis: 0px; }
|
flex-basis: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-view-resources .rbc-time-header-cell-single-day {
|
.rbc-time-view-resources .rbc-time-header-cell-single-day {
|
||||||
display: none; }
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-view-resources .rbc-day-slot {
|
.rbc-time-view-resources .rbc-day-slot {
|
||||||
min-width: 140px; }
|
min-width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-view-resources .rbc-header,
|
.rbc-time-view-resources .rbc-header,
|
||||||
.rbc-time-view-resources .rbc-day-bg {
|
.rbc-time-view-resources .rbc-day-bg {
|
||||||
width: 140px;
|
width: 140px;
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
flex-basis: 0 px; }
|
flex-basis: 0 px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-header-content + .rbc-time-header-content {
|
.rbc-time-header-content + .rbc-time-header-content {
|
||||||
margin-left: -1px; }
|
margin-left: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-slot {
|
.rbc-time-slot {
|
||||||
flex: 1 0 0; }
|
flex: 1 0 0;
|
||||||
|
}
|
||||||
.rbc-time-slot.rbc-now {
|
.rbc-time-slot.rbc-now {
|
||||||
font-weight: bold; }
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-day-header {
|
.rbc-day-header {
|
||||||
text-align: center; }
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-slot-selection {
|
.rbc-slot-selection {
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
@ -544,10 +636,12 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
color: white;
|
color: white;
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 3px; }
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-slot-selecting {
|
.rbc-slot-selecting {
|
||||||
cursor: move; }
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-view {
|
.rbc-time-view {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -555,39 +649,51 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-top: 1px solid #f0f0f0;
|
border-top: 1px solid #f0f0f0;
|
||||||
min-height: 0; }
|
min-height: 0;
|
||||||
|
}
|
||||||
.rbc-time-view .rbc-time-gutter {
|
.rbc-time-view .rbc-time-gutter {
|
||||||
white-space: nowrap; }
|
white-space: nowrap;
|
||||||
|
}
|
||||||
.rbc-time-view .rbc-allday-cell {
|
.rbc-time-view .rbc-allday-cell {
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative; }
|
position: relative;
|
||||||
|
}
|
||||||
.rbc-time-view .rbc-allday-cell + .rbc-allday-cell {
|
.rbc-time-view .rbc-allday-cell + .rbc-allday-cell {
|
||||||
border-left: 1px solid #f0f0f0; }
|
border-left: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-time-view .rbc-allday-events {
|
.rbc-time-view .rbc-allday-events {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 4; }
|
z-index: 4;
|
||||||
|
}
|
||||||
.rbc-time-view .rbc-row {
|
.rbc-time-view .rbc-row {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
min-height: 20px; }
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-header {
|
.rbc-time-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
flex-direction: row; }
|
flex-direction: row;
|
||||||
|
}
|
||||||
.rbc-time-header.rbc-overflowing {
|
.rbc-time-header.rbc-overflowing {
|
||||||
border-right: 1px solid #f0f0f0; }
|
border-right: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-rtl .rbc-time-header.rbc-overflowing {
|
.rbc-rtl .rbc-time-header.rbc-overflowing {
|
||||||
border-right-width: 0;
|
border-right-width: 0;
|
||||||
border-left: 1px solid #f0f0f0; }
|
border-left: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-time-header > .rbc-row:first-child {
|
.rbc-time-header > .rbc-row:first-child {
|
||||||
border-bottom: 1px solid #f0f0f0; }
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-time-header > .rbc-row.rbc-row-resource {
|
.rbc-time-header > .rbc-row.rbc-row-resource {
|
||||||
border-bottom: 1px solid #f0f0f0; }
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-header-cell-single-day {
|
.rbc-time-header-cell-single-day {
|
||||||
display: none; }
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-header-content {
|
.rbc-time-header-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -598,10 +704,12 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
}
|
}
|
||||||
.rbc-rtl .rbc-time-header-content {
|
.rbc-rtl .rbc-time-header-content {
|
||||||
border-left-width: 0;
|
border-left-width: 0;
|
||||||
border-right: 1px solid #f0f0f0; }
|
border-right: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-time-header-content > .rbc-row.rbc-row-resource {
|
.rbc-time-header-content > .rbc-row.rbc-row-resource {
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
flex-shrink: 0; }
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-time-content {
|
.rbc-time-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -610,19 +718,23 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
border-top: 1px solid #f0f0f0;
|
border-top: 1px solid #f0f0f0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
position: relative; }
|
position: relative;
|
||||||
|
}
|
||||||
.rbc-time-content > .rbc-time-gutter {
|
.rbc-time-content > .rbc-time-gutter {
|
||||||
flex: none; }
|
flex: none;
|
||||||
|
}
|
||||||
.rbc-time-content > * + * > * {
|
.rbc-time-content > * + * > * {
|
||||||
// border-left: 1px solid #f0f0f0;
|
// border-left: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
.rbc-rtl .rbc-time-content > * + * > * {
|
.rbc-rtl .rbc-time-content > * + * > * {
|
||||||
border-left-width: 0;
|
border-left-width: 0;
|
||||||
border-right: 1px solid #f0f0f0; }
|
border-right: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
.rbc-time-content > .rbc-day-slot {
|
.rbc-time-content > .rbc-day-slot {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none; }
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
.rbc-current-time-indicator {
|
.rbc-current-time-indicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -631,4 +743,5 @@ button.rbc-input::-moz-focus-inner {
|
|||||||
right: 0;
|
right: 0;
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background-color: #74ad31;
|
background-color: #74ad31;
|
||||||
pointer-events: none; }
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
@ -5,7 +5,15 @@ import { Spin } from '@nocobase/client';
|
|||||||
import { useRequest, useLocation } from 'umi';
|
import { useRequest, useLocation } from 'umi';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import { Actions } from '../Actions';
|
import { Actions } from '../Actions';
|
||||||
import { Table as AntdTable, Card, Pagination, Button, Tabs, Descriptions as AntdDescriptions, Tooltip } from 'antd';
|
import {
|
||||||
|
Table as AntdTable,
|
||||||
|
Card,
|
||||||
|
Pagination,
|
||||||
|
Button,
|
||||||
|
Tabs,
|
||||||
|
Descriptions as AntdDescriptions,
|
||||||
|
Tooltip,
|
||||||
|
} from 'antd';
|
||||||
import { LoadingOutlined } from '@ant-design/icons';
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
import { components, fields2columns } from '@/components/views/SortableTable';
|
import { components, fields2columns } from '@/components/views/SortableTable';
|
||||||
import ReactDragListView from 'react-drag-listview';
|
import ReactDragListView from 'react-drag-listview';
|
||||||
@ -52,11 +60,20 @@ function toGroups(fields: any[]) {
|
|||||||
|
|
||||||
export function Descriptions(props) {
|
export function Descriptions(props) {
|
||||||
const { data: record = {}, schema = {}, onDataChange } = props;
|
const { data: record = {}, schema = {}, onDataChange } = props;
|
||||||
const { rowKey = 'id', resourceName, fields = [], actions = [], appends = [], associationField = {} } = schema;
|
const {
|
||||||
|
rowKey = 'id',
|
||||||
|
resourceName,
|
||||||
|
fields = [],
|
||||||
|
actions = [],
|
||||||
|
appends = [],
|
||||||
|
associationField = {},
|
||||||
|
} = schema;
|
||||||
const responsive = useResponsive();
|
const responsive = useResponsive();
|
||||||
|
|
||||||
const resourceKey = props.resourceKey || record[associationField.targetKey||rowKey];
|
const resourceKey =
|
||||||
const associatedKey = props.associatedKey || record[associationField.sourceKey||'id'];
|
props.resourceKey || record[associationField.targetKey || rowKey];
|
||||||
|
const associatedKey =
|
||||||
|
props.associatedKey || record[associationField.sourceKey || 'id'];
|
||||||
|
|
||||||
// console.log({resourceKey, data: record, associatedKey, associationField})
|
// console.log({resourceKey, data: record, associatedKey, associationField})
|
||||||
|
|
||||||
@ -73,11 +90,11 @@ export function Descriptions(props) {
|
|||||||
let descriptionsProps: any = {
|
let descriptionsProps: any = {
|
||||||
size: 'middle',
|
size: 'middle',
|
||||||
bordered: true,
|
bordered: true,
|
||||||
}
|
};
|
||||||
if (responsive.small && !responsive.middle && !responsive.large) {
|
if (responsive.small && !responsive.middle && !responsive.large) {
|
||||||
descriptionsProps = {
|
descriptionsProps = {
|
||||||
layout: 'vertical'
|
layout: 'vertical',
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
const groups = toGroups(fields);
|
const groups = toGroups(fields);
|
||||||
return (
|
return (
|
||||||
@ -100,17 +117,41 @@ export function Descriptions(props) {
|
|||||||
// size={'middle'}
|
// size={'middle'}
|
||||||
// bordered
|
// bordered
|
||||||
{...descriptionsProps}
|
{...descriptionsProps}
|
||||||
title={group.title && <span>{group.title} {group.tooltip && <Tooltip title={group.tooltip}><InfoCircleOutlined /></Tooltip>}</span>}
|
title={
|
||||||
column={1}>
|
group.title && (
|
||||||
|
<span>
|
||||||
|
{group.title}{' '}
|
||||||
|
{group.tooltip && (
|
||||||
|
<Tooltip title={group.tooltip}>
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
column={1}
|
||||||
|
>
|
||||||
{group.children.map((field: any) => {
|
{group.children.map((field: any) => {
|
||||||
const label = field.tooltip ? (
|
const label = field.tooltip ? (
|
||||||
<>{field.title||field.name} <Tooltip title={field.tooltip}><InfoCircleOutlined /></Tooltip></>
|
<>
|
||||||
) : (field.title||field.name);
|
{field.title || field.name}
|
||||||
|
<Tooltip title={field.tooltip}>
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
field.title || field.name
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<AntdDescriptions.Item label={label}>
|
<AntdDescriptions.Item label={label}>
|
||||||
<Field data={data} viewType={'descriptions'} schema={field} value={get(data, field.name)}/>
|
<Field
|
||||||
|
data={data}
|
||||||
|
viewType={'descriptions'}
|
||||||
|
schema={field}
|
||||||
|
value={get(data, field.name)}
|
||||||
|
/>
|
||||||
</AntdDescriptions.Item>
|
</AntdDescriptions.Item>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
</AntdDescriptions>
|
</AntdDescriptions>
|
||||||
))}
|
))}
|
||||||
|
@ -27,9 +27,9 @@ export function FilterForm(props: any) {
|
|||||||
// actions={actions}
|
// actions={actions}
|
||||||
onReset={async () => {
|
onReset={async () => {
|
||||||
// setData({filter: {}});
|
// setData({filter: {}});
|
||||||
onFinish && await onFinish(null);
|
onFinish && (await onFinish(null));
|
||||||
}}
|
}}
|
||||||
onSubmit={async (values) => {
|
onSubmit={async values => {
|
||||||
if (onFinish) {
|
if (onFinish) {
|
||||||
await onFinish(values);
|
await onFinish(values);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ import api from '@/api-client';
|
|||||||
import { useRequest, useLocation } from 'umi';
|
import { useRequest, useLocation } from 'umi';
|
||||||
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
||||||
import set from 'lodash/set';
|
import set from 'lodash/set';
|
||||||
import cloneDeep from 'lodash/cloneDeep'
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import { Spin } from '@nocobase/client';
|
import { Spin } from '@nocobase/client';
|
||||||
import { markdown } from '@/components/views/Field';
|
import { markdown } from '@/components/views/Field';
|
||||||
import scopes from '@/components/views/Form/scopes';
|
import scopes from '@/components/views/Form/scopes';
|
||||||
@ -41,7 +41,12 @@ export function fields2properties(fields = [], options: any = {}) {
|
|||||||
}
|
}
|
||||||
if (field.showTime) {
|
if (field.showTime) {
|
||||||
set(data, 'x-component-props.showTime', true);
|
set(data, 'x-component-props.showTime', true);
|
||||||
field.timeFormat && set(data, 'x-component-props.format', `${field.dateFormat} ${field.timeFormat}`);
|
field.timeFormat &&
|
||||||
|
set(
|
||||||
|
data,
|
||||||
|
'x-component-props.format',
|
||||||
|
`${field.dateFormat} ${field.timeFormat}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (field.createOnly && mode !== 'create') {
|
if (field.createOnly && mode !== 'create') {
|
||||||
set(data, 'x-component-props.disabled', true);
|
set(data, 'x-component-props.disabled', true);
|
||||||
@ -68,16 +73,16 @@ export function fields2properties(fields = [], options: any = {}) {
|
|||||||
const property = {};
|
const property = {};
|
||||||
Object.assign(property, {
|
Object.assign(property, {
|
||||||
label: {
|
label: {
|
||||||
type: "string",
|
type: 'string',
|
||||||
title: "选项",
|
title: '选项',
|
||||||
required: true,
|
required: true,
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
bordered: false,
|
bordered: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
type: "colorSelect",
|
type: 'colorSelect',
|
||||||
title: "颜色",
|
title: '颜色',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
bordered: false,
|
bordered: false,
|
||||||
},
|
},
|
||||||
@ -92,7 +97,12 @@ export function fields2properties(fields = [], options: any = {}) {
|
|||||||
data.default = field.defaultValue;
|
data.default = field.defaultValue;
|
||||||
}
|
}
|
||||||
if (field.tooltip) {
|
if (field.tooltip) {
|
||||||
data.description = <div className={'markdown-content'} dangerouslySetInnerHTML={{__html: markdown(field.tooltip)}}></div>;
|
data.description = (
|
||||||
|
<div
|
||||||
|
className={'markdown-content'}
|
||||||
|
dangerouslySetInnerHTML={{ __html: markdown(field.tooltip) }}
|
||||||
|
></div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log({ properties, options });
|
console.log({ properties, options });
|
||||||
@ -101,18 +111,40 @@ export function fields2properties(fields = [], options: any = {}) {
|
|||||||
const actions = createFormActions();
|
const actions = createFormActions();
|
||||||
|
|
||||||
export function Form(props: any) {
|
export function Form(props: any) {
|
||||||
const { initialValues = {}, onValueChange, onReset, __parent, noRequest = false, onFinish, onDraft, resolve, data: record = {}, associatedKey, schema = {} } = props;
|
const {
|
||||||
|
initialValues = {},
|
||||||
|
onValueChange,
|
||||||
|
onReset,
|
||||||
|
__parent,
|
||||||
|
noRequest = false,
|
||||||
|
onFinish,
|
||||||
|
onDraft,
|
||||||
|
resolve,
|
||||||
|
data: record = {},
|
||||||
|
associatedKey,
|
||||||
|
schema = {},
|
||||||
|
} = props;
|
||||||
console.log({ noRequest, record, associatedKey, __parent });
|
console.log({ noRequest, record, associatedKey, __parent });
|
||||||
const { statusable, resourceName, rowKey = 'id', fields = [], appends = [], associationField = {} } = schema;
|
const {
|
||||||
|
statusable,
|
||||||
|
resourceName,
|
||||||
|
rowKey = 'id',
|
||||||
|
fields = [],
|
||||||
|
appends = [],
|
||||||
|
associationField = {},
|
||||||
|
} = schema;
|
||||||
|
|
||||||
const resourceKey = props.resourceKey || record[associationField.targetKey||rowKey];
|
const resourceKey =
|
||||||
|
props.resourceKey || record[associationField.targetKey || rowKey];
|
||||||
|
|
||||||
const { data = {}, loading, refresh } = useRequest(() => {
|
const { data = {}, loading, refresh } = useRequest(() => {
|
||||||
return (!noRequest && resourceKey) ? api.resource(resourceName).get({
|
return !noRequest && resourceKey
|
||||||
|
? api.resource(resourceName).get({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
resourceKey,
|
resourceKey,
|
||||||
'fields[appends]': appends,
|
'fields[appends]': appends,
|
||||||
}) : Promise.resolve({data: record});
|
})
|
||||||
|
: Promise.resolve({ data: record });
|
||||||
});
|
});
|
||||||
|
|
||||||
const [status, setStatus] = useState('publish');
|
const [status, setStatus] = useState('publish');
|
||||||
@ -135,22 +167,24 @@ export function Form(props: any) {
|
|||||||
$(LifeCycleTypes.ON_FORM_INIT).subscribe(() => {
|
$(LifeCycleTypes.ON_FORM_INIT).subscribe(() => {
|
||||||
setFieldState('*', state => {
|
setFieldState('*', state => {
|
||||||
set(state.props, 'x-component-props.__index', resourceKey);
|
set(state.props, 'x-component-props.__index', resourceKey);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
// actions={actions}
|
// actions={actions}
|
||||||
schema={{
|
schema={{
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: fields2properties(fields, { mode: !!Object.keys(data).length ? null : 'create' }),
|
properties: fields2properties(fields, {
|
||||||
|
mode: !!Object.keys(data).length ? null : 'create',
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
onReset={async () => {
|
onReset={async () => {
|
||||||
onReset && await onReset();
|
onReset && (await onReset());
|
||||||
}}
|
}}
|
||||||
onChange={(values) => {
|
onChange={values => {
|
||||||
console.log('onValueChange')
|
console.log('onValueChange');
|
||||||
onValueChange && onValueChange(values)
|
onValueChange && onValueChange(values);
|
||||||
}}
|
}}
|
||||||
onSubmit={async (values) => {
|
onSubmit={async values => {
|
||||||
console.log({ status });
|
console.log({ status });
|
||||||
if (!noRequest) {
|
if (!noRequest) {
|
||||||
resourceKey
|
resourceKey
|
||||||
@ -170,7 +204,7 @@ export function Form(props: any) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onFinish && await onFinish(values);
|
onFinish && (await onFinish(values));
|
||||||
}}
|
}}
|
||||||
expressionScope={scopes}
|
expressionScope={scopes}
|
||||||
>
|
>
|
||||||
@ -181,22 +215,22 @@ export function Form(props: any) {
|
|||||||
selector={[
|
selector={[
|
||||||
LifeCycleTypes.ON_FORM_MOUNT,
|
LifeCycleTypes.ON_FORM_MOUNT,
|
||||||
LifeCycleTypes.ON_FORM_SUBMIT_START,
|
LifeCycleTypes.ON_FORM_SUBMIT_START,
|
||||||
LifeCycleTypes.ON_FORM_SUBMIT_END
|
LifeCycleTypes.ON_FORM_SUBMIT_END,
|
||||||
]}
|
]}
|
||||||
reducer={(state, action) => {
|
reducer={(state, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case LifeCycleTypes.ON_FORM_SUBMIT_START:
|
case LifeCycleTypes.ON_FORM_SUBMIT_START:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
submitting: true
|
submitting: true,
|
||||||
}
|
};
|
||||||
case LifeCycleTypes.ON_FORM_SUBMIT_END:
|
case LifeCycleTypes.ON_FORM_SUBMIT_END:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
submitting: false
|
submitting: false,
|
||||||
}
|
};
|
||||||
default:
|
default:
|
||||||
return state
|
return state;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -227,10 +261,11 @@ export function Form(props: any) {
|
|||||||
await form.reset({
|
await form.reset({
|
||||||
validate: false,
|
validate: false,
|
||||||
});
|
});
|
||||||
onDraft && await onDraft({
|
onDraft &&
|
||||||
|
(await onDraft({
|
||||||
...state.values,
|
...state.values,
|
||||||
status: 'draft',
|
status: 'draft',
|
||||||
});
|
}));
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
@ -241,7 +276,7 @@ export function Form(props: any) {
|
|||||||
>
|
>
|
||||||
{'保存草稿'}
|
{'保存草稿'}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
);
|
||||||
}}
|
}}
|
||||||
</FormSpy>
|
</FormSpy>
|
||||||
)}
|
)}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from 'react';
|
||||||
import { useRequest, useHistory } from 'umi';
|
import { useRequest, useHistory } from 'umi';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import { Descriptions, Popconfirm, Card, Button } from 'antd';
|
import { Descriptions, Popconfirm, Card, Button } from 'antd';
|
||||||
import Board, { moveCard } from "@lourenci/react-kanban";
|
import Board, { moveCard } from '@lourenci/react-kanban';
|
||||||
import "@lourenci/react-kanban/dist/styles.css";
|
import '@lourenci/react-kanban/dist/styles.css';
|
||||||
import { PlusOutlined, CloseOutlined, RightOutlined } from '@ant-design/icons';
|
import { PlusOutlined, CloseOutlined, RightOutlined } from '@ant-design/icons';
|
||||||
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
import Drawer from '@/components/pages/AdminLoader/Drawer';
|
||||||
import { Actions, Create, Destroy } from '../../Actions';
|
import { Actions, Create, Destroy } from '../../Actions';
|
||||||
@ -35,16 +35,19 @@ export function Kanban(props: any) {
|
|||||||
rowKey = 'id',
|
rowKey = 'id',
|
||||||
} = schema;
|
} = schema;
|
||||||
const { dataSource = [] } = groupField;
|
const { dataSource = [] } = groupField;
|
||||||
console.log({groupField, dataSource})
|
console.log({ groupField, dataSource });
|
||||||
|
|
||||||
const paginated = false;
|
const paginated = false;
|
||||||
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const { data, loading, mutate, refresh, run, params } = useRequest((params = {}, ...args) => {
|
const { data, loading, mutate, refresh, run, params } = useRequest(
|
||||||
|
(params = {}, ...args) => {
|
||||||
const { current, pageSize, sorter, filter, ...restParams } = params;
|
const { current, pageSize, sorter, filter, ...restParams } = params;
|
||||||
console.log('paramsparamsparamsparamsparams', params, args);
|
console.log('paramsparamsparamsparamsparams', params, args);
|
||||||
return api.resource(resourceName).list({
|
return api
|
||||||
|
.resource(resourceName)
|
||||||
|
.list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
page: paginated ? current : 1,
|
page: paginated ? current : 1,
|
||||||
perPage: paginated ? pageSize : -1,
|
perPage: paginated ? pageSize : -1,
|
||||||
@ -61,8 +64,8 @@ export function Kanban(props: any) {
|
|||||||
// __parent ? {
|
// __parent ? {
|
||||||
// collection_name: __parent,
|
// collection_name: __parent,
|
||||||
// } : null,
|
// } : null,
|
||||||
].filter(obj => obj && Object.keys(obj).length)
|
].filter(obj => obj && Object.keys(obj).length),
|
||||||
}
|
},
|
||||||
// ...args2,
|
// ...args2,
|
||||||
})
|
})
|
||||||
.then(({ data = [], meta = {} }) => {
|
.then(({ data = [], meta = {} }) => {
|
||||||
@ -73,9 +76,11 @@ export function Kanban(props: any) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
paginated,
|
paginated,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Spin />;
|
return <Spin />;
|
||||||
@ -85,7 +90,7 @@ export function Kanban(props: any) {
|
|||||||
return {
|
return {
|
||||||
id: group.value,
|
id: group.value,
|
||||||
title: group.label,
|
title: group.label,
|
||||||
cards: filter(data?.list, (item) => {
|
cards: filter(data?.list, item => {
|
||||||
return get(item, groupField.name) === group.value;
|
return get(item, groupField.name) === group.value;
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@ -121,7 +126,9 @@ export function Kanban(props: any) {
|
|||||||
<Actions
|
<Actions
|
||||||
associatedKey={associatedKey}
|
associatedKey={associatedKey}
|
||||||
style={{ marginBottom: 14 }}
|
style={{ marginBottom: 14 }}
|
||||||
actions={actions.filter(action => !['create', 'destroy'].includes(action.type))}
|
actions={actions.filter(
|
||||||
|
action => !['create', 'destroy'].includes(action.type),
|
||||||
|
)}
|
||||||
onTrigger={{
|
onTrigger={{
|
||||||
async filter(values) {
|
async filter(values) {
|
||||||
const items = values.filter.and || values.filter.or;
|
const items = values.filter.and || values.filter.or;
|
||||||
@ -139,7 +146,7 @@ export function Kanban(props: any) {
|
|||||||
disableCardDrag={disableCardDrag}
|
disableCardDrag={disableCardDrag}
|
||||||
onLaneRemove={console.log}
|
onLaneRemove={console.log}
|
||||||
renderCard={(data, { dragging, removeCard }) => {
|
renderCard={(data, { dragging, removeCard }) => {
|
||||||
const openDetails = (e) => {
|
const openDetails = e => {
|
||||||
if (!detailsOpenMode || !details.length) {
|
if (!detailsOpenMode || !details.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -148,12 +155,15 @@ export function Kanban(props: any) {
|
|||||||
history.push(`/admin/${paths[2]}/${data[rowKey]}/0`);
|
history.push(`/admin/${paths[2]}/${data[rowKey]}/0`);
|
||||||
} else {
|
} else {
|
||||||
Drawer.open({
|
Drawer.open({
|
||||||
headerStyle: details.length > 1 ? {
|
headerStyle:
|
||||||
|
details.length > 1
|
||||||
|
? {
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
borderBottom: 0,
|
borderBottom: 0,
|
||||||
// paddingTop: 16,
|
// paddingTop: 16,
|
||||||
// marginBottom: -4,
|
// marginBottom: -4,
|
||||||
} : {},
|
}
|
||||||
|
: {},
|
||||||
title: data[labelField],
|
title: data[labelField],
|
||||||
content: ({ resolve, closeWithConfirm }) => (
|
content: ({ resolve, closeWithConfirm }) => (
|
||||||
<div>
|
<div>
|
||||||
@ -183,18 +193,19 @@ export function Kanban(props: any) {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
hoverable
|
hoverable
|
||||||
size={'small'}
|
size={'small'}
|
||||||
style={{background: '#fff', minWidth: 250, maxWidth: 250, marginBottom: 12}}
|
style={{
|
||||||
|
background: '#fff',
|
||||||
|
minWidth: 250,
|
||||||
|
maxWidth: 250,
|
||||||
|
marginBottom: 12,
|
||||||
|
}}
|
||||||
bordered={false}
|
bordered={false}
|
||||||
title={(
|
title={<div onClick={openDetails}>{data[labelField]}</div>}
|
||||||
<div onClick={openDetails}>
|
|
||||||
{data[labelField]}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
bodyStyle={bodyStyle}
|
bodyStyle={bodyStyle}
|
||||||
extra={
|
extra={
|
||||||
allowRemoveCard && (
|
allowRemoveCard && (
|
||||||
@ -226,9 +237,14 @@ export function Kanban(props: any) {
|
|||||||
{fields.map((field: any) => {
|
{fields.map((field: any) => {
|
||||||
return (
|
return (
|
||||||
<Descriptions.Item label={field.title || field.name}>
|
<Descriptions.Item label={field.title || field.name}>
|
||||||
<Field data={data} viewType={'descriptions'} schema={field} value={get(data, field.name)}/>
|
<Field
|
||||||
|
data={data}
|
||||||
|
viewType={'descriptions'}
|
||||||
|
schema={field}
|
||||||
|
value={get(data, field.name)}
|
||||||
|
/>
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
)}
|
)}
|
||||||
@ -244,9 +260,15 @@ export function Kanban(props: any) {
|
|||||||
[groupField.name]: destination.toColumnId,
|
[groupField.name]: destination.toColumnId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const destColumn = columns.find( column => column.id === destination.toColumnId);
|
const destColumn = columns.find(
|
||||||
const targetIndex = get(destColumn, ['cards', destination.toPosition+1, rowKey]);
|
column => column.id === destination.toColumnId,
|
||||||
console.log({targetIndex, card, destination})
|
);
|
||||||
|
const targetIndex = get(destColumn, [
|
||||||
|
'cards',
|
||||||
|
destination.toPosition + 1,
|
||||||
|
rowKey,
|
||||||
|
]);
|
||||||
|
console.log({ targetIndex, card, destination });
|
||||||
await api.resource(resourceName).sort({
|
await api.resource(resourceName).sort({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
resourceKey: card[rowKey],
|
resourceKey: card[rowKey],
|
||||||
@ -269,8 +291,11 @@ export function Kanban(props: any) {
|
|||||||
renderColumnHeader={({ title, id }, { addCard }) => {
|
renderColumnHeader={({ title, id }, { addCard }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="react-kanban-column-header"><span>{ title }</span></div>
|
<div className="react-kanban-column-header">
|
||||||
{allowAddCard && <Create
|
<span>{title}</span>
|
||||||
|
</div>
|
||||||
|
{allowAddCard && (
|
||||||
|
<Create
|
||||||
onFinish={(values: any) => {
|
onFinish={(values: any) => {
|
||||||
refresh();
|
refresh();
|
||||||
}}
|
}}
|
||||||
@ -290,7 +315,9 @@ export function Kanban(props: any) {
|
|||||||
background: '#fff',
|
background: '#fff',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})}/>}
|
})}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.noco-card-adder-button:hover {
|
.noco-card-adder-button:hover {
|
||||||
background: rgba(255, 255, 255, .4) !important;
|
background: rgba(255, 255, 255, 0.4) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.noco-kanban-view {
|
.noco-kanban-view {
|
||||||
|
@ -5,7 +5,16 @@ import { Spin } from '@nocobase/client';
|
|||||||
import { useRequest, useLocation } from 'umi';
|
import { useRequest, useLocation } from 'umi';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import { Actions } from '../Actions';
|
import { Actions } from '../Actions';
|
||||||
import { Modal, Table as AntdTable, Card, Pagination, Button, Tabs, Descriptions, Tooltip } from 'antd';
|
import {
|
||||||
|
Modal,
|
||||||
|
Table as AntdTable,
|
||||||
|
Card,
|
||||||
|
Pagination,
|
||||||
|
Button,
|
||||||
|
Tabs,
|
||||||
|
Descriptions,
|
||||||
|
Tooltip,
|
||||||
|
} from 'antd';
|
||||||
import { LoadingOutlined } from '@ant-design/icons';
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
import { components, fields2columns } from '@/components/views/SortableTable';
|
import { components, fields2columns } from '@/components/views/SortableTable';
|
||||||
import ReactDragListView from 'react-drag-listview';
|
import ReactDragListView from 'react-drag-listview';
|
||||||
@ -19,7 +28,19 @@ import { Form } from './Form';
|
|||||||
import { View } from './';
|
import { View } from './';
|
||||||
|
|
||||||
export function Details(props) {
|
export function Details(props) {
|
||||||
const { onValueChange, onReset, __parent, noRequest, associatedKey, resourceName, onFinish, onDataChange, data, items = [], resolve } = props;
|
const {
|
||||||
|
onValueChange,
|
||||||
|
onReset,
|
||||||
|
__parent,
|
||||||
|
noRequest,
|
||||||
|
associatedKey,
|
||||||
|
resourceName,
|
||||||
|
onFinish,
|
||||||
|
onDataChange,
|
||||||
|
data,
|
||||||
|
items = [],
|
||||||
|
resolve,
|
||||||
|
} = props;
|
||||||
if (!items || items.length === 0) {
|
if (!items || items.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -28,9 +49,13 @@ export function Details(props) {
|
|||||||
<div className={'page-tabs'}>
|
<div className={'page-tabs'}>
|
||||||
{items.length > 1 && (
|
{items.length > 1 && (
|
||||||
<div className={'tabs-wrap'}>
|
<div className={'tabs-wrap'}>
|
||||||
<Tabs size={'small'} activeKey={`${currentTabIndex}`} onChange={(activeKey) => {
|
<Tabs
|
||||||
|
size={'small'}
|
||||||
|
activeKey={`${currentTabIndex}`}
|
||||||
|
onChange={activeKey => {
|
||||||
setCurrentTabIndex(activeKey);
|
setCurrentTabIndex(activeKey);
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{items.map((page, index) => (
|
{items.map((page, index) => (
|
||||||
<Tabs.TabPane tab={page.title} key={`${index}`} />
|
<Tabs.TabPane tab={page.title} key={`${index}`} />
|
||||||
))}
|
))}
|
||||||
@ -41,7 +66,8 @@ export function Details(props) {
|
|||||||
let viewName: string;
|
let viewName: string;
|
||||||
if (typeof view === 'string') {
|
if (typeof view === 'string') {
|
||||||
viewName = `${resourceName}.${view}`;
|
viewName = `${resourceName}.${view}`;
|
||||||
} if (typeof view === 'object') {
|
}
|
||||||
|
if (typeof view === 'object') {
|
||||||
viewName = `${resourceName}.${view.name}`;
|
viewName = `${resourceName}.${view.name}`;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@ -54,7 +80,8 @@ export function Details(props) {
|
|||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
onDataChange={onDataChange}
|
onDataChange={onDataChange}
|
||||||
data={data}
|
data={data}
|
||||||
viewName={viewName}/>
|
viewName={viewName}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
@ -62,7 +89,11 @@ export function Details(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function generateIndex(): string {
|
export function generateIndex(): string {
|
||||||
return `${Math.random().toString(36).replace('0.', '').slice(-4).padStart(4, '0')}`;
|
return `${Math.random()
|
||||||
|
.toString(36)
|
||||||
|
.replace('0.', '')
|
||||||
|
.slice(-4)
|
||||||
|
.padStart(4, '0')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SubTable(props: any) {
|
export function SubTable(props: any) {
|
||||||
@ -71,7 +102,7 @@ export function SubTable(props: any) {
|
|||||||
schema = {},
|
schema = {},
|
||||||
associatedKey,
|
associatedKey,
|
||||||
onChange,
|
onChange,
|
||||||
size = 'middle'
|
size = 'middle',
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -111,22 +142,20 @@ export function SubTable(props: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (draggable && !sortField) {
|
if (draggable && !sortField) {
|
||||||
sortField = 'sort',
|
(sortField = 'sort'),
|
||||||
cloneFields.unshift({
|
cloneFields.unshift({
|
||||||
"dataIndex": [
|
dataIndex: ['sort'],
|
||||||
"sort"
|
title: '排序',
|
||||||
],
|
name: 'sort',
|
||||||
"title": "排序",
|
interface: 'sort',
|
||||||
"name": "sort",
|
type: 'sort',
|
||||||
"interface": "sort",
|
required: true,
|
||||||
"type": "sort",
|
developerMode: false,
|
||||||
"required": true,
|
component: {
|
||||||
"developerMode": false,
|
type: 'sort',
|
||||||
"component": {
|
showInTable: true,
|
||||||
"type": "sort",
|
width: 60,
|
||||||
"showInTable": true,
|
className: 'drag-visible',
|
||||||
"width": 60,
|
|
||||||
"className": "drag-visible"
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -136,15 +165,20 @@ export function SubTable(props: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { type } = associationField;
|
const { type } = associationField;
|
||||||
const { data = [], loading, mutate, refresh, run, params } = useRequest((params = {}, ...args) => {
|
const { data = [], loading, mutate, refresh, run, params } = useRequest(
|
||||||
return !associatedKey || type === 'virtual' || type === 'json' ? Promise.resolve({
|
(params = {}, ...args) => {
|
||||||
|
return !associatedKey || type === 'virtual' || type === 'json'
|
||||||
|
? Promise.resolve({
|
||||||
data: (props.data || []).map(item => {
|
data: (props.data || []).map(item => {
|
||||||
if (!item[rowKey]) {
|
if (!item[rowKey]) {
|
||||||
item[rowKey] = generateIndex();
|
item[rowKey] = generateIndex();
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
}) : api.resource(resourceName).list({
|
: api
|
||||||
|
.resource(resourceName)
|
||||||
|
.list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
perPage: -1,
|
perPage: -1,
|
||||||
'fields[appends]': appends,
|
'fields[appends]': appends,
|
||||||
@ -153,7 +187,7 @@ export function SubTable(props: any) {
|
|||||||
if (!Array.isArray(data)) {
|
if (!Array.isArray(data)) {
|
||||||
return {
|
return {
|
||||||
data: [],
|
data: [],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
data: data.map(item => {
|
data: data.map(item => {
|
||||||
@ -161,12 +195,14 @@ export function SubTable(props: any) {
|
|||||||
item[rowKey] = generateIndex();
|
item[rowKey] = generateIndex();
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
})
|
}),
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
paginated: false,
|
paginated: false,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const dataSource = data as any;
|
const dataSource = data as any;
|
||||||
|
|
||||||
@ -179,11 +215,11 @@ export function SubTable(props: any) {
|
|||||||
return { ...v, [sortField]: i };
|
return { ...v, [sortField]: i };
|
||||||
});
|
});
|
||||||
mutate(data);
|
mutate(data);
|
||||||
onChange && await onChange(data);
|
onChange && (await onChange(data));
|
||||||
},
|
},
|
||||||
handleSelector: ".drag-handle",
|
handleSelector: '.drag-handle',
|
||||||
ignoreSelector: "tr.ant-table-expanded-row",
|
ignoreSelector: 'tr.ant-table-expanded-row',
|
||||||
nodeSelector: "tr.ant-table-row"
|
nodeSelector: 'tr.ant-table-row',
|
||||||
};
|
};
|
||||||
|
|
||||||
const tableProps: any = {};
|
const tableProps: any = {};
|
||||||
@ -194,15 +230,23 @@ export function SubTable(props: any) {
|
|||||||
tableProps.rowSelection = {
|
tableProps.rowSelection = {
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
selectedRowKeys,
|
selectedRowKeys,
|
||||||
onChange: (selectedRowKeys: React.ReactText[], selectedRows: React.ReactText[]) => {
|
onChange: (
|
||||||
|
selectedRowKeys: React.ReactText[],
|
||||||
|
selectedRows: React.ReactText[],
|
||||||
|
) => {
|
||||||
setSelectedRowKeys(selectedRowKeys);
|
setSelectedRowKeys(selectedRowKeys);
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Actions size={size} __parent={__parent} associatedKey={associatedKey} noRequest={true} onTrigger={{
|
<Actions
|
||||||
|
size={size}
|
||||||
|
__parent={__parent}
|
||||||
|
associatedKey={associatedKey}
|
||||||
|
noRequest={true}
|
||||||
|
onTrigger={{
|
||||||
async create(values) {
|
async create(values) {
|
||||||
values[rowKey] = generateIndex();
|
values[rowKey] = generateIndex();
|
||||||
let data = [...dataSource];
|
let data = [...dataSource];
|
||||||
@ -211,7 +255,7 @@ export function SubTable(props: any) {
|
|||||||
return { ...v, [sortField]: i };
|
return { ...v, [sortField]: i };
|
||||||
});
|
});
|
||||||
mutate(data);
|
mutate(data);
|
||||||
onChange && await onChange(data);
|
onChange && (await onChange(data));
|
||||||
},
|
},
|
||||||
async add(items = []) {
|
async add(items = []) {
|
||||||
let data = [...dataSource];
|
let data = [...dataSource];
|
||||||
@ -223,46 +267,60 @@ export function SubTable(props: any) {
|
|||||||
return { ...v, [sortField]: i };
|
return { ...v, [sortField]: i };
|
||||||
});
|
});
|
||||||
mutate(data);
|
mutate(data);
|
||||||
onChange && await onChange(data);
|
onChange && (await onChange(data));
|
||||||
},
|
},
|
||||||
async destroy() {
|
async destroy() {
|
||||||
let data = dataSource.filter(item => !selectedRowKeys.includes(item[rowKey]));
|
let data = dataSource.filter(
|
||||||
|
item => !selectedRowKeys.includes(item[rowKey]),
|
||||||
|
);
|
||||||
data = data.map((v: any, i) => {
|
data = data.map((v: any, i) => {
|
||||||
return { ...v, [sortField]: i };
|
return { ...v, [sortField]: i };
|
||||||
});
|
});
|
||||||
mutate(data);
|
mutate(data);
|
||||||
onChange && await onChange(data);
|
onChange && (await onChange(data));
|
||||||
},
|
},
|
||||||
}} actions={actions} style={{ marginBottom: 14, marginTop: -31 }}/>
|
}}
|
||||||
|
actions={actions}
|
||||||
|
style={{ marginBottom: 14, marginTop: -31 }}
|
||||||
|
/>
|
||||||
<ReactDragListView {...dragProps}>
|
<ReactDragListView {...dragProps}>
|
||||||
<AntdTable
|
<AntdTable
|
||||||
rowKey={rowKey}
|
rowKey={rowKey}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
size={size}
|
size={size}
|
||||||
columns={fields2columns(cloneFields, { mutate, dataSource, onChange })}
|
columns={fields2columns(cloneFields, {
|
||||||
|
mutate,
|
||||||
|
dataSource,
|
||||||
|
onChange,
|
||||||
|
})}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
onChange={(pagination, filters, sorter, extra) => {
|
onChange={(pagination, filters, sorter, extra) => {}}
|
||||||
|
|
||||||
}}
|
|
||||||
components={{
|
components={{
|
||||||
body: {
|
body: {
|
||||||
row: ({ className, ...others }) => {
|
row: ({ className, ...others }) => {
|
||||||
if (!details.length) {
|
if (!details.length) {
|
||||||
return <tr className={className} {...others}/>
|
return <tr className={className} {...others} />;
|
||||||
}
|
}
|
||||||
return <tr className={className ? `${className} row-clickable` : 'row-clickable'} {...others}/>
|
return (
|
||||||
|
<tr
|
||||||
|
className={
|
||||||
|
className ? `${className} row-clickable` : 'row-clickable'
|
||||||
|
}
|
||||||
|
{...others}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
expandable={expandable}
|
expandable={expandable}
|
||||||
onRow={(data, index) => ({
|
onRow={(data, index) => ({
|
||||||
onClick: (e) => {
|
onClick: e => {
|
||||||
const className = (e.target as HTMLElement).className;
|
const className = (e.target as HTMLElement).className;
|
||||||
if (typeof className === 'string' &&
|
if (
|
||||||
(className.includes('ant-table-selection-column')
|
typeof className === 'string' &&
|
||||||
|| className.includes('ant-checkbox')
|
(className.includes('ant-table-selection-column') ||
|
||||||
|| className.includes('ant-radio')
|
className.includes('ant-checkbox') ||
|
||||||
)
|
className.includes('ant-radio'))
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -280,7 +338,7 @@ export function SubTable(props: any) {
|
|||||||
// __parent={__parent}
|
// __parent={__parent}
|
||||||
associatedKey={associatedKey}
|
associatedKey={associatedKey}
|
||||||
resourceName={resourceName}
|
resourceName={resourceName}
|
||||||
onFinish={async (values) => {
|
onFinish={async values => {
|
||||||
let data = [...dataSource];
|
let data = [...dataSource];
|
||||||
console.log({ values });
|
console.log({ values });
|
||||||
data[index] = values;
|
data[index] = values;
|
||||||
@ -288,14 +346,12 @@ export function SubTable(props: any) {
|
|||||||
return { ...v, [sortField]: i };
|
return { ...v, [sortField]: i };
|
||||||
});
|
});
|
||||||
mutate(data);
|
mutate(data);
|
||||||
onChange && await onChange(data);
|
onChange && (await onChange(data));
|
||||||
console.log({ values, data });
|
console.log({ values, data });
|
||||||
resolve();
|
resolve();
|
||||||
}}
|
}}
|
||||||
onReset={resolve}
|
onReset={resolve}
|
||||||
onDataChange={() => {
|
onDataChange={() => {}}
|
||||||
|
|
||||||
}}
|
|
||||||
onValueChange={() => {
|
onValueChange={() => {
|
||||||
closeWithConfirm && closeWithConfirm(true);
|
closeWithConfirm && closeWithConfirm(true);
|
||||||
}}
|
}}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user