improve calendar and kanban
This commit is contained in:
parent
3e5e9c194c
commit
f3bdaf641e
@ -30,6 +30,7 @@ import { Space, Card, Modal, Spin } from 'antd';
|
|||||||
import { ArrayTable } from '../../schemas/array-table';
|
import { ArrayTable } from '../../schemas/array-table';
|
||||||
import { Action } from '../../schemas/action';
|
import { Action } from '../../schemas/action';
|
||||||
import { AddNew } from '../../schemas/add-new';
|
import { AddNew } from '../../schemas/add-new';
|
||||||
|
import { Calendar } from '../../schemas/calendar';
|
||||||
import { Cascader } from '../../schemas/cascader';
|
import { Cascader } from '../../schemas/cascader';
|
||||||
import { Checkbox } from '../../schemas/checkbox';
|
import { Checkbox } from '../../schemas/checkbox';
|
||||||
import { ColorSelect } from '../../schemas/color-select';
|
import { ColorSelect } from '../../schemas/color-select';
|
||||||
@ -46,6 +47,7 @@ import { IconPicker } from '../../schemas/icon-picker';
|
|||||||
import { Input } from '../../schemas/input';
|
import { Input } from '../../schemas/input';
|
||||||
import { InputNumber } from '../../schemas/input-number';
|
import { InputNumber } from '../../schemas/input-number';
|
||||||
import { Markdown } from '../../schemas/markdown';
|
import { Markdown } from '../../schemas/markdown';
|
||||||
|
import { Kanban } from '../../schemas/kanban';
|
||||||
import { Menu } from '../../schemas/menu';
|
import { Menu } from '../../schemas/menu';
|
||||||
import { Password } from '../../schemas/password';
|
import { Password } from '../../schemas/password';
|
||||||
import { Radio } from '../../schemas/radio';
|
import { Radio } from '../../schemas/radio';
|
||||||
@ -170,6 +172,7 @@ export const SchemaField = createSchemaField({
|
|||||||
|
|
||||||
Action,
|
Action,
|
||||||
AddNew,
|
AddNew,
|
||||||
|
Calendar,
|
||||||
Cascader,
|
Cascader,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
ColorSelect,
|
ColorSelect,
|
||||||
@ -182,6 +185,7 @@ export const SchemaField = createSchemaField({
|
|||||||
IconPicker,
|
IconPicker,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
|
Kanban,
|
||||||
Markdown,
|
Markdown,
|
||||||
Menu,
|
Menu,
|
||||||
Password,
|
Password,
|
||||||
|
@ -347,6 +347,123 @@ function generateCardItemSchema(component) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Kanban: {
|
||||||
|
type: 'array',
|
||||||
|
name: 'kanban1',
|
||||||
|
'x-decorator': 'CardItem',
|
||||||
|
'x-decorator-props': {
|
||||||
|
style: {
|
||||||
|
background: 'none',
|
||||||
|
},
|
||||||
|
bodyStyle: {
|
||||||
|
padding: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-designable-bar': 'Kanban.DesignableBar',
|
||||||
|
'x-component': 'Kanban',
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'A',
|
||||||
|
title: 'A1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
type: 'A',
|
||||||
|
title: 'A2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
type: 'A',
|
||||||
|
title: 'A3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
type: 'B',
|
||||||
|
title: 'B4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
type: 'B',
|
||||||
|
title: 'B5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '6',
|
||||||
|
type: 'B',
|
||||||
|
title: 'B6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '7',
|
||||||
|
type: 'C',
|
||||||
|
title: 'C7',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '8',
|
||||||
|
type: 'C',
|
||||||
|
title: 'C8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '9',
|
||||||
|
type: 'C',
|
||||||
|
title: 'C9',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: {
|
||||||
|
card1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Kanban.Card',
|
||||||
|
properties: {
|
||||||
|
item1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Kanban.Item',
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
type: 'string',
|
||||||
|
// title: '标题',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
view1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Kanban.Card.View',
|
||||||
|
properties: {
|
||||||
|
item1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Kanban.Item',
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
type: 'string',
|
||||||
|
title: '标题',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Calendar: {
|
||||||
|
type: 'array',
|
||||||
|
name: 'calendar1',
|
||||||
|
'x-component': 'Calendar',
|
||||||
|
'x-designable-bar': 'Calendar.DesignableBar',
|
||||||
|
'x-decorator': 'CardItem',
|
||||||
|
default: [],
|
||||||
|
properties: {
|
||||||
|
event: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Calendar.Event',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
'Chart.Column': {
|
'Chart.Column': {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'CardItem',
|
'x-decorator': 'CardItem',
|
||||||
@ -733,6 +850,12 @@ AddNew.CardItem = observer((props: any) => {
|
|||||||
overlay={
|
overlay={
|
||||||
<Menu
|
<Menu
|
||||||
onClick={async (info) => {
|
onClick={async (info) => {
|
||||||
|
if (info.key.startsWith('Calendar.')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (info.key.startsWith('Kanban.')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let data: ISchema;
|
let data: ISchema;
|
||||||
let collectionName = null;
|
let collectionName = null;
|
||||||
let isNew = false;
|
let isNew = false;
|
||||||
@ -801,22 +924,10 @@ AddNew.CardItem = observer((props: any) => {
|
|||||||
{[
|
{[
|
||||||
{ key: 'Table', title: '表格', icon: 'TableOutlined' },
|
{ key: 'Table', title: '表格', icon: 'TableOutlined' },
|
||||||
{ key: 'Form', title: '表单', icon: 'FormOutlined' },
|
{ key: 'Form', title: '表单', icon: 'FormOutlined' },
|
||||||
{
|
|
||||||
key: 'Calendar',
|
|
||||||
title: '日历',
|
|
||||||
icon: 'CalendarOutlined',
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'Kanban',
|
|
||||||
title: '看板',
|
|
||||||
icon: 'CreditCardOutlined',
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
].map((view) => (
|
].map((view) => (
|
||||||
<Menu.SubMenu
|
<Menu.SubMenu
|
||||||
icon={<IconPicker type={view.icon} />}
|
icon={<IconPicker type={view.icon} />}
|
||||||
disabled={view.disabled}
|
// disabled={view.disabled}
|
||||||
key={view.key}
|
key={view.key}
|
||||||
title={view.title}
|
title={view.title}
|
||||||
>
|
>
|
||||||
@ -840,6 +951,220 @@ AddNew.CardItem = observer((props: any) => {
|
|||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu.SubMenu>
|
</Menu.SubMenu>
|
||||||
))}
|
))}
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
key: 'Calendar',
|
||||||
|
title: '日历',
|
||||||
|
icon: 'CalendarOutlined',
|
||||||
|
// disabled: true,
|
||||||
|
},
|
||||||
|
].map((view) => (
|
||||||
|
<Menu.SubMenu
|
||||||
|
icon={<IconPicker type={view.icon} />}
|
||||||
|
// disabled={view.disabled}
|
||||||
|
key={view.key}
|
||||||
|
title={view.title}
|
||||||
|
>
|
||||||
|
<Menu.ItemGroup
|
||||||
|
className={'display-fields'}
|
||||||
|
key={`${view.key}-select`}
|
||||||
|
title={'所属数据表'}
|
||||||
|
>
|
||||||
|
{collections?.map((item) => (
|
||||||
|
<Menu.Item
|
||||||
|
style={{ minWidth: 150 }}
|
||||||
|
key={`Calendar.collection.${item.name}.${view.key}`}
|
||||||
|
onClick={async () => {
|
||||||
|
const values = await FormDialog(`日历配置`, () => {
|
||||||
|
return (
|
||||||
|
<FormLayout layout={'vertical'}>
|
||||||
|
<SchemaField
|
||||||
|
schema={{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
titleField: {
|
||||||
|
type: 'string',
|
||||||
|
title: '标题字段',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
enum: item?.generalFields?.map(
|
||||||
|
(field) => {
|
||||||
|
return {
|
||||||
|
label: field?.uiSchema.title,
|
||||||
|
name: field?.name,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
startTimeField: {
|
||||||
|
title: '开始日期字段',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
enum: item?.generalFields
|
||||||
|
?.filter(
|
||||||
|
(field) => field.dataType === 'date',
|
||||||
|
)
|
||||||
|
?.map((field) => {
|
||||||
|
return {
|
||||||
|
label: field?.uiSchema.title,
|
||||||
|
name: field?.name,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
endTimeField: {
|
||||||
|
title: '结束日期字段',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
enum: item?.generalFields
|
||||||
|
?.filter(
|
||||||
|
(field) => field.dataType === 'date',
|
||||||
|
)
|
||||||
|
?.map((field) => {
|
||||||
|
return {
|
||||||
|
label: field?.uiSchema.title,
|
||||||
|
name: field?.name,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormLayout>
|
||||||
|
);
|
||||||
|
}).open({});
|
||||||
|
let data = generateCardItemSchema('Calendar');
|
||||||
|
const collectionName = item.name;
|
||||||
|
if (schema['key']) {
|
||||||
|
data['key'] = uid();
|
||||||
|
}
|
||||||
|
if (collectionName) {
|
||||||
|
data['x-component-props'] =
|
||||||
|
data['x-component-props'] || {};
|
||||||
|
data['x-component-props']['resource'] =
|
||||||
|
collectionName;
|
||||||
|
data['x-component-props']['collectionName'] =
|
||||||
|
collectionName;
|
||||||
|
data['x-component-props']['titleField'] =
|
||||||
|
values.titleField;
|
||||||
|
data['x-component-props']['startTimeField'] =
|
||||||
|
values.startTimeField;
|
||||||
|
data['x-component-props']['endTimeField'] =
|
||||||
|
values.endTimeField;
|
||||||
|
}
|
||||||
|
if (isGridBlock(schema)) {
|
||||||
|
path.pop();
|
||||||
|
path.pop();
|
||||||
|
data = generateGridBlock(data);
|
||||||
|
} else if (isGrid(schema)) {
|
||||||
|
data = generateGridBlock(data);
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
let s;
|
||||||
|
if (isGrid(schema)) {
|
||||||
|
s = appendChild(data, [...path]);
|
||||||
|
} else if (defaultAction === 'insertAfter') {
|
||||||
|
s = insertAfter(data, [...path]);
|
||||||
|
} else {
|
||||||
|
s = insertBefore(data, [...path]);
|
||||||
|
}
|
||||||
|
await createSchema(s);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.title}
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu.ItemGroup>
|
||||||
|
{/* <Menu.Divider></Menu.Divider> */}
|
||||||
|
{/* <Menu.Item icon={<PlusOutlined />} key={`addNew${view.key}`}>
|
||||||
|
新建数据表
|
||||||
|
</Menu.Item> */}
|
||||||
|
</Menu.SubMenu>
|
||||||
|
))}
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
key: 'Kanban',
|
||||||
|
title: '看板',
|
||||||
|
icon: 'CreditCardOutlined',
|
||||||
|
// disabled: true,
|
||||||
|
},
|
||||||
|
].map((view) => (
|
||||||
|
<Menu.SubMenu
|
||||||
|
icon={<IconPicker type={view.icon} />}
|
||||||
|
// disabled={view.disabled}
|
||||||
|
key={view.key}
|
||||||
|
title={view.title}
|
||||||
|
>
|
||||||
|
<Menu.ItemGroup
|
||||||
|
className={'display-fields'}
|
||||||
|
key={`${view.key}-select`}
|
||||||
|
title={'所属数据表'}
|
||||||
|
>
|
||||||
|
{collections?.map((item) => (
|
||||||
|
<Menu.SubMenu
|
||||||
|
// style={{ minWidth: 150 }}
|
||||||
|
key={`collection.${item.name}.${view.key}`}
|
||||||
|
title={item.title}
|
||||||
|
>
|
||||||
|
<Menu.ItemGroup title={'选择分组字段'}>
|
||||||
|
<Menu.Item
|
||||||
|
style={{ minWidth: 150 }}
|
||||||
|
key={`Kanban.collection.${item.name}.${view.key}`}
|
||||||
|
onClick={async () => {
|
||||||
|
let data = generateCardItemSchema('Kanban');
|
||||||
|
const collectionName = item.name;
|
||||||
|
if (schema['key']) {
|
||||||
|
data['key'] = uid();
|
||||||
|
}
|
||||||
|
if (collectionName) {
|
||||||
|
data['x-component-props'] =
|
||||||
|
data['x-component-props'] || {};
|
||||||
|
data['x-component-props']['resource'] =
|
||||||
|
collectionName;
|
||||||
|
data['x-component-props']['collectionName'] =
|
||||||
|
collectionName;
|
||||||
|
// data['x-component-props']['groupField'] = '';
|
||||||
|
}
|
||||||
|
if (isGridBlock(schema)) {
|
||||||
|
path.pop();
|
||||||
|
path.pop();
|
||||||
|
data = generateGridBlock(data);
|
||||||
|
} else if (isGrid(schema)) {
|
||||||
|
data = generateGridBlock(data);
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
let s;
|
||||||
|
if (isGrid(schema)) {
|
||||||
|
s = appendChild(data, [...path]);
|
||||||
|
} else if (defaultAction === 'insertAfter') {
|
||||||
|
s = insertAfter(data, [...path]);
|
||||||
|
} else {
|
||||||
|
s = insertBefore(data, [...path]);
|
||||||
|
}
|
||||||
|
await createSchema(s);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
分组字段1
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.ItemGroup>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
// <Menu.Item
|
||||||
|
// style={{ minWidth: 150 }}
|
||||||
|
// key={`collection.${item.name}.${view.key}`}
|
||||||
|
// >
|
||||||
|
// {item.title}
|
||||||
|
// </Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu.ItemGroup>
|
||||||
|
<Menu.Divider></Menu.Divider>
|
||||||
|
<Menu.Item icon={<PlusOutlined />} key={`addNew${view.key}`}>
|
||||||
|
新建数据表
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
))}
|
||||||
</Menu.ItemGroup>
|
</Menu.ItemGroup>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.ItemGroup title={'多媒体区块'}>
|
<Menu.ItemGroup title={'多媒体区块'}>
|
||||||
@ -887,7 +1212,7 @@ AddNew.CardItem = observer((props: any) => {
|
|||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu.ItemGroup>
|
</Menu.ItemGroup>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.SubMenu key={'Ref'} title={'引用模板'}>
|
<Menu.SubMenu key={'Ref'} icon={<LinkOutlined />} title={'引用模板'}>
|
||||||
<Menu.ItemGroup key={'form-select'} title={'选择模板'}>
|
<Menu.ItemGroup key={'form-select'} title={'选择模板'}>
|
||||||
<Menu.Item key={'Ref.ActionLogs'}>操作日志</Menu.Item>
|
<Menu.Item key={'Ref.ActionLogs'}>操作日志</Menu.Item>
|
||||||
</Menu.ItemGroup>
|
</Menu.ItemGroup>
|
||||||
|
91
packages/client/src/schemas/calendar/DesignableBar.tsx
Normal file
91
packages/client/src/schemas/calendar/DesignableBar.tsx
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import React, { useContext, useMemo, useRef, useState } from 'react';
|
||||||
|
import { createForm } from '@formily/core';
|
||||||
|
import {
|
||||||
|
SchemaOptionsContext,
|
||||||
|
Schema,
|
||||||
|
useFieldSchema,
|
||||||
|
observer,
|
||||||
|
SchemaExpressionScopeContext,
|
||||||
|
FormProvider,
|
||||||
|
ISchema,
|
||||||
|
useField,
|
||||||
|
useForm,
|
||||||
|
RecursionField,
|
||||||
|
} from '@formily/react';
|
||||||
|
import { useSchemaPath, SchemaField, useDesignable, removeSchema } from '../';
|
||||||
|
import get from 'lodash/get';
|
||||||
|
import { Button, Dropdown, Menu, Space } from 'antd';
|
||||||
|
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||||
|
import cls from 'classnames';
|
||||||
|
import { FormLayout } from '@formily/antd';
|
||||||
|
// import './style.less';
|
||||||
|
import AddNew from '../add-new';
|
||||||
|
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||||
|
import { isGridRowOrCol } from '../grid';
|
||||||
|
import constate from 'constate';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { getSchemaPath } from '../../components/schema-renderer';
|
||||||
|
import { useCollection, useCollectionContext } from '../../constate';
|
||||||
|
import { useTable } from '../table';
|
||||||
|
|
||||||
|
export const DesignableBar = observer((props) => {
|
||||||
|
const field = useField();
|
||||||
|
const { designable, schema, refresh, deepRemove } = useDesignable();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const { dragRef } = useContext(DraggableBlockContext);
|
||||||
|
const { props: tableProps } = useTable();
|
||||||
|
const collectionName = field.componentProps?.collectionName || tableProps?.collectionName;
|
||||||
|
const { collection } = useCollection({ collectionName });
|
||||||
|
return (
|
||||||
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
|
<div className={'designable-info'}>{collection?.title || collection?.name}</div>
|
||||||
|
<span
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
className={cls('designable-bar-actions', { active: visible })}
|
||||||
|
>
|
||||||
|
<Space size={2}>
|
||||||
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
|
{dragRef && <DragOutlined ref={dragRef} />}
|
||||||
|
<Dropdown
|
||||||
|
trigger={['click']}
|
||||||
|
visible={visible}
|
||||||
|
onVisibleChange={(visible) => {
|
||||||
|
setVisible(visible);
|
||||||
|
}}
|
||||||
|
overlay={
|
||||||
|
<Menu>
|
||||||
|
{/* <Menu.Item
|
||||||
|
key={'update'}
|
||||||
|
onClick={() => {
|
||||||
|
field.readPretty = true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
编辑表单配置
|
||||||
|
</Menu.Item> */}
|
||||||
|
{/* <Menu.Divider /> */}
|
||||||
|
<Menu.Item
|
||||||
|
key={'delete'}
|
||||||
|
onClick={async () => {
|
||||||
|
const removed = deepRemove();
|
||||||
|
// console.log({ removed })
|
||||||
|
const last = removed.pop();
|
||||||
|
if (isGridRowOrCol(last)) {
|
||||||
|
await removeSchema(last);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
移除
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuOutlined />
|
||||||
|
</Dropdown>
|
||||||
|
</Space>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -11,6 +11,7 @@ import { LeftOutlined, RightOutlined } from '@ant-design/icons';
|
|||||||
import { Space, Button, Radio, Select } from 'antd';
|
import { Space, Button, Radio, Select } from 'antd';
|
||||||
import './style2.less';
|
import './style2.less';
|
||||||
import { observer, useField } from '@formily/react';
|
import { observer, useField } from '@formily/react';
|
||||||
|
import { DesignableBar } from './DesignableBar';
|
||||||
|
|
||||||
const localizer = momentLocalizer(moment);
|
const localizer = momentLocalizer(moment);
|
||||||
|
|
||||||
@ -71,7 +72,7 @@ function Toolbar(props: ToolbarProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Calendar = observer((props: any) => {
|
export const Calendar: any = observer((props: any) => {
|
||||||
const field = useField<Formily.Core.Models.ArrayField>();
|
const field = useField<Formily.Core.Models.ArrayField>();
|
||||||
return (
|
return (
|
||||||
<div style={{ height: 700 }}>
|
<div style={{ height: 700 }}>
|
||||||
@ -130,3 +131,5 @@ export const Calendar = observer((props: any) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Calendar.DesignableBar = DesignableBar;
|
||||||
|
91
packages/client/src/schemas/kanban/DesignableBar.tsx
Normal file
91
packages/client/src/schemas/kanban/DesignableBar.tsx
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import React, { useContext, useMemo, useRef, useState } from 'react';
|
||||||
|
import { createForm } from '@formily/core';
|
||||||
|
import {
|
||||||
|
SchemaOptionsContext,
|
||||||
|
Schema,
|
||||||
|
useFieldSchema,
|
||||||
|
observer,
|
||||||
|
SchemaExpressionScopeContext,
|
||||||
|
FormProvider,
|
||||||
|
ISchema,
|
||||||
|
useField,
|
||||||
|
useForm,
|
||||||
|
RecursionField,
|
||||||
|
} from '@formily/react';
|
||||||
|
import { useSchemaPath, SchemaField, useDesignable, removeSchema } from '../';
|
||||||
|
import get from 'lodash/get';
|
||||||
|
import { Button, Dropdown, Menu, Space } from 'antd';
|
||||||
|
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||||
|
import cls from 'classnames';
|
||||||
|
import { FormLayout } from '@formily/antd';
|
||||||
|
import './style.less';
|
||||||
|
import AddNew from '../add-new';
|
||||||
|
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||||
|
import { isGridRowOrCol } from '../grid';
|
||||||
|
import constate from 'constate';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { getSchemaPath } from '../../components/schema-renderer';
|
||||||
|
import { useCollection, useCollectionContext } from '../../constate';
|
||||||
|
import { useTable } from '../table';
|
||||||
|
|
||||||
|
export const DesignableBar = observer((props) => {
|
||||||
|
const field = useField();
|
||||||
|
const { designable, schema, refresh, deepRemove } = useDesignable();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const { dragRef } = useContext(DraggableBlockContext);
|
||||||
|
const { props: tableProps } = useTable();
|
||||||
|
const collectionName = field.componentProps?.collectionName || tableProps?.collectionName;
|
||||||
|
const { collection } = useCollection({ collectionName });
|
||||||
|
return (
|
||||||
|
<div className={cls('designable-bar', { active: visible })}>
|
||||||
|
<div className={'designable-info'}>{collection?.title || collection?.name}</div>
|
||||||
|
<span
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
className={cls('designable-bar-actions', { active: visible })}
|
||||||
|
>
|
||||||
|
<Space size={2}>
|
||||||
|
<AddNew.CardItem defaultAction={'insertAfter'} ghost />
|
||||||
|
{dragRef && <DragOutlined ref={dragRef} />}
|
||||||
|
<Dropdown
|
||||||
|
trigger={['click']}
|
||||||
|
visible={visible}
|
||||||
|
onVisibleChange={(visible) => {
|
||||||
|
setVisible(visible);
|
||||||
|
}}
|
||||||
|
overlay={
|
||||||
|
<Menu>
|
||||||
|
{/* <Menu.Item
|
||||||
|
key={'update'}
|
||||||
|
onClick={() => {
|
||||||
|
field.readPretty = true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
编辑表单配置
|
||||||
|
</Menu.Item> */}
|
||||||
|
{/* <Menu.Divider /> */}
|
||||||
|
<Menu.Item
|
||||||
|
key={'delete'}
|
||||||
|
onClick={async () => {
|
||||||
|
const removed = deepRemove();
|
||||||
|
// console.log({ removed })
|
||||||
|
const last = removed.pop();
|
||||||
|
if (isGridRowOrCol(last)) {
|
||||||
|
await removeSchema(last);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
移除
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuOutlined />
|
||||||
|
</Dropdown>
|
||||||
|
</Space>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -22,6 +22,7 @@ import { createContext } from 'react';
|
|||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
|
import { DesignableBar } from './DesignableBar';
|
||||||
|
|
||||||
export function SortableItem(props) {
|
export function SortableItem(props) {
|
||||||
const {
|
const {
|
||||||
@ -95,109 +96,114 @@ export const Kanban: any = observer(() => {
|
|||||||
return prev;
|
return prev;
|
||||||
}, null);
|
}, null);
|
||||||
return (
|
return (
|
||||||
<div className={'kanban'}>
|
<div>
|
||||||
<DndContext
|
{/* <div>
|
||||||
// collisionDetection={closestCorners}
|
<Button>筛选</Button>
|
||||||
onDragEnd={({ active, over }) => {
|
</div> */}
|
||||||
const source = values.find((item) => item.id === active?.id);
|
<div className={'kanban'}>
|
||||||
const target = values.find((item) => item.id === over?.id);
|
<DndContext
|
||||||
if (source && target) {
|
// collisionDetection={closestCorners}
|
||||||
const fromIndex = values.findIndex(
|
onDragEnd={({ active, over }) => {
|
||||||
(item) => item.id === active?.id,
|
const source = values.find((item) => item.id === active?.id);
|
||||||
);
|
const target = values.find((item) => item.id === over?.id);
|
||||||
const toIndex = values.findIndex((item) => item.id === over?.id);
|
if (source && target) {
|
||||||
// setValues((items) => {
|
const fromIndex = values.findIndex(
|
||||||
// const fromIndex = items.findIndex(
|
(item) => item.id === active?.id,
|
||||||
// (item) => item.id === active?.id,
|
);
|
||||||
// );
|
const toIndex = values.findIndex((item) => item.id === over?.id);
|
||||||
// const toIndex = items.findIndex(
|
// setValues((items) => {
|
||||||
// (item) => item.id === over?.id,
|
// const fromIndex = items.findIndex(
|
||||||
// );
|
// (item) => item.id === active?.id,
|
||||||
// return arrayMove(items, fromIndex, toIndex);
|
// );
|
||||||
// });
|
// const toIndex = items.findIndex(
|
||||||
field.move(fromIndex, toIndex);
|
// (item) => item.id === over?.id,
|
||||||
}
|
// );
|
||||||
}}
|
// return arrayMove(items, fromIndex, toIndex);
|
||||||
onDragOver={({ active, over }) => {
|
// });
|
||||||
if (!over) {
|
field.move(fromIndex, toIndex);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (active?.id === over?.id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const source = values.find((item) => item.id === active?.id);
|
|
||||||
if (source && over?.data?.current?.type === 'column') {
|
|
||||||
source.type = over.id;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log('active.id', active.id, over?.data?.current);
|
|
||||||
const target = values.find((item) => item.id === over?.id);
|
|
||||||
if (source && target) {
|
|
||||||
if (source.type !== target.type) {
|
|
||||||
source.type = target.type;
|
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
}}
|
onDragOver={({ active, over }) => {
|
||||||
>
|
if (!over) {
|
||||||
<DragOverlay style={{ pointerEvents: 'none' }}>aaa</DragOverlay>
|
return;
|
||||||
|
}
|
||||||
<SortableContext
|
if (active?.id === over?.id) {
|
||||||
strategy={horizontalListSortingStrategy}
|
return;
|
||||||
items={columns}
|
}
|
||||||
|
const source = values.find((item) => item.id === active?.id);
|
||||||
|
if (source && over?.data?.current?.type === 'column') {
|
||||||
|
source.type = over.id;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log('active.id', active.id, over?.data?.current);
|
||||||
|
const target = values.find((item) => item.id === over?.id);
|
||||||
|
if (source && target) {
|
||||||
|
if (source.type !== target.type) {
|
||||||
|
source.type = target.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{columns.map((column) => (
|
<DragOverlay style={{ pointerEvents: 'none' }}>aaa</DragOverlay>
|
||||||
<SortableItem
|
|
||||||
key={column.id}
|
<SortableContext
|
||||||
type={'column'}
|
strategy={horizontalListSortingStrategy}
|
||||||
className={'column'}
|
items={columns}
|
||||||
id={column.id}
|
>
|
||||||
>
|
{columns.map((column) => (
|
||||||
<div className={'column-title'}>{column.title}</div>
|
<SortableItem
|
||||||
<SortableContext
|
key={column.id}
|
||||||
strategy={verticalListSortingStrategy}
|
type={'column'}
|
||||||
items={column.items}
|
className={'column'}
|
||||||
|
id={column.id}
|
||||||
>
|
>
|
||||||
{column.items.map((item) => {
|
<div className={'column-title'}>{column.title}</div>
|
||||||
const index = values.findIndex(
|
<SortableContext
|
||||||
(value) => value.id === item.id,
|
strategy={verticalListSortingStrategy}
|
||||||
);
|
items={column.items}
|
||||||
return (
|
>
|
||||||
<SortableItem
|
{column.items.map((item) => {
|
||||||
key={item.id}
|
const index = values.findIndex(
|
||||||
className={'item'}
|
(value) => value.id === item.id,
|
||||||
id={item.id}
|
);
|
||||||
type={'item'}
|
return (
|
||||||
>
|
<SortableItem
|
||||||
<KanbanCardContext.Provider
|
key={item.id}
|
||||||
value={{
|
className={'item'}
|
||||||
index: index,
|
id={item.id}
|
||||||
record: item,
|
type={'item'}
|
||||||
viewSchema: cardViewSchema,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<RecursionField name={index} schema={cardSchema} />
|
<KanbanCardContext.Provider
|
||||||
</KanbanCardContext.Provider>
|
value={{
|
||||||
</SortableItem>
|
index: index,
|
||||||
);
|
record: item,
|
||||||
})}
|
viewSchema: cardViewSchema,
|
||||||
</SortableContext>
|
}}
|
||||||
<Button
|
>
|
||||||
type={'text'}
|
<RecursionField name={index} schema={cardSchema} />
|
||||||
icon={<PlusOutlined />}
|
</KanbanCardContext.Provider>
|
||||||
onClick={() => {
|
</SortableItem>
|
||||||
field.push({
|
);
|
||||||
id: uid(),
|
})}
|
||||||
type: column.id,
|
</SortableContext>
|
||||||
title: uid(),
|
<Button
|
||||||
});
|
type={'text'}
|
||||||
}}
|
icon={<PlusOutlined />}
|
||||||
>
|
onClick={() => {
|
||||||
添加卡片
|
field.push({
|
||||||
</Button>
|
id: uid(),
|
||||||
</SortableItem>
|
type: column.id,
|
||||||
))}
|
title: uid(),
|
||||||
</SortableContext>
|
});
|
||||||
</DndContext>
|
}}
|
||||||
|
>
|
||||||
|
添加卡片
|
||||||
|
</Button>
|
||||||
|
</SortableItem>
|
||||||
|
))}
|
||||||
|
</SortableContext>
|
||||||
|
</DndContext>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -232,3 +238,5 @@ Kanban.Card = observer((props) => {
|
|||||||
Kanban.Card.View = observer((props) => {
|
Kanban.Card.View = observer((props) => {
|
||||||
return <div>{props.children}</div>;
|
return <div>{props.children}</div>;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Kanban.DesignableBar = DesignableBar;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 25vw;
|
width: 25vw;
|
||||||
background: #f9f9f9;
|
background: #f9f9f9;
|
||||||
margin: 0 1%;
|
margin: 0 12px;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
.kanban {
|
.kanban {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
margin: 0 -12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
@ -374,6 +374,12 @@ const useTableColumns = () => {
|
|||||||
|
|
||||||
const columnSchemas = schema.reduceProperties((columns, current) => {
|
const columnSchemas = schema.reduceProperties((columns, current) => {
|
||||||
if (isColumn(current)) {
|
if (isColumn(current)) {
|
||||||
|
if (current['x-hidden']) {
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
if (current['x-display'] && current['x-display'] !== 'visible') {
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
return [...columns, current];
|
return [...columns, current];
|
||||||
}
|
}
|
||||||
return [...columns];
|
return [...columns];
|
||||||
@ -1409,6 +1415,7 @@ Table.Filter.DesignableBar = () => {
|
|||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
setVisible(false);
|
||||||
const values = await FormDialog('修改名称和图标', () => {
|
const values = await FormDialog('修改名称和图标', () => {
|
||||||
return (
|
return (
|
||||||
<FormLayout layout={'vertical'}>
|
<FormLayout layout={'vertical'}>
|
||||||
@ -1531,6 +1538,7 @@ Table.ExportActionDesignableBar = () => {
|
|||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
setVisible(false);
|
||||||
const values = await FormDialog('修改名称和图标', () => {
|
const values = await FormDialog('修改名称和图标', () => {
|
||||||
return (
|
return (
|
||||||
<FormLayout layout={'vertical'}>
|
<FormLayout layout={'vertical'}>
|
||||||
@ -1721,6 +1729,7 @@ Table.Action.DesignableBar = () => {
|
|||||||
<Menu>
|
<Menu>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
setVisible(false);
|
||||||
const values = await FormDialog('修改名称和图标', () => {
|
const values = await FormDialog('修改名称和图标', () => {
|
||||||
return (
|
return (
|
||||||
<FormLayout layout={'vertical'}>
|
<FormLayout layout={'vertical'}>
|
||||||
@ -1901,6 +1910,7 @@ Table.Column.DesignableBar = () => {
|
|||||||
<Menu>
|
<Menu>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
setVisible(false);
|
||||||
const values = await FormDialog('修改列标题', () => {
|
const values = await FormDialog('修改列标题', () => {
|
||||||
return (
|
return (
|
||||||
<FormLayout layout={'vertical'}>
|
<FormLayout layout={'vertical'}>
|
||||||
@ -1940,7 +1950,6 @@ Table.Column.DesignableBar = () => {
|
|||||||
key: schema['key'],
|
key: schema['key'],
|
||||||
title: title,
|
title: title,
|
||||||
});
|
});
|
||||||
setVisible(false);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
修改列标题
|
修改列标题
|
||||||
@ -1948,14 +1957,20 @@ Table.Column.DesignableBar = () => {
|
|||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const s = remove();
|
|
||||||
const fieldName =
|
const fieldName =
|
||||||
schema['x-component-props']?.['fieldName'];
|
schema['x-component-props']?.['fieldName'];
|
||||||
displayed.remove(fieldName);
|
displayed.remove(fieldName);
|
||||||
await removeSchema(s);
|
schema['x-hidden'] = true;
|
||||||
|
refresh();
|
||||||
|
await updateSchema({
|
||||||
|
key: schema['key'],
|
||||||
|
['x-hidden']: true,
|
||||||
|
});
|
||||||
|
// const s = remove();
|
||||||
|
// await removeSchema(s);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
移除
|
隐藏
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user