mirror of
https://github.com/nocobase/nocobase
synced 2024-11-14 16:34:14 +00:00
Revert "feat: date type fields support setting the picker type (#5271)"
This reverts commit dcaad79370
.
This commit is contained in:
parent
6dee46440a
commit
c91c43a71b
@ -31,12 +31,26 @@ export class DateFieldInterface extends CollectionFieldInterface {
|
||||
hasDefaultValue = true;
|
||||
properties = {
|
||||
...defaultProps,
|
||||
...dateTimeProps,
|
||||
'uiSchema.x-component-props.showTime': {
|
||||
type: 'boolean',
|
||||
'uiSchema.x-component-props.dateFormat': {
|
||||
type: 'string',
|
||||
title: '{{t("Date format")}}',
|
||||
'x-component': 'Radio.Group',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Checkbox',
|
||||
'x-visible': false,
|
||||
default: 'YYYY-MM-DD',
|
||||
enum: [
|
||||
{
|
||||
label: '{{t("Year/Month/Day")}}',
|
||||
value: 'YYYY/MM/DD',
|
||||
},
|
||||
{
|
||||
label: '{{t("Year-Month-Day")}}',
|
||||
value: 'YYYY-MM-DD',
|
||||
},
|
||||
{
|
||||
label: '{{t("Day/Month/Year")}}',
|
||||
value: 'DD/MM/YYYY',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
filterable = {
|
||||
|
@ -10,8 +10,6 @@
|
||||
import { Field } from '@formily/core';
|
||||
import { ISchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { css } from '@emotion/css';
|
||||
import { DateFormatCom } from '../../../schema-component/antd/expiresRadio';
|
||||
export * as operators from './operators';
|
||||
|
||||
export const type: ISchema = {
|
||||
@ -227,88 +225,26 @@ export const reverseFieldProperties: Record<string, ISchema> = {
|
||||
};
|
||||
|
||||
export const dateTimeProps: { [key: string]: ISchema } = {
|
||||
'uiSchema.x-component-props.picker': {
|
||||
type: 'string',
|
||||
title: '{{t("Picker")}}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Radio.Group',
|
||||
default: 'date',
|
||||
enum: [
|
||||
{
|
||||
label: '{{t("Date")}}',
|
||||
value: 'date',
|
||||
},
|
||||
// {
|
||||
// label: '{{t("Week")}}',
|
||||
// value: 'week',
|
||||
// },
|
||||
{
|
||||
label: '{{t("Month")}}',
|
||||
value: 'month',
|
||||
},
|
||||
{
|
||||
label: '{{t("Quarter")}}',
|
||||
value: 'quarter',
|
||||
},
|
||||
{
|
||||
label: '{{t("Year")}}',
|
||||
value: 'year',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
'uiSchema.x-component-props.dateFormat': {
|
||||
type: 'string',
|
||||
title: '{{t("Date format")}}',
|
||||
'x-component': 'Radio.Group',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'ExpiresRadio',
|
||||
'x-decorator-props': {},
|
||||
'x-component-props': {
|
||||
className: css`
|
||||
.ant-radio-wrapper {
|
||||
display: flex;
|
||||
margin: 5px 0px;
|
||||
}
|
||||
`,
|
||||
defaultValue: 'dddd',
|
||||
formats: ['MMMM Do YYYY', 'YYYY-MM-DD', 'MM/DD/YY', 'YYYY/MM/DD', 'DD/MM/YYYY'],
|
||||
},
|
||||
default: 'YYYY-MM-DD',
|
||||
enum: [
|
||||
{
|
||||
label: DateFormatCom({ format: 'MMMM Do YYYY' }),
|
||||
value: 'MMMM Do YYYY',
|
||||
},
|
||||
{
|
||||
label: DateFormatCom({ format: 'YYYY-MM-DD' }),
|
||||
value: 'YYYY-MM-DD',
|
||||
},
|
||||
{
|
||||
label: DateFormatCom({ format: 'MM/DD/YY' }),
|
||||
value: 'MM/DD/YY',
|
||||
},
|
||||
{
|
||||
label: DateFormatCom({ format: 'YYYY/MM/DD' }),
|
||||
label: '{{t("Year/Month/Day")}}',
|
||||
value: 'YYYY/MM/DD',
|
||||
},
|
||||
{
|
||||
label: DateFormatCom({ format: 'DD/MM/YYYY' }),
|
||||
value: 'DD/MM/YYYY',
|
||||
label: '{{t("Year-Month-Day")}}',
|
||||
value: 'YYYY-MM-DD',
|
||||
},
|
||||
{
|
||||
label: 'custom',
|
||||
value: 'custom',
|
||||
label: '{{t("Day/Month/Year")}}',
|
||||
value: 'DD/MM/YYYY',
|
||||
},
|
||||
],
|
||||
'x-reactions': {
|
||||
dependencies: ['uiSchema.x-component-props.picker'],
|
||||
fulfill: {
|
||||
state: {
|
||||
value: `{{ getPickerFormat($deps[0])}}`,
|
||||
componentProps: { picker: `{{$deps[0]}}` },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'uiSchema.x-component-props.showTime': {
|
||||
type: 'boolean',
|
||||
@ -322,21 +258,6 @@ export const dateTimeProps: { [key: string]: ISchema } = {
|
||||
f.value='HH:mm:ss'
|
||||
});
|
||||
}}}`,
|
||||
{
|
||||
dependencies: ['uiSchema.x-component-props.picker'],
|
||||
when: '{{$deps[0]==="date"}}',
|
||||
fulfill: {
|
||||
state: {
|
||||
hidden: false,
|
||||
},
|
||||
},
|
||||
otherwise: {
|
||||
state: {
|
||||
hidden: true,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
'uiSchema.x-component-props.timeFormat': {
|
||||
@ -355,14 +276,6 @@ export const dateTimeProps: { [key: string]: ISchema } = {
|
||||
value: 'HH:mm:ss',
|
||||
},
|
||||
],
|
||||
'x-reactions': {
|
||||
dependencies: ['uiSchema.x-component-props.showTime'],
|
||||
fulfill: {
|
||||
state: {
|
||||
hidden: `{{ !$deps[0] }}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -60,48 +60,13 @@ export const object = [
|
||||
];
|
||||
|
||||
export const datetime = [
|
||||
{
|
||||
label: "{{ t('is') }}",
|
||||
value: '$dateOn',
|
||||
selected: true,
|
||||
schema: { 'x-component': 'DatePicker.FilterWithPicker' },
|
||||
onlyFilterAction: true, //schema 仅在Filter.Action生效,筛选表单中不生效
|
||||
},
|
||||
{
|
||||
label: "{{ t('is not') }}",
|
||||
value: '$dateNotOn',
|
||||
schema: { 'x-component': 'DatePicker.FilterWithPicker' },
|
||||
onlyFilterAction: true,
|
||||
},
|
||||
{
|
||||
label: "{{ t('is before') }}",
|
||||
value: '$dateBefore',
|
||||
schema: { 'x-component': 'DatePicker.FilterWithPicker' },
|
||||
onlyFilterAction: true,
|
||||
},
|
||||
{
|
||||
label: "{{ t('is after') }}",
|
||||
value: '$dateAfter',
|
||||
schema: { 'x-component': 'DatePicker.FilterWithPicker' },
|
||||
onlyFilterAction: true,
|
||||
},
|
||||
{
|
||||
label: "{{ t('is on or after') }}",
|
||||
value: '$dateNotBefore',
|
||||
schema: { 'x-component': 'DatePicker.FilterWithPicker' },
|
||||
onlyFilterAction: true,
|
||||
},
|
||||
{
|
||||
label: "{{ t('is on or before') }}",
|
||||
value: '$dateNotAfter',
|
||||
schema: { 'x-component': 'DatePicker.FilterWithPicker' },
|
||||
onlyFilterAction: true,
|
||||
},
|
||||
{
|
||||
label: "{{ t('is between') }}",
|
||||
value: '$dateBetween',
|
||||
schema: { 'x-component': 'DatePicker.RangePicker' },
|
||||
},
|
||||
{ label: "{{ t('is') }}", value: '$dateOn', selected: true },
|
||||
{ label: "{{ t('is not') }}", value: '$dateNotOn' },
|
||||
{ label: "{{ t('is before') }}", value: '$dateBefore' },
|
||||
{ label: "{{ t('is after') }}", value: '$dateAfter' },
|
||||
{ label: "{{ t('is on or after') }}", value: '$dateNotBefore' },
|
||||
{ label: "{{ t('is on or before') }}", value: '$dateNotAfter' },
|
||||
{ label: "{{ t('is between') }}", value: '$dateBetween', schema: { 'x-component': 'DatePicker.RangePicker' } },
|
||||
{ label: "{{ t('is empty') }}", value: '$empty', noValue: true },
|
||||
{ label: "{{ t('is not empty') }}", value: '$notEmpty', noValue: true },
|
||||
];
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import { CollectionFieldInterface } from '../../data-source/collection-field-interface/CollectionFieldInterface';
|
||||
import { defaultProps, operators, dateTimeProps } from './properties';
|
||||
import { defaultProps, operators } from './properties';
|
||||
export class UnixTimestampFieldInterface extends CollectionFieldInterface {
|
||||
name = 'unixTimestamp';
|
||||
type = 'object';
|
||||
@ -34,7 +34,6 @@ export class UnixTimestampFieldInterface extends CollectionFieldInterface {
|
||||
hasDefaultValue = false;
|
||||
properties = {
|
||||
...defaultProps,
|
||||
...dateTimeProps,
|
||||
accuracy: {
|
||||
type: 'string',
|
||||
title: '{{t("Accuracy")}}',
|
||||
|
@ -106,7 +106,6 @@ export abstract class CollectionFieldInterface {
|
||||
'uiSchema.x-component-props.showTime',
|
||||
'uiSchema.x-component-props.dateFormat',
|
||||
'uiSchema.x-component-props.timeFormat',
|
||||
'uiSchema.x-component-props.picker',
|
||||
],
|
||||
fulfill: {
|
||||
state: {
|
||||
@ -115,20 +114,10 @@ export abstract class CollectionFieldInterface {
|
||||
showTime: '{{$deps[1]}}',
|
||||
dateFormat: '{{$deps[2]}}',
|
||||
timeFormat: '{{$deps[3]}}',
|
||||
picker: '{{$deps[4]}}',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// 当 picker 改变时,清空 defaultValue
|
||||
dependencies: ['uiSchema.x-component-props.picker'],
|
||||
fulfill: {
|
||||
state: {
|
||||
value: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
dependencies: ['primaryKey', 'unique', 'autoIncrement', 'defaultToCurrentTime'],
|
||||
when: '{{$deps[0]||$deps[1]||$deps[2]||$deps[3]}}',
|
||||
|
@ -997,8 +997,5 @@
|
||||
"Are you sure you want to perform the Submit action?": "你确定执行提交操作吗?",
|
||||
"Perform the Trigger workflow": "执行触发工作流",
|
||||
"Are you sure you want to perform the Trigger workflow action?": "你确定执行触发工作流吗?",
|
||||
"Ellipsis overflow content": "省略超出长度的内容",
|
||||
"Picker": "选择器",
|
||||
"Quarter":"季度",
|
||||
"Switching the picker, the value and default value will be cleared":"切换选择器时,字段的值和默认值将会被清空"
|
||||
"Ellipsis overflow content": "省略超出长度的内容"
|
||||
}
|
||||
|
@ -29,21 +29,3 @@ export const datePickerComponentFieldSettings = new SchemaSettings({
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const rangePickerPickerComponentFieldSettings = new SchemaSettings({
|
||||
name: 'fieldSettings:component:DatePicker.RangePicker',
|
||||
items: [
|
||||
{
|
||||
name: 'dateDisplayFormat',
|
||||
Component: SchemaSettingsDateFormat as any,
|
||||
useComponentProps() {
|
||||
const schema = useFieldSchema();
|
||||
const { fieldSchema: tableColumnSchema } = useColumnSchema();
|
||||
const fieldSchema = tableColumnSchema || schema;
|
||||
return {
|
||||
fieldSchema,
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -7,17 +7,14 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react';
|
||||
import { DatePicker as AntdDatePicker, DatePickerProps as AntdDatePickerProps, Space, Select } from 'antd';
|
||||
import { connect, mapProps, mapReadPretty } from '@formily/react';
|
||||
import { DatePicker as AntdDatePicker, DatePickerProps as AntdDatePickerProps } from 'antd';
|
||||
import { RangePickerProps } from 'antd/es/date-picker';
|
||||
import dayjs from 'dayjs';
|
||||
import React, { useState, useContext } from 'react';
|
||||
import { getPickerFormat } from '@nocobase/utils/client';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ReadPretty, ReadPrettyComposed } from './ReadPretty';
|
||||
import { getDateRanges, mapDatePicker, mapRangePicker, inferPickerType } from './util';
|
||||
import { FilterContext } from '../../antd/filter';
|
||||
import { useCompile } from '../../';
|
||||
import { getDateRanges, mapDatePicker, mapRangePicker } from './util';
|
||||
|
||||
interface IDatePickerProps {
|
||||
utc?: boolean;
|
||||
@ -26,7 +23,6 @@ interface IDatePickerProps {
|
||||
type ComposedDatePicker = React.FC<AntdDatePickerProps> & {
|
||||
ReadPretty?: ReadPrettyComposed['DatePicker'];
|
||||
RangePicker?: ComposedRangePicker;
|
||||
FilterWithPicker?: any;
|
||||
};
|
||||
|
||||
type ComposedRangePicker = React.FC<RangePickerProps> & {
|
||||
@ -64,14 +60,9 @@ export const DatePicker: ComposedDatePicker = (props: any) => {
|
||||
DatePicker.ReadPretty = ReadPretty.DatePicker;
|
||||
|
||||
DatePicker.RangePicker = function RangePicker(props: any) {
|
||||
const { value, picker = 'date', format } = props;
|
||||
const { t } = useTranslation();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field: any = useField();
|
||||
const { utc = true } = useDatePickerContext();
|
||||
const rangesValue = getDateRanges();
|
||||
const compile = useCompile();
|
||||
const ctx: any = useContext(FilterContext); // 在筛选按钮中使用
|
||||
const presets = [
|
||||
{ label: t('Today'), value: rangesValue.today },
|
||||
{ label: t('Last week'), value: rangesValue.lastWeek },
|
||||
@ -93,138 +84,13 @@ DatePicker.RangePicker = function RangePicker(props: any) {
|
||||
{ label: t('Last 90 days'), value: rangesValue.last90Days },
|
||||
{ label: t('Next 90 days'), value: rangesValue.next90Days },
|
||||
];
|
||||
|
||||
const targetPicker = value ? inferPickerType(value?.[0]) : picker;
|
||||
const targetFormat = getPickerFormat(targetPicker) || format;
|
||||
const newProps: any = {
|
||||
utc,
|
||||
presets,
|
||||
...props,
|
||||
format: targetFormat,
|
||||
picker: targetPicker,
|
||||
showTime: props.showTime ? { defaultValue: [dayjs('00:00:00', 'HH:mm:ss'), dayjs('00:00:00', 'HH:mm:ss')] } : false,
|
||||
};
|
||||
const [stateProps, setStateProps] = useState(newProps);
|
||||
|
||||
if (ctx) {
|
||||
return (
|
||||
<Space.Compact>
|
||||
<Select
|
||||
// @ts-ignore
|
||||
role="button"
|
||||
data-testid="select-picker"
|
||||
style={{ width: '100px' }}
|
||||
popupMatchSelectWidth={false}
|
||||
defaultValue={targetPicker}
|
||||
options={compile([
|
||||
{
|
||||
label: '{{t("Date")}}',
|
||||
value: 'date',
|
||||
},
|
||||
|
||||
{
|
||||
label: '{{t("Month")}}',
|
||||
value: 'month',
|
||||
},
|
||||
{
|
||||
label: '{{t("Quarter")}}',
|
||||
value: 'quarter',
|
||||
},
|
||||
{
|
||||
label: '{{t("Year")}}',
|
||||
value: 'year',
|
||||
},
|
||||
])}
|
||||
onChange={(value) => {
|
||||
const format = getPickerFormat(value);
|
||||
field.setComponentProps({
|
||||
picker: value,
|
||||
format,
|
||||
});
|
||||
newProps.picker = value;
|
||||
newProps.format = format;
|
||||
setStateProps(newProps);
|
||||
fieldSchema['x-component-props'] = {
|
||||
...props,
|
||||
picker: value,
|
||||
format,
|
||||
};
|
||||
field.value = undefined;
|
||||
}}
|
||||
/>
|
||||
<InternalRangePicker {...stateProps} value={value} />
|
||||
</Space.Compact>
|
||||
);
|
||||
}
|
||||
return <InternalRangePicker {...newProps} />;
|
||||
};
|
||||
|
||||
DatePicker.FilterWithPicker = function FilterWithPicker(props: any) {
|
||||
const { picker = 'date', format } = props;
|
||||
const { utc = true } = useDatePickerContext();
|
||||
const value = Array.isArray(props.value) ? props.value[0] : props.value;
|
||||
const compile = useCompile();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const targetPicker = value ? inferPickerType(value) : picker;
|
||||
const targetFormat = getPickerFormat(targetPicker) || format;
|
||||
const newProps = {
|
||||
utc,
|
||||
...props,
|
||||
underFilter: true,
|
||||
showTime: props.showTime ? { defaultValue: dayjs('00:00:00', 'HH:mm:ss') } : false,
|
||||
format: targetFormat,
|
||||
picker: targetPicker,
|
||||
};
|
||||
const field: any = useField();
|
||||
const [stateProps, setStateProps] = useState(newProps);
|
||||
return (
|
||||
<Space.Compact>
|
||||
<Select
|
||||
// @ts-ignore
|
||||
role="button"
|
||||
data-testid="select-picker"
|
||||
style={{ width: '100px' }}
|
||||
popupMatchSelectWidth={false}
|
||||
defaultValue={targetPicker}
|
||||
options={compile([
|
||||
{
|
||||
label: '{{t("Date")}}',
|
||||
value: 'date',
|
||||
},
|
||||
|
||||
{
|
||||
label: '{{t("Month")}}',
|
||||
value: 'month',
|
||||
},
|
||||
{
|
||||
label: '{{t("Quarter")}}',
|
||||
value: 'quarter',
|
||||
},
|
||||
{
|
||||
label: '{{t("Year")}}',
|
||||
value: 'year',
|
||||
},
|
||||
])}
|
||||
onChange={(value) => {
|
||||
const format = getPickerFormat(value);
|
||||
field.setComponentProps({
|
||||
picker: value,
|
||||
format,
|
||||
});
|
||||
newProps.picker = value;
|
||||
newProps.format = format;
|
||||
setStateProps(newProps);
|
||||
fieldSchema['x-component-props'] = {
|
||||
...props,
|
||||
picker: value,
|
||||
format,
|
||||
};
|
||||
field.value = null;
|
||||
}}
|
||||
/>
|
||||
<InternalDatePicker {...stateProps} value={value} />
|
||||
</Space.Compact>
|
||||
);
|
||||
};
|
||||
|
||||
export default DatePicker;
|
||||
|
@ -34,15 +34,16 @@ export interface ReadPrettyDatePickerProps extends Str2momentOptions, GetDefault
|
||||
showTime?: boolean;
|
||||
}
|
||||
|
||||
ReadPretty.DatePicker = function DatePicker(props: any) {
|
||||
const { value, picker = 'date' } = props;
|
||||
ReadPretty.DatePicker = function DatePicker(props) {
|
||||
const prefixCls = usePrefixCls('description-date-picker', props);
|
||||
if (!value) {
|
||||
|
||||
if (!props.value) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
const getLabels = () => {
|
||||
const format = getDefaultFormat(props) as string;
|
||||
const m = str2moment(value, props);
|
||||
const m = str2moment(props.value, props);
|
||||
const labels = dayjs.isDayjs(m) ? m.format(format) : '';
|
||||
return isArr(labels) ? labels.join('~') : labels;
|
||||
};
|
||||
|
@ -232,6 +232,9 @@ describe('RangePicker', () => {
|
||||
expect(
|
||||
screen.getByText(currentDateString.replace(/-/g, '/'), { selector: '.ant-description-date-picker' }),
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Value
|
||||
expect(screen.getByText(`${currentDateString}T00:00:00.000Z`)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -62,7 +62,7 @@ describe('mapDatePicker', () => {
|
||||
};
|
||||
const result = mapDatePicker()(props);
|
||||
result.onChange(dayjs.utc('2022-02-22 22:22:22'));
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-22 00:00:00');
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-22T22:22:22.000Z');
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when showTime is true and gmt is false', () => {
|
||||
@ -74,7 +74,7 @@ describe('mapDatePicker', () => {
|
||||
const result = mapDatePicker()(props);
|
||||
const m = dayjs('2022-02-22 22:22:22');
|
||||
result.onChange(m);
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-22 00:00:00');
|
||||
expect(props.onChange).toHaveBeenCalledWith(m.toISOString());
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when showTime is false and gmt is true', () => {
|
||||
@ -85,7 +85,7 @@ describe('mapDatePicker', () => {
|
||||
};
|
||||
const result = mapDatePicker()(props);
|
||||
result.onChange(dayjs.utc('2022-02-22'));
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-22');
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-22T00:00:00.000Z');
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when showTime is false and gmt is false', () => {
|
||||
@ -97,7 +97,7 @@ describe('mapDatePicker', () => {
|
||||
const result = mapDatePicker()(props);
|
||||
const m = dayjs('2022-02-22');
|
||||
result.onChange(m);
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-22');
|
||||
expect(props.onChange).toHaveBeenCalledWith(m.toISOString());
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when picker is year and gmt is true', () => {
|
||||
@ -108,7 +108,7 @@ describe('mapDatePicker', () => {
|
||||
};
|
||||
const result = mapDatePicker()(props);
|
||||
result.onChange(dayjs.utc('2022-01-01T00:00:00.000Z'));
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-01-01');
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-01-01T00:00:00.000Z');
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when picker is year and gmt is false', () => {
|
||||
@ -120,7 +120,7 @@ describe('mapDatePicker', () => {
|
||||
const result = mapDatePicker()(props);
|
||||
const m = dayjs('2022-02-01 00:00:00');
|
||||
result.onChange(m);
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-01-01');
|
||||
expect(props.onChange).toHaveBeenCalledWith(m.startOf('year').toISOString());
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when picker is month and gmt is true', () => {
|
||||
@ -131,7 +131,7 @@ describe('mapDatePicker', () => {
|
||||
};
|
||||
const result = mapDatePicker()(props);
|
||||
result.onChange(dayjs.utc('2022-02-22T00:00:00.000Z'));
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-01');
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-01T00:00:00.000Z');
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when picker is month and gmt is false', () => {
|
||||
@ -143,7 +143,7 @@ describe('mapDatePicker', () => {
|
||||
const result = mapDatePicker()(props);
|
||||
const m = dayjs('2022-02-01 00:00:00');
|
||||
result.onChange(m);
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-01');
|
||||
expect(props.onChange).toHaveBeenCalledWith(m.startOf('month').toISOString());
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when picker is quarter and gmt is true', () => {
|
||||
@ -154,7 +154,7 @@ describe('mapDatePicker', () => {
|
||||
};
|
||||
const result = mapDatePicker()(props);
|
||||
result.onChange(dayjs.utc('2022-02-22T00:00:00.000Z'));
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-01-01');
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-01-01T00:00:00.000Z');
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when picker is quarter and gmt is false', () => {
|
||||
@ -166,7 +166,7 @@ describe('mapDatePicker', () => {
|
||||
const result = mapDatePicker()(props);
|
||||
const m = dayjs('2022-02-01 00:00:00');
|
||||
result.onChange(m);
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-01-01');
|
||||
expect(props.onChange).toHaveBeenCalledWith(m.startOf('quarter').toISOString());
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when picker is week and gmt is true', () => {
|
||||
@ -178,7 +178,7 @@ describe('mapDatePicker', () => {
|
||||
const result = mapDatePicker()(props);
|
||||
const m = dayjs.utc('2022-02-21T00:00:00.000Z');
|
||||
result.onChange(m);
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-20');
|
||||
expect(props.onChange).toHaveBeenCalledWith(m.startOf('week').add(1, 'day').toISOString());
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when picker is week and gmt is false', () => {
|
||||
@ -190,7 +190,7 @@ describe('mapDatePicker', () => {
|
||||
const result = mapDatePicker()(props);
|
||||
const m = dayjs('2022-02-21 00:00:00');
|
||||
result.onChange(m);
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-20');
|
||||
expect(props.onChange).toHaveBeenCalledWith(m.startOf('week').add(1, 'day').toISOString());
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when utc is false', () => {
|
||||
@ -202,7 +202,7 @@ describe('mapDatePicker', () => {
|
||||
};
|
||||
const result = mapDatePicker()(props);
|
||||
result.onChange(dayjs('2022-02-22 22:22:22'));
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-22 00:00:00');
|
||||
expect(props.onChange).toHaveBeenCalledWith('2022-02-22 22:22:22');
|
||||
});
|
||||
|
||||
it('should call onChange with correct value when picker is year and utc is false', () => {
|
||||
|
@ -29,7 +29,7 @@ describe('str2moment', () => {
|
||||
});
|
||||
|
||||
test('picker is month', async () => {
|
||||
const m = str2moment('2022-06-01T00:00:00.000Z', { picker: 'month', gmt: true });
|
||||
const m = str2moment('2022-06-01T00:00:00.000Z', { picker: 'month' });
|
||||
expect(m.format('YYYY-MM-DD HH:mm:ss')).toBe('2022-06-01 00:00:00');
|
||||
});
|
||||
});
|
||||
@ -130,10 +130,10 @@ describe('moment2str', () => {
|
||||
expect(str).toBe('2023-06-01T00:00:00.000Z');
|
||||
});
|
||||
|
||||
test('picker is month gmt is false', () => {
|
||||
test('picker is month', () => {
|
||||
const m = dayjs('2023-06-21 10:10:00');
|
||||
const str = moment2str(m, { picker: 'month', gmt: false });
|
||||
expect(str).toBe(dayjs('2023-06-01 00:00:00').toISOString());
|
||||
const str = moment2str(m, { picker: 'month', gmt: true });
|
||||
expect(str).toBe('2023-06-01T00:00:00.000Z');
|
||||
});
|
||||
|
||||
test('picker is week, gmt is false', () => {
|
||||
|
@ -7,11 +7,11 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { getDefaultFormat, str2moment, toGmt, toLocal, getPickerFormat } from '@nocobase/utils/client';
|
||||
import { getDefaultFormat, str2moment, toGmt, toLocal } from '@nocobase/utils/client';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const toStringByPicker = (value, picker = 'date', timezone: 'gmt' | 'local') => {
|
||||
const toStringByPicker = (value, picker, timezone: 'gmt' | 'local') => {
|
||||
if (!dayjs.isDayjs(value)) return value;
|
||||
if (timezone === 'local') {
|
||||
const offset = new Date().getTimezoneOffset();
|
||||
@ -57,7 +57,7 @@ export interface Moment2strOptions {
|
||||
}
|
||||
|
||||
export const moment2str = (value?: Dayjs | null, options: Moment2strOptions = {}) => {
|
||||
const { showTime, gmt, picker = 'date', utc = true } = options;
|
||||
const { showTime, gmt, picker, utc = true } = options;
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
@ -74,39 +74,9 @@ export const moment2str = (value?: Dayjs | null, options: Moment2strOptions = {}
|
||||
return toLocalByPicker(value, picker);
|
||||
};
|
||||
|
||||
const handleChangeOnFilter = (value, picker, showTime) => {
|
||||
const format = showTime ? 'YYYY-MM-DD HH:mm:ss' : getPickerFormat(picker);
|
||||
if (value) {
|
||||
return value.format(format);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const handleChangeOnForm = (value, dateOnly, utc, picker, showTime, gmt) => {
|
||||
const format = showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD';
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
if (dateOnly) {
|
||||
return dayjs(value).startOf(picker).format('YYYY-MM-DD');
|
||||
}
|
||||
if (utc) {
|
||||
if (gmt) {
|
||||
return toGmt(value);
|
||||
}
|
||||
if (picker !== 'date') {
|
||||
return dayjs(value).startOf(picker).toISOString();
|
||||
}
|
||||
const formattedDate = dayjs(value).format(format);
|
||||
return dayjs(formattedDate).toISOString();
|
||||
}
|
||||
return dayjs(value).startOf(picker).format(format);
|
||||
};
|
||||
|
||||
export const mapDatePicker = function () {
|
||||
return (props: any) => {
|
||||
const { dateOnly, showTime, picker = 'date', utc, gmt, underFilter } = props;
|
||||
const format = getDefaultFormat(props);
|
||||
const format = getDefaultFormat(props) as any;
|
||||
const onChange = props.onChange;
|
||||
return {
|
||||
...props,
|
||||
@ -114,10 +84,13 @@ export const mapDatePicker = function () {
|
||||
value: str2moment(props.value, props),
|
||||
onChange: (value: Dayjs | null, dateString) => {
|
||||
if (onChange) {
|
||||
if (underFilter) {
|
||||
onChange(handleChangeOnFilter(value, picker, showTime));
|
||||
if (!props.showTime && value) {
|
||||
value = value.startOf('day');
|
||||
}
|
||||
if (props.dateOnly) {
|
||||
onChange(dateString !== '' ? dateString : undefined);
|
||||
} else {
|
||||
onChange(handleChangeOnForm(value, dateOnly, utc, picker, showTime, gmt));
|
||||
onChange(moment2str(value, props));
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -129,26 +102,18 @@ export const mapRangePicker = function () {
|
||||
return (props: any) => {
|
||||
const format = getDefaultFormat(props) as any;
|
||||
const onChange = props.onChange;
|
||||
const { dateOnly, showTime, picker = 'date', utc, gmt, underFilter } = props;
|
||||
|
||||
return {
|
||||
...props,
|
||||
format: format,
|
||||
value: str2moment(props.value, props),
|
||||
onChange: (value: Dayjs[]) => {
|
||||
if (onChange) {
|
||||
if (underFilter) {
|
||||
onChange(
|
||||
value
|
||||
? [handleChangeOnFilter(value[0], picker, showTime), handleChangeOnFilter(value[1], picker, showTime)]
|
||||
: [],
|
||||
);
|
||||
} else {
|
||||
onChange(
|
||||
value
|
||||
? [moment2str(getRangeStart(value[0], props), props), moment2str(getRangeEnd(value[1], props), props)]
|
||||
: [],
|
||||
);
|
||||
}
|
||||
onChange(
|
||||
value
|
||||
? [moment2str(getRangeStart(value[0], props), props), moment2str(getRangeEnd(value[1], props), props)]
|
||||
: [],
|
||||
);
|
||||
}
|
||||
},
|
||||
} as any;
|
||||
@ -261,17 +226,3 @@ function withParams(value: any[], params: { fieldOperator?: string }) {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export function inferPickerType(dateString: string): 'year' | 'month' | 'quarter' | 'date' {
|
||||
if (/^\d{4}$/.test(dateString)) {
|
||||
return 'year';
|
||||
} else if (/^\d{4}-\d{2}$/.test(dateString)) {
|
||||
return 'month';
|
||||
} else if (/^\d{4}Q[1-4]$/.test(dateString)) {
|
||||
return 'quarter';
|
||||
} else if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
|
||||
return 'date';
|
||||
} else {
|
||||
return 'date';
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,6 @@ export const DynamicComponent = (props: Props) => {
|
||||
...props.style,
|
||||
},
|
||||
utc: false,
|
||||
underFilter: true,
|
||||
}),
|
||||
name: 'value',
|
||||
'x-read-pretty': false,
|
||||
|
@ -496,6 +496,7 @@ export const EditOperator = () => {
|
||||
const { dn } = useDesignable();
|
||||
const operatorList = useOperatorList();
|
||||
const { getOperator, collectOperator } = useOperators();
|
||||
|
||||
if (operatorList.length && !getOperator(fieldSchema.name)) {
|
||||
collectOperator(fieldSchema.name, operatorList[0].value);
|
||||
}
|
||||
@ -511,22 +512,22 @@ export const EditOperator = () => {
|
||||
_.set(fieldSchema, 'x-filter-operator', v);
|
||||
|
||||
const operator = operatorList.find((item) => item.value === v);
|
||||
let componentProps = { ...fieldSchema['x-component-props'] };
|
||||
field.value = undefined; //切换操作符清空字段值
|
||||
let componentProps = {};
|
||||
|
||||
// 根据操作符的配置,设置组件的属性
|
||||
if (operator?.schema?.['x-component'] && !operator?.onlyFilterAction) {
|
||||
if (operator?.schema?.['x-component']) {
|
||||
_.set(fieldSchema, 'x-component-props.component', operator.schema?.['x-component']);
|
||||
_.set(field, 'componentProps.component', operator.schema?.['x-component']);
|
||||
field.reset();
|
||||
componentProps = {
|
||||
...fieldSchema['x-component-props'],
|
||||
component: operator.schema['x-component'],
|
||||
...operator.schema?.['x-component-props'],
|
||||
};
|
||||
} else if (fieldSchema['x-component-props']?.component) {
|
||||
_.set(fieldSchema, 'x-component-props.component', null);
|
||||
_.set(field, 'componentProps.component', null);
|
||||
field.reset();
|
||||
componentProps = {
|
||||
...fieldSchema['x-component-props'],
|
||||
component: null,
|
||||
...operator.schema?.['x-component-props'],
|
||||
};
|
||||
|
@ -62,6 +62,5 @@ export * from './variable';
|
||||
export * from './unix-timestamp';
|
||||
export * from './nanoid-input';
|
||||
export * from './error-fallback';
|
||||
export * from './expiresRadio';
|
||||
|
||||
import './index.less';
|
||||
|
@ -11,12 +11,11 @@ import { connect, mapProps, mapReadPretty } from '@formily/react';
|
||||
import React from 'react';
|
||||
import ReactQuill from 'react-quill';
|
||||
import { isVariable } from '../../../variables/utils/isVariable';
|
||||
import { ReadPretty as InputReadPretty, Input } from '../input';
|
||||
import { ReadPretty as InputReadPretty } from '../input';
|
||||
import { useStyles } from './style';
|
||||
|
||||
export const RichText = connect(
|
||||
(props) => {
|
||||
const { underFilter } = props;
|
||||
const { wrapSSR, hashId, componentCls } = useStyles();
|
||||
const modules = {
|
||||
toolbar: [['bold', 'italic', 'underline', 'link'], [{ list: 'ordered' }, { list: 'bullet' }], ['clean']],
|
||||
@ -36,9 +35,7 @@ export const RichText = connect(
|
||||
];
|
||||
const { value, defaultValue, onChange, disabled } = props;
|
||||
const resultValue = isVariable(value || defaultValue) ? undefined : value || defaultValue || '';
|
||||
if (underFilter) {
|
||||
return <Input {...props} />;
|
||||
}
|
||||
|
||||
return wrapSSR(
|
||||
<ReactQuill
|
||||
className={`${componentCls} ${hashId}`}
|
||||
|
@ -19,6 +19,7 @@ interface UnixTimestampProps {
|
||||
export const UnixTimestamp = connect(
|
||||
(props: UnixTimestampProps) => {
|
||||
const { value, onChange } = props;
|
||||
|
||||
return (
|
||||
<DatePicker
|
||||
{...props}
|
||||
|
@ -160,75 +160,58 @@ export function getJsonLogic() {
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
return a === b;
|
||||
if (!Array.isArray(a)) {
|
||||
a = [a, a];
|
||||
}
|
||||
if (!Array.isArray(b)) {
|
||||
b = [b, b];
|
||||
}
|
||||
a = a.map((date) => dayjs(date));
|
||||
b = b.map((date) => dayjs(date));
|
||||
|
||||
return a[0].isBetween(b[0], b[1], null, '[]') && a[1].isBetween(b[0], b[1], null, '[]');
|
||||
},
|
||||
$dateBefore: function (a, b) {
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
// Parse both date strings
|
||||
const dateA = parseDate(a);
|
||||
const dateB = parseDate(b);
|
||||
|
||||
if (!dateA || !dateB) {
|
||||
throw new Error('Invalid date format');
|
||||
if (!Array.isArray(a)) {
|
||||
a = [a, a];
|
||||
}
|
||||
return dateA < dateB;
|
||||
if (!Array.isArray(b)) {
|
||||
b = [b, b];
|
||||
}
|
||||
a = a.map((date) => dayjs(date));
|
||||
b = b.map((date) => dayjs(date));
|
||||
|
||||
return a[0].isBefore(b[0]) && a[1].isBefore(b[0]);
|
||||
},
|
||||
$dateNotBefore: function (a, b) {
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
const dateA = parseDate(a);
|
||||
const dateB = parseDate(b);
|
||||
|
||||
if (!dateA || !dateB) {
|
||||
throw new Error('Invalid date format');
|
||||
}
|
||||
|
||||
// Compare the two dates
|
||||
return dateA >= dateB;
|
||||
return !operations.$dateBefore(a, b);
|
||||
},
|
||||
$dateAfter: function (a, b) {
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
// Parse both date strings
|
||||
const dateA = parseDate(a);
|
||||
const dateB = parseDate(b);
|
||||
if (!Array.isArray(a)) {
|
||||
a = [a, a];
|
||||
}
|
||||
if (!Array.isArray(b)) {
|
||||
b = [b, b];
|
||||
}
|
||||
a = a.map((date) => dayjs(date));
|
||||
b = b.map((date) => dayjs(date));
|
||||
|
||||
return dateA > dateB;
|
||||
return a[0].isAfter(b[1]) && a[1].isAfter(b[1]);
|
||||
},
|
||||
$dateNotAfter: function (a, b) {
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
const dateA = parseDate(a);
|
||||
const dateB = parseDate(b);
|
||||
|
||||
if (!dateA || !dateB) {
|
||||
throw new Error('Invalid date format');
|
||||
}
|
||||
return dateA <= dateB;
|
||||
return !operations.$dateAfter(a, b);
|
||||
},
|
||||
$dateBetween: function (a, b) {
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
const dateA = parseFullDate(a);
|
||||
const dateBStart = parseFullDate(b[0]);
|
||||
const dateBEnd = parseFullDate(b[1]);
|
||||
|
||||
if (!dateA || !dateBStart || !dateBEnd) {
|
||||
throw new Error('Invalid date format');
|
||||
}
|
||||
return dateA >= dateBStart && dateA <= dateBEnd;
|
||||
return operations.$dateOn(a, b);
|
||||
},
|
||||
$dateNotOn: function (a, b) {
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
return a !== b;
|
||||
return !operations.$dateOn(a, b);
|
||||
},
|
||||
$isTruly: function (a) {
|
||||
if (Array.isArray(a)) return a.some((k) => k === true || k === 1);
|
||||
@ -632,43 +615,3 @@ export function getJsonLogic() {
|
||||
|
||||
return jsonLogic;
|
||||
}
|
||||
|
||||
function parseFullDate(dateStr) {
|
||||
return new Date(dateStr);
|
||||
}
|
||||
|
||||
function parseMonth(dateStr) {
|
||||
const [year, month] = dateStr.split('-').map(Number);
|
||||
return new Date(year, month - 1);
|
||||
}
|
||||
|
||||
function parseQuarter(dateStr) {
|
||||
const year = parseInt(dateStr.slice(0, 4));
|
||||
const quarter = parseInt(dateStr.slice(5, 6));
|
||||
const month = (quarter - 1) * 3;
|
||||
return new Date(year, month);
|
||||
}
|
||||
|
||||
function parseYear(dateStr) {
|
||||
const year = parseInt(dateStr);
|
||||
return new Date(year, 0);
|
||||
}
|
||||
|
||||
function parseDate(dateStr) {
|
||||
dateStr = dateStr.trim();
|
||||
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
|
||||
// It's in "YYYY-MM-DD" format
|
||||
return parseFullDate(dateStr);
|
||||
} else if (/^\d{4}-\d{2}$/.test(dateStr)) {
|
||||
// It's in "YYYY-MM" format
|
||||
return parseMonth(dateStr);
|
||||
} else if (/^\d{4}Q[1-4]$/.test(dateStr)) {
|
||||
// It's in "YYYYQn" format
|
||||
return parseQuarter(dateStr);
|
||||
} else if (/^\d{4}$/.test(dateStr)) {
|
||||
// It's in "YYYY" format
|
||||
return parseYear(dateStr);
|
||||
}
|
||||
return null; // Invalid format
|
||||
}
|
||||
|
@ -11,13 +11,11 @@ import Handlebars from 'handlebars';
|
||||
import { dayjs } from '@nocobase/utils/client';
|
||||
import helpers from '@budibase/handlebars-helpers';
|
||||
import _, { every, findIndex, some } from 'lodash';
|
||||
import { getPickerFormat } from '@nocobase/utils/client';
|
||||
import { replaceVariableValue } from '../../../block-provider/hooks';
|
||||
import { VariableOption, VariablesContextType } from '../../../variables/types';
|
||||
import { isVariable } from '../../../variables/utils/isVariable';
|
||||
import { transformVariableValue } from '../../../variables/utils/transformVariableValue';
|
||||
import { getJsonLogic } from '../../common/utils/logic';
|
||||
import { inferPickerType } from '../../antd/date-picker/util';
|
||||
import url from 'url';
|
||||
type VariablesCtx = {
|
||||
/** 当前登录的用户 */
|
||||
@ -126,19 +124,11 @@ export const conditionAnalyses = async ({
|
||||
const jsonLogic = getJsonLogic();
|
||||
const [value, targetValue] = await Promise.all(parsingResult);
|
||||
const targetCollectionField = await variables.getCollectionField(targetVariableName, localVariables);
|
||||
let currentInputValue = transformVariableValue(targetValue, { targetCollectionField });
|
||||
const comparisonValue = transformVariableValue(value, { targetCollectionField });
|
||||
if (
|
||||
['datetime', 'date', 'datetimeNoTz', 'dateOnly', 'unixTimestamp'].includes(targetCollectionField.type) &&
|
||||
currentInputValue
|
||||
) {
|
||||
const picker = inferPickerType(comparisonValue);
|
||||
const format = getPickerFormat(picker);
|
||||
currentInputValue = dayjs(currentInputValue).format(format);
|
||||
}
|
||||
|
||||
return jsonLogic.apply({
|
||||
[operator]: [currentInputValue, comparisonValue],
|
||||
[operator]: [
|
||||
transformVariableValue(targetValue, { targetCollectionField }),
|
||||
transformVariableValue(value, { targetCollectionField }),
|
||||
],
|
||||
});
|
||||
} catch (error) {
|
||||
throw error;
|
||||
|
@ -462,8 +462,8 @@ export const useFilterFormItemInitializerFields = (options?: any) => {
|
||||
'x-use-decorator-props': 'useFormItemProps',
|
||||
'x-collection-field': `${name}.${field.name}`,
|
||||
'x-component-props': {
|
||||
component: interfaceConfig?.filterable?.operators?.[0]?.schema?.['x-component'],
|
||||
utc: false,
|
||||
underFilter: true,
|
||||
},
|
||||
};
|
||||
if (isAssocField(field)) {
|
||||
@ -478,7 +478,7 @@ export const useFilterFormItemInitializerFields = (options?: any) => {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-use-decorator-props': 'useFormItemProps',
|
||||
'x-collection-field': `${name}.${field.name}`,
|
||||
'x-component-props': { ...field.uiSchema?.['x-component-props'], utc: false, underFilter: true },
|
||||
'x-component-props': field.uiSchema?.['x-component-props'],
|
||||
};
|
||||
}
|
||||
const resultItem = {
|
||||
@ -572,7 +572,7 @@ const associationFieldToMenu = (
|
||||
interface: field.interface,
|
||||
},
|
||||
'x-component': 'CollectionField',
|
||||
'x-component-props': { utc: false, underFilter: true },
|
||||
'x-component-props': { utc: false },
|
||||
'x-read-pretty': false,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-collection-field': `${collectionName}.${schemaName}`,
|
||||
@ -688,7 +688,7 @@ export const useFilterInheritsFormItemInitializerFields = (options?) => {
|
||||
'x-component': 'CollectionField',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-collection-field': `${name}.${field.name}`,
|
||||
'x-component-props': { utc: false, underFilter: true },
|
||||
'x-component-props': { utc: false },
|
||||
'x-read-pretty': field?.uiSchema?.['x-read-pretty'],
|
||||
};
|
||||
return {
|
||||
|
@ -9,11 +9,12 @@
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { connect, mapProps } from '@formily/react';
|
||||
import { useBoolean } from 'ahooks';
|
||||
import { Input, Radio, Space } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useToken } from '../../../';
|
||||
import React, { useState } from 'react';
|
||||
import { useToken } from '../../';
|
||||
|
||||
const date = dayjs();
|
||||
|
||||
@ -23,7 +24,7 @@ const spaceCSS = css`
|
||||
flex: 1;
|
||||
}
|
||||
`;
|
||||
const DateFormatCom = (props?) => {
|
||||
export const DateFormatCom = (props?) => {
|
||||
const date = dayjs();
|
||||
return (
|
||||
<div style={{ display: 'inline-flex' }}>
|
||||
@ -52,11 +53,9 @@ const DateTimeFormatPreview = ({ content }) => {
|
||||
};
|
||||
|
||||
const InternalExpiresRadio = (props) => {
|
||||
const { onChange, defaultValue, formats, picker } = props;
|
||||
const { onChange, defaultValue, formats, timeFormat } = props;
|
||||
const [isCustom, { setFalse, setTrue }] = useBoolean(props.value && !formats.includes(props.value));
|
||||
const [targetValue, setTargetValue] = useState(
|
||||
props.value && !formats.includes(props.value) ? props.value : defaultValue,
|
||||
);
|
||||
const targetValue = props.value && !formats.includes(props.value) ? props.value : defaultValue;
|
||||
const [customFormatPreview, setCustomFormatPreview] = useState(targetValue ? date.format(targetValue) : null);
|
||||
const onSelectChange = (v) => {
|
||||
if (v.target.value === 'custom') {
|
||||
@ -67,19 +66,6 @@ const InternalExpiresRadio = (props) => {
|
||||
onChange(v.target.value);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (!formats.includes(props.value)) {
|
||||
setTrue();
|
||||
} else {
|
||||
setFalse();
|
||||
}
|
||||
setTargetValue(props.value && !formats.includes(props.value) ? props.value : defaultValue);
|
||||
}, [props.value]);
|
||||
|
||||
useEffect(() => {
|
||||
setCustomFormatPreview(targetValue ? date.format(targetValue) : null);
|
||||
}, [targetValue]);
|
||||
|
||||
return (
|
||||
<Space className={spaceCSS}>
|
||||
<Radio.Group value={isCustom ? 'custom' : props.value} onChange={onSelectChange}>
|
||||
@ -90,7 +76,7 @@ const InternalExpiresRadio = (props) => {
|
||||
<Radio value={v.value} key={v.value}>
|
||||
<Input
|
||||
style={{ width: '150px' }}
|
||||
value={targetValue}
|
||||
defaultValue={targetValue}
|
||||
onChange={(e) => {
|
||||
if (e.target.value) {
|
||||
setCustomFormatPreview(date.format(e.target.value));
|
||||
@ -100,22 +86,19 @@ const InternalExpiresRadio = (props) => {
|
||||
if (isCustom) {
|
||||
onChange(e.target.value);
|
||||
}
|
||||
setTargetValue(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<DateTimeFormatPreview content={customFormatPreview} />
|
||||
</Radio>
|
||||
);
|
||||
}
|
||||
if (!picker || picker === 'date') {
|
||||
return (
|
||||
<Radio value={v.value} key={v.value} aria-label={v.value}>
|
||||
<span role="button" aria-label={v.value}>
|
||||
{v.label}
|
||||
</span>
|
||||
</Radio>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Radio value={v.value} key={v.value} aria-label={v.value}>
|
||||
<span role="button" aria-label={v.value}>
|
||||
{v.label}
|
||||
</span>
|
||||
</Radio>
|
||||
);
|
||||
})}
|
||||
</Space>
|
||||
</Radio.Group>
|
||||
@ -130,4 +113,4 @@ const ExpiresRadio = connect(
|
||||
}),
|
||||
);
|
||||
|
||||
export { ExpiresRadio, DateFormatCom };
|
||||
export { ExpiresRadio };
|
@ -11,14 +11,13 @@ import { css } from '@emotion/css';
|
||||
import { ISchema, Schema, useField } from '@formily/react';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { getPickerFormat } from '@nocobase/utils/client';
|
||||
import { useCollectionManager_deprecated, useDesignable } from '..';
|
||||
import { DateFormatCom, ExpiresRadio } from '../schema-component';
|
||||
import { DateFormatCom, ExpiresRadio } from './DateFormat/ExpiresRadio';
|
||||
import { SchemaSettingsModalItem } from './SchemaSettings';
|
||||
|
||||
export const SchemaSettingsDateFormat = function DateFormatConfig(props: { fieldSchema: Schema }) {
|
||||
const { fieldSchema } = props;
|
||||
const field: any = useField();
|
||||
const field = useField();
|
||||
const { dn } = useDesignable();
|
||||
const { t } = useTranslation();
|
||||
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
||||
@ -32,48 +31,13 @@ export const SchemaSettingsDateFormat = function DateFormatConfig(props: { field
|
||||
fieldSchema?.['x-component-props']?.timeFormat ||
|
||||
collectionField?.uiSchema?.['x-component-props']?.timeFormat ||
|
||||
'HH:mm:ss';
|
||||
const pickerDefaultValue =
|
||||
fieldSchema?.['x-component-props']?.picker || collectionField?.uiSchema?.['x-component-props']?.picker || 'date';
|
||||
const isReadPretty = fieldSchema['x-read-pretty'] || field.readOnly || field.readPretty;
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
title={t('Date display format')}
|
||||
scope={{ getPickerFormat }}
|
||||
schema={
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
picker: {
|
||||
type: 'string',
|
||||
title: '{{t("Picker")}}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Radio.Group',
|
||||
default: pickerDefaultValue,
|
||||
description:
|
||||
!isReadPretty && '{{ t("Switching the picker, the value and default value will be cleared") }}',
|
||||
enum: [
|
||||
{
|
||||
label: '{{t("Date")}}',
|
||||
value: 'date',
|
||||
},
|
||||
// {
|
||||
// label: '{{t("Week")}}',
|
||||
// value: 'week',
|
||||
// },
|
||||
{
|
||||
label: '{{t("Month")}}',
|
||||
value: 'month',
|
||||
},
|
||||
{
|
||||
label: '{{t("Quarter")}}',
|
||||
value: 'quarter',
|
||||
},
|
||||
{
|
||||
label: '{{t("Year")}}',
|
||||
value: 'year',
|
||||
},
|
||||
],
|
||||
},
|
||||
dateFormat: {
|
||||
type: 'string',
|
||||
title: '{{t("Date format")}}',
|
||||
@ -117,15 +81,6 @@ export const SchemaSettingsDateFormat = function DateFormatConfig(props: { field
|
||||
value: 'custom',
|
||||
},
|
||||
],
|
||||
'x-reactions': {
|
||||
dependencies: ['picker'],
|
||||
fulfill: {
|
||||
state: {
|
||||
value: `{{ getPickerFormat($deps[0])}}`,
|
||||
componentProps: { picker: `{{$deps[0]}}` },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
showTime: {
|
||||
default:
|
||||
@ -141,21 +96,6 @@ export const SchemaSettingsDateFormat = function DateFormatConfig(props: { field
|
||||
f.display = field.value ? 'visible' : 'none';
|
||||
});
|
||||
}}}`,
|
||||
{
|
||||
dependencies: ['picker'],
|
||||
when: '{{$deps[0]!=="date"}}',
|
||||
fulfill: {
|
||||
state: {
|
||||
hidden: true,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
otherwise: {
|
||||
state: {
|
||||
hidden: collectionField?.type === 'dateOnly',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
timeFormat: {
|
||||
@ -200,15 +140,10 @@ export const SchemaSettingsDateFormat = function DateFormatConfig(props: { field
|
||||
} as ISchema
|
||||
}
|
||||
onSubmit={(data) => {
|
||||
const schema: any = {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
if ((field.componentProps.picker || 'date') !== data.picker && !isReadPretty && field.value) {
|
||||
field.value = undefined;
|
||||
field.initialValue = undefined;
|
||||
fieldSchema.default = undefined;
|
||||
schema.default = undefined;
|
||||
}
|
||||
console.log(field.componentProps);
|
||||
schema['x-component-props'] = field.componentProps || {};
|
||||
fieldSchema['x-component-props'] = {
|
||||
...(field.componentProps || {}),
|
||||
@ -222,10 +157,6 @@ export const SchemaSettingsDateFormat = function DateFormatConfig(props: { field
|
||||
const modifiedString = parts.join('.');
|
||||
field.query(`${modifiedString}.*[0:].${fieldSchema.name}`).forEach((f) => {
|
||||
if (f.props.name === fieldSchema.name) {
|
||||
if ((field.componentProps.picker || 'date') !== data.picker && !isReadPretty) {
|
||||
f.value = undefined;
|
||||
f.initialValue = undefined;
|
||||
}
|
||||
f.setComponentProps({ ...data });
|
||||
}
|
||||
});
|
||||
|
@ -110,11 +110,7 @@ export const SchemaSettingsDefaultValue = function DefaultValueConfigure(props:
|
||||
VariableInput: (inputProps) => {
|
||||
return (
|
||||
<FlagProvider isInSubForm={isInSubForm} isInSubTable={isInSubTable} isInSetDefaultValueDialog>
|
||||
<VariableInput
|
||||
{...inputProps}
|
||||
value={inputProps.value || undefined}
|
||||
hideVariableButton={props?.hideVariableButton}
|
||||
/>
|
||||
<VariableInput {...inputProps} hideVariableButton={props?.hideVariableButton} />
|
||||
</FlagProvider>
|
||||
);
|
||||
},
|
||||
|
@ -48,10 +48,7 @@ import { filterFormBlockSettings } from '../modules/blocks/filter-blocks/form/fi
|
||||
import { filterFormItemFieldSettings } from '../modules/blocks/filter-blocks/form/filterFormItemFieldSettings';
|
||||
import { markdownBlockSettings } from '../modules/blocks/other-blocks/markdown/markdownBlockSettings';
|
||||
import { cascadeSelectComponentFieldSettings } from '../modules/fields/component/CascadeSelect/cascadeSelectComponentFieldSettings';
|
||||
import {
|
||||
datePickerComponentFieldSettings,
|
||||
rangePickerPickerComponentFieldSettings,
|
||||
} from '../modules/fields/component/DatePicker/datePickerComponentFieldSettings';
|
||||
import { datePickerComponentFieldSettings } from '../modules/fields/component/DatePicker/datePickerComponentFieldSettings';
|
||||
import { fileManagerComponentFieldSettings } from '../modules/fields/component/FileManager/fileManagerComponentFieldSettings';
|
||||
import { previewComponentFieldSettings } from '../modules/fields/component/FileManager/previewComponentFieldSettings';
|
||||
import { uploadAttachmentComponentFieldSettings } from '../modules/fields/component/FileManager/uploadAttachmentComponentFieldSettings';
|
||||
@ -123,7 +120,6 @@ export class SchemaSettingsPlugin extends Plugin {
|
||||
this.schemaSettingsManager.add(subformPopoverComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(subTablePopoverComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(datePickerComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(rangePickerPickerComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(unixTimestampComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(inputNumberComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(inputComponentSettings);
|
||||
|
@ -44,7 +44,7 @@ export const getDefaultFormat = (props: GetDefaultFormatProps) => {
|
||||
} else if (props['picker'] === 'year') {
|
||||
return 'YYYY';
|
||||
} else if (props['picker'] === 'week') {
|
||||
return 'YYYY[W]W';
|
||||
return 'YYYY-wo';
|
||||
}
|
||||
return props['showTime'] ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD';
|
||||
};
|
||||
@ -68,33 +68,24 @@ export const toLocal = (value: dayjs.Dayjs) => {
|
||||
}
|
||||
};
|
||||
|
||||
const convertQuarterToFirstDay = (quarterStr) => {
|
||||
const year = parseInt(quarterStr.slice(0, 4)); // 提取年份
|
||||
const quarter = parseInt(quarterStr.slice(-1)); // 提取季度数字
|
||||
return dayjs().quarter(quarter).year(year);
|
||||
};
|
||||
|
||||
const toMoment = (val: any, options?: Str2momentOptions) => {
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
const offset = options.utcOffset || -1 * new Date().getTimezoneOffset();
|
||||
const { gmt, picker, utc = true } = options;
|
||||
if (dayjs(val).isValid()) {
|
||||
if (!utc) {
|
||||
return dayjs(val);
|
||||
}
|
||||
|
||||
if (dayjs.isDayjs(val)) {
|
||||
return val.utcOffset(offsetFromString(offset));
|
||||
}
|
||||
if (gmt) {
|
||||
return dayjs(val).utcOffset(0);
|
||||
}
|
||||
return dayjs(val).utcOffset(offsetFromString(offset));
|
||||
} else {
|
||||
return convertQuarterToFirstDay(val);
|
||||
if (!utc) {
|
||||
return dayjs(val);
|
||||
}
|
||||
|
||||
if (dayjs.isDayjs(val)) {
|
||||
return val.utcOffset(offsetFromString(offset));
|
||||
}
|
||||
if (gmt || picker) {
|
||||
return dayjs(val).utcOffset(0);
|
||||
}
|
||||
return dayjs(val).utcOffset(offsetFromString(offset));
|
||||
};
|
||||
|
||||
export const str2moment = (
|
||||
@ -207,18 +198,3 @@ function absFloor(number) {
|
||||
return Math.floor(number);
|
||||
}
|
||||
}
|
||||
|
||||
export const getPickerFormat = (picker) => {
|
||||
switch (picker) {
|
||||
case 'week':
|
||||
return 'YYYY[W]W';
|
||||
case 'month':
|
||||
return 'YYYY-MM';
|
||||
case 'quarter':
|
||||
return 'YYYY[Q]Q';
|
||||
case 'year':
|
||||
return 'YYYY';
|
||||
default:
|
||||
return 'YYYY-MM-DD';
|
||||
}
|
||||
};
|
||||
|
@ -99,6 +99,7 @@ export const BulkEditField = (props: any) => {
|
||||
const [value, setValue] = useState(null);
|
||||
const { getField } = useCollection_deprecated();
|
||||
const collectionField = getField(fieldSchema.name) || {};
|
||||
|
||||
useEffect(() => {
|
||||
field.value = toFormFieldValue({ [type]: value });
|
||||
if (field.required) {
|
||||
@ -111,12 +112,6 @@ export const BulkEditField = (props: any) => {
|
||||
}
|
||||
}, [field, type, value]);
|
||||
|
||||
useEffect(() => {
|
||||
if (field.value === null) {
|
||||
setValue(undefined);
|
||||
}
|
||||
}, [field.value]);
|
||||
|
||||
const typeChangeHandler = (val) => {
|
||||
setType(val);
|
||||
field.required = val === BulkEditFormItemValueType.ChangedTo;
|
||||
|
@ -30,7 +30,6 @@ import {
|
||||
ResourceActionContext,
|
||||
useDataSourceManager,
|
||||
} from '@nocobase/client';
|
||||
import { getPickerFormat } from '@nocobase/utils/client';
|
||||
import { message } from 'antd';
|
||||
import { getCollectionSchema } from './schema/collections';
|
||||
import { CollectionFields } from './CollectionFields';
|
||||
@ -209,7 +208,6 @@ export const ConfigurationTable = () => {
|
||||
interfaces,
|
||||
enableInherits: database?.dialect === 'postgres',
|
||||
isPG: database?.dialect === 'postgres',
|
||||
getPickerFormat,
|
||||
}}
|
||||
/>
|
||||
</SchemaComponentContext.Provider>
|
||||
|
@ -12,6 +12,7 @@ import { action } from '@formily/reactive';
|
||||
import { uid } from '@formily/shared';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
// import { CollectionFieldsTable } from '.';
|
||||
import {
|
||||
useAPIClient,
|
||||
useCurrentAppInfo,
|
||||
@ -28,8 +29,9 @@ import {
|
||||
CollectionCategoriesContext,
|
||||
FieldSummary,
|
||||
TemplateSummary,
|
||||
useRequest,
|
||||
useCollectionRecordData,
|
||||
} from '@nocobase/client';
|
||||
import { getPickerFormat } from '@nocobase/utils/client';
|
||||
import { CollectionFields } from './CollectionFields';
|
||||
import { collectionSchema } from './schemas/collections';
|
||||
|
||||
@ -237,7 +239,6 @@ export const ConfigurationTable = () => {
|
||||
interfaces,
|
||||
enableInherits: database?.dialect === 'postgres',
|
||||
isPG: database?.dialect === 'postgres',
|
||||
getPickerFormat,
|
||||
}}
|
||||
/>
|
||||
</SchemaComponentContext.Provider>
|
||||
|
Loading…
Reference in New Issue
Block a user