mirror of
https://gitee.com/nocobase/nocobase.git
synced 2024-11-29 18:58:26 +08:00
Merge branch 'main' into next
This commit is contained in:
commit
08f25c2336
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import { getDateRanges } from '../util';
|
||||
import { getDateRanges, moment2str } from '../util';
|
||||
|
||||
describe('getDateRanges', () => {
|
||||
const dateRanges = getDateRanges();
|
||||
@ -139,3 +139,127 @@ describe('getDateRanges', () => {
|
||||
expect(end.toISOString()).toBe(dayjs().add(90, 'days').endOf('days').toISOString());
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDateRanges: shouldBeString is true and utc is false', () => {
|
||||
const dateRanges = getDateRanges({ shouldBeString: true, utc: false });
|
||||
|
||||
it('today', () => {
|
||||
const [start, end] = dateRanges.today();
|
||||
expect(start).toBe(moment2str(dayjs().startOf('day'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().endOf('day'), { utc: false }));
|
||||
});
|
||||
|
||||
test('yesterday', () => {
|
||||
const [start, end] = dateRanges.yesterday();
|
||||
expect(start).toBe(moment2str(dayjs().subtract(1, 'day').startOf('day'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().subtract(1, 'day').endOf('day'), { utc: false }));
|
||||
});
|
||||
|
||||
test('tomorrow', () => {
|
||||
const [start, end] = dateRanges.tomorrow();
|
||||
expect(start).toBe(moment2str(dayjs().add(1, 'day').startOf('day'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(1, 'day').endOf('day'), { utc: false }));
|
||||
});
|
||||
|
||||
it('lastWeek', () => {
|
||||
const [start, end] = dateRanges.lastWeek();
|
||||
expect(start).toBe(moment2str(dayjs().add(-1, 'week').startOf('isoWeek'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(-1, 'week').endOf('isoWeek'), { utc: false }));
|
||||
});
|
||||
|
||||
it('thisWeek', () => {
|
||||
const [start, end] = dateRanges.thisWeek();
|
||||
expect(start).toBe(moment2str(dayjs().startOf('isoWeek'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().endOf('isoWeek'), { utc: false }));
|
||||
});
|
||||
|
||||
it('nextWeek', () => {
|
||||
const [start, end] = dateRanges.nextWeek();
|
||||
expect(start).toBe(moment2str(dayjs().add(1, 'week').startOf('isoWeek'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(1, 'week').endOf('isoWeek'), { utc: false }));
|
||||
});
|
||||
|
||||
it('lastMonth', () => {
|
||||
const [start, end] = dateRanges.lastMonth();
|
||||
expect(start).toBe(moment2str(dayjs().add(-1, 'month').startOf('month'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(-1, 'month').endOf('month'), { utc: false }));
|
||||
});
|
||||
|
||||
it('thisMonth', () => {
|
||||
const [start, end] = dateRanges.thisMonth();
|
||||
expect(start).toBe(moment2str(dayjs().startOf('month'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().endOf('month'), { utc: false }));
|
||||
});
|
||||
|
||||
it('nextMonth', () => {
|
||||
const [start, end] = dateRanges.nextMonth();
|
||||
expect(start).toBe(moment2str(dayjs().add(1, 'month').startOf('month'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(1, 'month').endOf('month'), { utc: false }));
|
||||
});
|
||||
|
||||
it('lastQuarter', () => {
|
||||
const [start, end] = dateRanges.lastQuarter();
|
||||
expect(start).toBe(moment2str(dayjs().add(-1, 'quarter').startOf('quarter'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(-1, 'quarter').endOf('quarter'), { utc: false }));
|
||||
});
|
||||
|
||||
it('thisQuarter', () => {
|
||||
const [start, end] = dateRanges.thisQuarter();
|
||||
expect(start).toBe(moment2str(dayjs().startOf('quarter'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().endOf('quarter'), { utc: false }));
|
||||
});
|
||||
|
||||
it('nextQuarter', () => {
|
||||
const [start, end] = dateRanges.nextQuarter();
|
||||
expect(start).toBe(moment2str(dayjs().add(1, 'quarter').startOf('quarter'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(1, 'quarter').endOf('quarter'), { utc: false }));
|
||||
});
|
||||
|
||||
it('lastYear', () => {
|
||||
const [start, end] = dateRanges.lastYear();
|
||||
expect(start).toBe(moment2str(dayjs().add(-1, 'year').startOf('year'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(-1, 'year').endOf('year'), { utc: false }));
|
||||
});
|
||||
|
||||
it('thisYear', () => {
|
||||
const [start, end] = dateRanges.thisYear();
|
||||
expect(start).toBe(moment2str(dayjs().startOf('year'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().endOf('year'), { utc: false }));
|
||||
});
|
||||
|
||||
it('nextYear', () => {
|
||||
const [start, end] = dateRanges.nextYear();
|
||||
expect(start).toBe(moment2str(dayjs().add(1, 'year').startOf('year'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(1, 'year').endOf('year'), { utc: false }));
|
||||
});
|
||||
|
||||
it('last7Days', () => {
|
||||
const [start, end] = dateRanges.last7Days();
|
||||
expect(start).toBe(moment2str(dayjs().add(-6, 'days').startOf('days'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().endOf('days'), { utc: false }));
|
||||
});
|
||||
|
||||
it('next7Days', () => {
|
||||
const [start, end] = dateRanges.next7Days();
|
||||
expect(start).toBe(moment2str(dayjs().add(1, 'day').startOf('day'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(7, 'days').endOf('days'), { utc: false }));
|
||||
});
|
||||
|
||||
it('last30Days', () => {
|
||||
const [start, end] = dateRanges.last30Days();
|
||||
expect(start).toBe(moment2str(dayjs().add(-29, 'days').startOf('days'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().endOf('days'), { utc: false }));
|
||||
});
|
||||
|
||||
it('next30Days', () => {
|
||||
const [start, end] = dateRanges.next30Days();
|
||||
expect(start).toBe(moment2str(dayjs().add(1, 'day').startOf('day'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().add(30, 'days').endOf('days'), { utc: false }));
|
||||
});
|
||||
|
||||
it('last90Days', () => {
|
||||
const [start, end] = dateRanges.last90Days();
|
||||
expect(start).toBe(moment2str(dayjs().add(-89, 'days').startOf('days'), { utc: false }));
|
||||
expect(end).toBe(moment2str(dayjs().endOf('days'), { utc: false }));
|
||||
});
|
||||
});
|
||||
|
@ -145,7 +145,48 @@ const getEnd = (offset: any, unit: any) => {
|
||||
.endOf(unit);
|
||||
};
|
||||
|
||||
export const getDateRanges = () => {
|
||||
export const getDateRanges = (props?: {
|
||||
/** 日期是否是 UTC 格式 */
|
||||
utc?: boolean;
|
||||
/** 如果为 true 则返回的值是一个字符串 */
|
||||
shouldBeString?: boolean;
|
||||
}) => {
|
||||
if (props?.shouldBeString) {
|
||||
const toString = (date) => {
|
||||
if (Array.isArray(date)) {
|
||||
return date.map((d) => moment2str(d, { utc: props?.utc }));
|
||||
}
|
||||
return moment2str(date, { utc: props?.utc });
|
||||
};
|
||||
return {
|
||||
now: () => toString(dayjs()),
|
||||
today: () => toString([getStart(0, 'day'), getEnd(0, 'day')]),
|
||||
yesterday: () => toString([getStart(-1, 'day'), getEnd(-1, 'day')]),
|
||||
tomorrow: () => toString([getStart(1, 'day'), getEnd(1, 'day')]),
|
||||
thisWeek: () => toString([getStart(0, 'isoWeek'), getEnd(0, 'isoWeek')]),
|
||||
lastWeek: () => toString([getStart(-1, 'isoWeek'), getEnd(-1, 'isoWeek')]),
|
||||
nextWeek: () => toString([getStart(1, 'isoWeek'), getEnd(1, 'isoWeek')]),
|
||||
thisIsoWeek: () => toString([getStart(0, 'isoWeek'), getEnd(0, 'isoWeek')]),
|
||||
lastIsoWeek: () => toString([getStart(-1, 'isoWeek'), getEnd(-1, 'isoWeek')]),
|
||||
nextIsoWeek: () => toString([getStart(1, 'isoWeek'), getEnd(1, 'isoWeek')]),
|
||||
thisMonth: () => toString([getStart(0, 'month'), getEnd(0, 'month')]),
|
||||
lastMonth: () => toString([getStart(-1, 'month'), getEnd(-1, 'month')]),
|
||||
nextMonth: () => toString([getStart(1, 'month'), getEnd(1, 'month')]),
|
||||
thisQuarter: () => toString([getStart(0, 'quarter'), getEnd(0, 'quarter')]),
|
||||
lastQuarter: () => toString([getStart(-1, 'quarter'), getEnd(-1, 'quarter')]),
|
||||
nextQuarter: () => toString([getStart(1, 'quarter'), getEnd(1, 'quarter')]),
|
||||
thisYear: () => toString([getStart(0, 'year'), getEnd(0, 'year')]),
|
||||
lastYear: () => toString([getStart(-1, 'year'), getEnd(-1, 'year')]),
|
||||
nextYear: () => toString([getStart(1, 'year'), getEnd(1, 'year')]),
|
||||
last7Days: () => toString([getStart(-6, 'days'), getEnd(0, 'days')]),
|
||||
next7Days: () => toString([getStart(1, 'day'), getEnd(7, 'days')]),
|
||||
last30Days: () => toString([getStart(-29, 'days'), getEnd(0, 'days')]),
|
||||
next30Days: () => toString([getStart(1, 'day'), getEnd(30, 'days')]),
|
||||
last90Days: () => toString([getStart(-89, 'days'), getEnd(0, 'days')]),
|
||||
next90Days: () => toString([getStart(1, 'day'), getEnd(90, 'days')]),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
now: () => dayjs().toISOString(),
|
||||
today: () => [getStart(0, 'day'), getEnd(0, 'day')],
|
||||
|
@ -52,6 +52,7 @@ import {
|
||||
useBlockContext,
|
||||
useBlockRequestContext,
|
||||
} from '../block-provider/BlockProvider';
|
||||
import { CollectOperators, useOperators } from '../block-provider/CollectOperators';
|
||||
import {
|
||||
FormBlockContext,
|
||||
findFormBlock,
|
||||
@ -101,7 +102,7 @@ import { EnableChildCollections } from './EnableChildCollections';
|
||||
import { ChildDynamicComponent } from './EnableChildCollections/DynamicComponent';
|
||||
import { FormLinkageRules } from './LinkageRules';
|
||||
import { useLinkageCollectionFieldOptions } from './LinkageRules/action-hooks';
|
||||
import { LinkageRuleDataKeyMap, LinkageRuleCategory } from './LinkageRules/type';
|
||||
import { LinkageRuleCategory, LinkageRuleDataKeyMap } from './LinkageRules/type';
|
||||
|
||||
export interface SchemaSettingsProps {
|
||||
title?: any;
|
||||
@ -767,6 +768,7 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
|
||||
const { association } = useDataBlockProps() || {};
|
||||
const formCtx = useFormBlockContext();
|
||||
const blockOptions = useBlockContext();
|
||||
const { getOperators } = useOperators();
|
||||
const locationSearch = useLocationSearch();
|
||||
|
||||
// 解决变量`当前对象`值在弹窗中丢失的问题
|
||||
@ -790,64 +792,66 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
|
||||
{ title: schema.title || title, width },
|
||||
() => {
|
||||
return (
|
||||
<BlockContext.Provider value={blockOptions}>
|
||||
<VariablePopupRecordProvider
|
||||
recordData={popupRecordVariable?.value}
|
||||
collection={popupRecordVariable?.collection}
|
||||
parent={{
|
||||
recordData: parentPopupRecordVariable?.value,
|
||||
collection: parentPopupRecordVariable?.collection,
|
||||
}}
|
||||
>
|
||||
<CollectionRecordProvider record={noRecord ? null : record}>
|
||||
<FormBlockContext.Provider value={formCtx}>
|
||||
<SubFormProvider value={{ value: subFormValue, collection: subFormCollection }}>
|
||||
<FormActiveFieldsProvider
|
||||
name="form"
|
||||
getActiveFieldsName={upLevelActiveFields?.getActiveFieldsName}
|
||||
>
|
||||
<LocationSearchContext.Provider value={locationSearch}>
|
||||
<BlockRequestContext_deprecated.Provider value={ctx}>
|
||||
<DataSourceApplicationProvider dataSourceManager={dm} dataSource={dataSourceKey}>
|
||||
<AssociationOrCollectionProvider
|
||||
allowNull
|
||||
collection={collection.name}
|
||||
association={association}
|
||||
>
|
||||
<SchemaComponentOptions scope={options.scope} components={options.components}>
|
||||
<FormLayout
|
||||
layout={'vertical'}
|
||||
className={css`
|
||||
// screen > 576px
|
||||
@media (min-width: 576px) {
|
||||
min-width: 520px;
|
||||
}
|
||||
<CollectOperators defaultOperators={getOperators()}>
|
||||
<BlockContext.Provider value={blockOptions}>
|
||||
<VariablePopupRecordProvider
|
||||
recordData={popupRecordVariable?.value}
|
||||
collection={popupRecordVariable?.collection}
|
||||
parent={{
|
||||
recordData: parentPopupRecordVariable?.value,
|
||||
collection: parentPopupRecordVariable?.collection,
|
||||
}}
|
||||
>
|
||||
<CollectionRecordProvider record={noRecord ? null : record}>
|
||||
<FormBlockContext.Provider value={formCtx}>
|
||||
<SubFormProvider value={{ value: subFormValue, collection: subFormCollection }}>
|
||||
<FormActiveFieldsProvider
|
||||
name="form"
|
||||
getActiveFieldsName={upLevelActiveFields?.getActiveFieldsName}
|
||||
>
|
||||
<LocationSearchContext.Provider value={locationSearch}>
|
||||
<BlockRequestContext_deprecated.Provider value={ctx}>
|
||||
<DataSourceApplicationProvider dataSourceManager={dm} dataSource={dataSourceKey}>
|
||||
<AssociationOrCollectionProvider
|
||||
allowNull
|
||||
collection={collection.name}
|
||||
association={association}
|
||||
>
|
||||
<SchemaComponentOptions scope={options.scope} components={options.components}>
|
||||
<FormLayout
|
||||
layout={'vertical'}
|
||||
className={css`
|
||||
// screen > 576px
|
||||
@media (min-width: 576px) {
|
||||
min-width: 520px;
|
||||
}
|
||||
|
||||
// screen <= 576px
|
||||
@media (max-width: 576px) {
|
||||
min-width: 320px;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<ApplicationContext.Provider value={app}>
|
||||
<APIClientProvider apiClient={apiClient}>
|
||||
<ConfigProvider locale={locale}>
|
||||
<SchemaComponent components={components} scope={scope} schema={schema} />
|
||||
</ConfigProvider>
|
||||
</APIClientProvider>
|
||||
</ApplicationContext.Provider>
|
||||
</FormLayout>
|
||||
</SchemaComponentOptions>
|
||||
</AssociationOrCollectionProvider>
|
||||
</DataSourceApplicationProvider>
|
||||
</BlockRequestContext_deprecated.Provider>
|
||||
</LocationSearchContext.Provider>
|
||||
</FormActiveFieldsProvider>
|
||||
</SubFormProvider>
|
||||
</FormBlockContext.Provider>
|
||||
</CollectionRecordProvider>
|
||||
</VariablePopupRecordProvider>
|
||||
</BlockContext.Provider>
|
||||
// screen <= 576px
|
||||
@media (max-width: 576px) {
|
||||
min-width: 320px;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<ApplicationContext.Provider value={app}>
|
||||
<APIClientProvider apiClient={apiClient}>
|
||||
<ConfigProvider locale={locale}>
|
||||
<SchemaComponent components={components} scope={scope} schema={schema} />
|
||||
</ConfigProvider>
|
||||
</APIClientProvider>
|
||||
</ApplicationContext.Provider>
|
||||
</FormLayout>
|
||||
</SchemaComponentOptions>
|
||||
</AssociationOrCollectionProvider>
|
||||
</DataSourceApplicationProvider>
|
||||
</BlockRequestContext_deprecated.Provider>
|
||||
</LocationSearchContext.Provider>
|
||||
</FormActiveFieldsProvider>
|
||||
</SubFormProvider>
|
||||
</FormBlockContext.Provider>
|
||||
</CollectionRecordProvider>
|
||||
</VariablePopupRecordProvider>
|
||||
</BlockContext.Provider>
|
||||
</CollectOperators>
|
||||
);
|
||||
},
|
||||
theme,
|
||||
|
@ -7,8 +7,11 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { Schema } from '@formily/json-schema';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useOperators } from '../../../block-provider/CollectOperators';
|
||||
import { useDatePickerContext } from '../../../schema-component/antd/date-picker/DatePicker';
|
||||
import { getDateRanges } from '../../../schema-component/antd/date-picker/util';
|
||||
|
||||
interface Props {
|
||||
@ -20,6 +23,8 @@ interface Props {
|
||||
* 不需要禁用选项,一般会在表达式中使用
|
||||
*/
|
||||
noDisabled?: boolean;
|
||||
/** 消费变量值的字段 */
|
||||
targetFieldSchema?: Schema;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,11 +194,16 @@ export const useDateVariable = ({ operator, schema, noDisabled }: Props) => {
|
||||
* @param param0
|
||||
* @returns
|
||||
*/
|
||||
export const useDatetimeVariable = ({ operator, schema, noDisabled }: Props = {}) => {
|
||||
export const useDatetimeVariable = ({ operator, schema, noDisabled, targetFieldSchema }: Props = {}) => {
|
||||
const { t } = useTranslation();
|
||||
const { getOperator } = useOperators();
|
||||
const { utc = true } = useDatePickerContext();
|
||||
|
||||
const datetimeSettings = useMemo(() => {
|
||||
const operatorValue = operator?.value || '';
|
||||
const disabled = noDisabled ? false : !['DatePicker.RangePicker'].includes(schema?.['x-component']);
|
||||
const operatorValue = operator?.value || getOperator(targetFieldSchema?.name) || '';
|
||||
const disabled = noDisabled
|
||||
? false
|
||||
: !['DatePicker.RangePicker'].includes(schema?.['x-component']) && !operatorValue;
|
||||
const dateOptions = [
|
||||
{
|
||||
key: 'now',
|
||||
@ -336,9 +346,9 @@ export const useDatetimeVariable = ({ operator, schema, noDisabled }: Props = {}
|
||||
disabled: dateOptions.every((option) => option.disabled),
|
||||
children: dateOptions,
|
||||
};
|
||||
}, [schema?.['x-component']]);
|
||||
}, [schema?.['x-component'], targetFieldSchema]);
|
||||
|
||||
const datetimeCtx = useMemo(() => getDateRanges(), []);
|
||||
const datetimeCtx = useMemo(() => getDateRanges({ shouldBeString: true, utc }), [utc]);
|
||||
|
||||
return {
|
||||
datetimeSettings,
|
||||
|
@ -73,7 +73,7 @@ export const useVariableOptions = ({
|
||||
targetFieldSchema,
|
||||
});
|
||||
const { apiTokenSettings } = useAPITokenVariable({ noDisabled });
|
||||
const { datetimeSettings } = useDatetimeVariable({ operator, schema: uiSchema, noDisabled });
|
||||
const { datetimeSettings } = useDatetimeVariable({ operator, schema: uiSchema, noDisabled, targetFieldSchema });
|
||||
const { currentFormSettings, shouldDisplayCurrentForm } = useCurrentFormVariable({
|
||||
schema: uiSchema,
|
||||
collectionField,
|
||||
|
Loading…
Reference in New Issue
Block a user