Merge branch 'main' into next

This commit is contained in:
Zeke Zhang 2024-08-02 14:29:01 +08:00
commit 08f25c2336
5 changed files with 245 additions and 66 deletions

View File

@ -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 }));
});
});

View File

@ -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')],

View File

@ -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,

View File

@ -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,

View File

@ -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,