fix: quick edit (#1176)
Co-authored-by: sealday <sealday@gmail.com> Reviewed-on: daoyoucloud/tachybase#1176
This commit is contained in:
parent
7118423925
commit
31188169f3
@ -54,6 +54,7 @@
|
|||||||
"react-i18next": "^11.15.1",
|
"react-i18next": "^11.15.1",
|
||||||
"react-iframe": "~1.8.5",
|
"react-iframe": "~1.8.5",
|
||||||
"react-image-lightbox": "^5.1.4",
|
"react-image-lightbox": "^5.1.4",
|
||||||
|
"react-intersection-observer": "^9.10.3",
|
||||||
"react-js-cron": "^3.1.0",
|
"react-js-cron": "^3.1.0",
|
||||||
"react-quill": "^2.0.0",
|
"react-quill": "^2.0.0",
|
||||||
"react-router": "^6.11.2",
|
"react-router": "^6.11.2",
|
||||||
@ -64,6 +65,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/react": "^14.0.0",
|
"@testing-library/react": "^14.0.0",
|
||||||
|
"@types/flat": "^5.0.5",
|
||||||
"@types/lodash": "^4.17.5",
|
"@types/lodash": "^4.17.5",
|
||||||
"@types/markdown-it": "12.2.3",
|
"@types/markdown-it": "12.2.3",
|
||||||
"@types/markdown-it-highlightjs": "3.3.1",
|
"@types/markdown-it-highlightjs": "3.3.1",
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import { ArrayField, observer, onFieldChange, Schema, useFieldSchema, useFormEffects } from '@tachybase/schema';
|
import { ArrayField, observer, onFieldChange, Schema, useFieldSchema, useFormEffects } from '@tachybase/schema';
|
||||||
import { fuzzysearch } from '@tachybase/utils/client';
|
import { fuzzysearch } from '@tachybase/utils/client';
|
||||||
|
|
||||||
import { CheckOutlined, SearchOutlined } from '@ant-design/icons';
|
import { CheckOutlined, SearchOutlined } from '@ant-design/icons';
|
||||||
import { useAsyncEffect, useDeepCompareEffect } from 'ahooks';
|
import { useAsyncEffect, useDeepCompareEffect } from 'ahooks';
|
||||||
import { Button, Collapse, CollapseProps, Input, Space, Tabs } from 'antd';
|
import { Button, Collapse, CollapseProps, Input, Space, Tabs } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import flat from 'flat';
|
import flat from 'flat';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useInView } from 'react-intersection-observer';
|
||||||
|
|
||||||
import { useAPIClient } from '../../../../api-client';
|
import { useAPIClient } from '../../../../api-client';
|
||||||
import { useCollectionManager } from '../../../../data-source';
|
import { useCollectionManager } from '../../../../data-source';
|
||||||
@ -14,15 +16,79 @@ import { markRecordAsNew } from '../../../../data-source/collection-record/isNew
|
|||||||
import { useAssociationFieldContext } from '../hooks';
|
import { useAssociationFieldContext } from '../hooks';
|
||||||
import { useFieldServiceFilter } from './hook';
|
import { useFieldServiceFilter } from './hook';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ css }) => {
|
||||||
|
return {
|
||||||
|
container: css`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
max-height: 30vh;
|
||||||
|
.left-pane {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 200px;
|
||||||
|
background-color: red;
|
||||||
|
overflow-y: auto;
|
||||||
|
div {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right-pane {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1;
|
||||||
|
background-color: blue;
|
||||||
|
div {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ObservableItem = ({ item, onChange, leftRef }) => {
|
||||||
|
const { ref } = useInView({
|
||||||
|
threshold: 0.1,
|
||||||
|
onChange: (inView: boolean) => {
|
||||||
|
if (inView) {
|
||||||
|
leftRef.current?.querySelector('#parent-item-' + item.id).scrollIntoView({
|
||||||
|
behavior: 'auto',
|
||||||
|
block: 'nearest',
|
||||||
|
inline: 'start',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div key={item.id} id={'item-' + item.id} ref={ref}>
|
||||||
|
{item?.childrenItems
|
||||||
|
?.sort((a, b) => (a.sort != null ? a.sort - b.sort : a.id - b.id))
|
||||||
|
.map((childrenitem, index) => (
|
||||||
|
<Button
|
||||||
|
key={index}
|
||||||
|
onClick={() => {
|
||||||
|
onChange(childrenitem);
|
||||||
|
}}
|
||||||
|
icon={childrenitem.checked ? <CheckOutlined /> : null}
|
||||||
|
>
|
||||||
|
{childrenitem.label}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const InternalTabs = observer((props) => {
|
export const InternalTabs = observer((props) => {
|
||||||
|
const ref = useRef<HTMLDivElement>();
|
||||||
|
const { styles } = useStyles();
|
||||||
const { fieldValue, setFieldValue } = props as any;
|
const { fieldValue, setFieldValue } = props as any;
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const cm = useCollectionManager();
|
const cm = useCollectionManager();
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
|
const [filter, setFilter] = useState<string>('');
|
||||||
const isQuickAdd = fieldSchema['parent']['x-component-props']['isQuickAdd'];
|
const isQuickAdd = fieldSchema['parent']['x-component-props']['isQuickAdd'];
|
||||||
const { value: quickAddField, fieldInterface } = fieldSchema['parent']['x-component-props']?.['quickAddField'] || {};
|
const { value: quickAddField, fieldInterface } = fieldSchema['parent']['x-component-props']?.['quickAddField'] || {};
|
||||||
const quickAddParentField = fieldSchema['parent']['x-component-props']['quickAddParentCollection'];
|
const quickAddParentField = fieldSchema['parent']['x-component-props']['quickAddParentCollection'];
|
||||||
const [options, setOptions] = useState([]);
|
|
||||||
const [defOptions, setDefOptions] = useState([]);
|
const [defOptions, setDefOptions] = useState([]);
|
||||||
const { field } = useAssociationFieldContext<ArrayField>();
|
const { field } = useAssociationFieldContext<ArrayField>();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -61,7 +127,7 @@ export const InternalTabs = observer((props) => {
|
|||||||
const collection = cm.getCollection(quickAddParentField.collectionField);
|
const collection = cm.getCollection(quickAddParentField.collectionField);
|
||||||
const parentItem = await api.request({
|
const parentItem = await api.request({
|
||||||
url: collection.name + ':list',
|
url: collection.name + ':list',
|
||||||
params: { pageSize: 9999 },
|
params: { pageSize: 99999 },
|
||||||
});
|
});
|
||||||
itemParams['parentTitleField'] = collection.titleField;
|
itemParams['parentTitleField'] = collection.titleField;
|
||||||
itemParams['parentOptions'] = parentItem?.data?.data;
|
itemParams['parentOptions'] = parentItem?.data?.data;
|
||||||
@ -82,12 +148,6 @@ export const InternalTabs = observer((props) => {
|
|||||||
itemParams['childrenOptions']?.length &&
|
itemParams['childrenOptions']?.length &&
|
||||||
quickAddParentField?.value !== 'none'
|
quickAddParentField?.value !== 'none'
|
||||||
) {
|
) {
|
||||||
optionsItem.unshift({
|
|
||||||
value: 'all',
|
|
||||||
label: t('All'),
|
|
||||||
key: 'all',
|
|
||||||
childrenItems: [],
|
|
||||||
});
|
|
||||||
itemParams['parentOptions'].forEach((parentItem) => {
|
itemParams['parentOptions'].forEach((parentItem) => {
|
||||||
const items = itemParams['childrenOptions']
|
const items = itemParams['childrenOptions']
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
@ -103,7 +163,6 @@ export const InternalTabs = observer((props) => {
|
|||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
if (!items.length) return;
|
if (!items.length) return;
|
||||||
optionsItem[0].childrenItems.push(...items);
|
|
||||||
optionsItem.push({
|
optionsItem.push({
|
||||||
...parentItem,
|
...parentItem,
|
||||||
value: parentItem?.id,
|
value: parentItem?.id,
|
||||||
@ -126,7 +185,6 @@ export const InternalTabs = observer((props) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setOptions(optionsItem);
|
|
||||||
setDefOptions(optionsItem);
|
setDefOptions(optionsItem);
|
||||||
} else if (quickAddSchema) {
|
} else if (quickAddSchema) {
|
||||||
const fieldItem = cm.getCollectionField(quickAddSchema['x-collection-field']);
|
const fieldItem = cm.getCollectionField(quickAddSchema['x-collection-field']);
|
||||||
@ -134,7 +192,6 @@ export const InternalTabs = observer((props) => {
|
|||||||
fieldItem.uiSchema.enum.forEach((item) => {
|
fieldItem.uiSchema.enum.forEach((item) => {
|
||||||
optionsItem.push(item);
|
optionsItem.push(item);
|
||||||
});
|
});
|
||||||
setOptions(optionsItem);
|
|
||||||
setDefOptions(optionsItem);
|
setDefOptions(optionsItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,14 +202,10 @@ export const InternalTabs = observer((props) => {
|
|||||||
const fieldTabs = field.value;
|
const fieldTabs = field.value;
|
||||||
if (quickAddParentField && quickAddParentField?.value !== 'none') {
|
if (quickAddParentField && quickAddParentField?.value !== 'none') {
|
||||||
const filterParantOptions = tabsParantFilterOptions(defOptions, fieldTabs, quickAddField);
|
const filterParantOptions = tabsParantFilterOptions(defOptions, fieldTabs, quickAddField);
|
||||||
const filterOptions = tabsParantFilterOptions(options, fieldTabs, quickAddField);
|
|
||||||
setDefOptions(filterParantOptions);
|
setDefOptions(filterParantOptions);
|
||||||
setOptions(filterOptions);
|
|
||||||
} else {
|
} else {
|
||||||
const filterDefOptions = tabsFilterOptions(defOptions, fieldTabs, quickAddField);
|
const filterDefOptions = tabsFilterOptions(defOptions, fieldTabs, quickAddField);
|
||||||
setDefOptions(filterDefOptions);
|
setDefOptions(filterDefOptions);
|
||||||
const filterOptions = tabsFilterOptions(options, fieldTabs, quickAddField);
|
|
||||||
setOptions(filterOptions);
|
|
||||||
}
|
}
|
||||||
}, [quickAddField, fieldValue]);
|
}, [quickAddField, fieldValue]);
|
||||||
|
|
||||||
@ -161,28 +214,27 @@ export const InternalTabs = observer((props) => {
|
|||||||
setChangeForm(field);
|
setChangeForm(field);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const onSelect = (value) => {
|
|
||||||
if (!value) {
|
// 下面做过滤的逻辑
|
||||||
setOptions(defOptions);
|
let options = defOptions;
|
||||||
}
|
|
||||||
if (quickAddParentField && quickAddParentField.value !== 'none') {
|
if (quickAddParentField && quickAddParentField.value !== 'none') {
|
||||||
const filterOption = defOptions
|
const filterOption = defOptions
|
||||||
?.map((item) => {
|
?.map((item) => {
|
||||||
const filterItem = item?.childrenItems?.filter((childrenItem) => fuzzysearch(value, childrenItem?.label));
|
const filterItem = item?.childrenItems?.filter((childrenItem) => fuzzysearch(filter, childrenItem?.label));
|
||||||
if (fuzzysearch(value, item?.label) || filterItem?.length) {
|
if (fuzzysearch(filter, item?.label) || filterItem?.length) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
childrenItems: filterItem.length ? filterItem : item.childrenItems,
|
childrenItems: filterItem.length ? filterItem : item.childrenItems,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
setOptions(filterOption);
|
options = filterOption;
|
||||||
} else {
|
} else {
|
||||||
const filterOption = defOptions.filter((item) => fuzzysearch(value, item?.label));
|
const filterOption = defOptions.filter((item) => fuzzysearch(filter, item?.label));
|
||||||
setOptions(filterOption);
|
options = filterOption;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const onChange = (item) => {
|
const onChange = (item) => {
|
||||||
field.value = field.value || [];
|
field.value = field.value || [];
|
||||||
@ -197,43 +249,41 @@ export const InternalTabs = observer((props) => {
|
|||||||
<Input
|
<Input
|
||||||
placeholder={t('Please enter search content')}
|
placeholder={t('Please enter search content')}
|
||||||
prefix={<SearchOutlined />}
|
prefix={<SearchOutlined />}
|
||||||
|
value={filter}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onSelect(e?.target?.value);
|
setFilter(e.target.value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{quickAddParentField && quickAddParentField?.value !== 'none' ? (
|
{quickAddParentField && quickAddParentField?.value !== 'none' ? (
|
||||||
<>
|
<div className={styles.container} ref={ref}>
|
||||||
{options.length ? (
|
<div className="left-pane">
|
||||||
<Tabs
|
{options
|
||||||
tabPosition="left"
|
.sort((a, b) => (a.sort != null ? a.sort - b.sort : a.id - b.id))
|
||||||
items={options
|
.map((item) => (
|
||||||
.sort((a, b) => (a.sort != null ? a.sort - b.sort : a.id - b.id))
|
<div
|
||||||
.map((item) => ({
|
id={'parent-item-' + item.id}
|
||||||
...item,
|
key={item.id}
|
||||||
children: (
|
onClick={() => {
|
||||||
<Space style={{ maxHeight: '30vh', overflow: 'auto', padding: '10px 0px 20px 0px' }}>
|
ref.current?.querySelector('#item-' + item.id).scrollIntoView({
|
||||||
{item?.childrenItems
|
behavior: 'auto',
|
||||||
?.sort((a, b) => (a.sort != null ? a.sort - b.sort : a.id - b.id))
|
block: 'nearest',
|
||||||
.map((childrenitem, index) => (
|
inline: 'start',
|
||||||
<Button
|
});
|
||||||
key={index}
|
}}
|
||||||
onClick={() => {
|
>
|
||||||
onChange(childrenitem);
|
{item.label}
|
||||||
}}
|
</div>
|
||||||
icon={childrenitem.checked ? <CheckOutlined /> : null}
|
))}
|
||||||
>
|
</div>
|
||||||
{childrenitem.label}
|
<div className="right-pane">
|
||||||
</Button>
|
{options
|
||||||
))}
|
.sort((a, b) => (a.sort != null ? a.sort - b.sort : a.id - b.id))
|
||||||
</Space>
|
.map((item) => (
|
||||||
),
|
<ObservableItem item={item} onChange={onChange} key={item.id} leftRef={ref} />
|
||||||
}))}
|
))}
|
||||||
style={{ maxHeight: '30vh', padding: '10px' }}
|
</div>
|
||||||
defaultActiveKey="all"
|
</div>
|
||||||
></Tabs>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<Space style={{ maxHeight: '30vh', overflow: 'auto', padding: '10px' }}>
|
<Space style={{ maxHeight: '30vh', overflow: 'auto', padding: '10px' }}>
|
||||||
{options.map((item, index) => (
|
{options.map((item, index) => (
|
||||||
|
2168
pnpm-lock.yaml
2168
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user