mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 13:39:24 +08:00
Merge branch 'next' into develop
This commit is contained in:
commit
9f6688b436
@ -2,9 +2,7 @@
|
||||
"version": "1.6.0-alpha.6",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"npmClientArgs": [
|
||||
"--ignore-engines"
|
||||
],
|
||||
"npmClientArgs": ["--ignore-engines"],
|
||||
"command": {
|
||||
"version": {
|
||||
"forcePublish": true,
|
||||
|
@ -854,6 +854,10 @@
|
||||
"Failed to load plugin": "插件加载失败",
|
||||
"Allow add new, update and delete actions": "允许增删改操作",
|
||||
"Date display format": "日期显示格式",
|
||||
"Date range limit": "日期限定范围",
|
||||
"MinDate": "最小日期",
|
||||
"MaxDate": "最大日期",
|
||||
"Please select time or variable": "请选择时间或变量",
|
||||
"Filter out a single piece or a group of records as a template": "筛选出一条或一组数据,作为模板",
|
||||
"The title field is used to identify the template record": "用于识别模板数据",
|
||||
"Template fields": "模板字段",
|
||||
|
@ -9,8 +9,9 @@
|
||||
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
||||
import { SchemaSettingsDateFormat } from '../../../../schema-settings/SchemaSettingsDateFormat';
|
||||
import { SchemaSettingsDateRange } from '../../../../schema-settings/SchemaSettingsDateRange';
|
||||
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
||||
import { ellipsisSettingsItem, enableLinkSettingsItem, openModeSettingsItem } from '../Input/inputComponentSettings';
|
||||
|
||||
export const datePickerComponentFieldSettings = new SchemaSettings({
|
||||
@ -28,6 +29,24 @@ export const datePickerComponentFieldSettings = new SchemaSettings({
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'dateScopeSelect',
|
||||
Component: SchemaSettingsDateRange as any,
|
||||
useComponentProps() {
|
||||
const schema = useFieldSchema();
|
||||
const { fieldSchema: tableColumnSchema } = useColumnSchema();
|
||||
const fieldSchema = tableColumnSchema || schema;
|
||||
return {
|
||||
fieldSchema,
|
||||
};
|
||||
},
|
||||
useVisible() {
|
||||
const { fieldSchema: columnSchema } = useColumnSchema();
|
||||
const schema = useFieldSchema();
|
||||
const fieldSchema = columnSchema || schema;
|
||||
return !fieldSchema?.['x-read-pretty'];
|
||||
},
|
||||
},
|
||||
ellipsisSettingsItem,
|
||||
enableLinkSettingsItem,
|
||||
openModeSettingsItem,
|
||||
|
@ -7,17 +7,19 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react';
|
||||
import { connect, mapProps, mapReadPretty, useField, useFieldSchema, observer } from '@formily/react';
|
||||
import { DatePicker as AntdDatePicker, DatePickerProps as AntdDatePickerProps, Space, Select } from 'antd';
|
||||
import { RangePickerProps } from 'antd/es/date-picker';
|
||||
import dayjs from 'dayjs';
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { getPickerFormat } from '@nocobase/utils/client';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ReadPretty, ReadPrettyComposed } from './ReadPretty';
|
||||
import { getDateRanges, mapDatePicker, mapRangePicker, inferPickerType } from './util';
|
||||
import { useCompile } from '../../';
|
||||
|
||||
import { useVariables, useLocalVariables, isVariable } from '../../../variables';
|
||||
import { autorun } from '@formily/reactive';
|
||||
import { log10 } from 'mathjs';
|
||||
interface IDatePickerProps {
|
||||
utc?: boolean;
|
||||
}
|
||||
@ -52,9 +54,111 @@ const InternalRangePicker = connect(
|
||||
export const DatePicker: ComposedDatePicker = (props: any) => {
|
||||
const { utc = true } = useDatePickerContext();
|
||||
const value = Array.isArray(props.value) ? props.value[0] : props.value;
|
||||
const { parseVariable } = useVariables() || {};
|
||||
const localVariables = useLocalVariables();
|
||||
const [disabledDate, setDisabledDate] = useState(null);
|
||||
const [disabledTime, setDisabledTime] = useState(null);
|
||||
const disposeRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (disposeRef.current) {
|
||||
disposeRef.current();
|
||||
}
|
||||
disposeRef.current = autorun(() => {
|
||||
limitDate();
|
||||
});
|
||||
return () => {
|
||||
disposeRef.current();
|
||||
};
|
||||
}, [props._maxDate, props._minDate, localVariables, parseVariable]);
|
||||
|
||||
const limitDate = async () => {
|
||||
//dayjs()如果传入undefined可能会被解析成当前时间
|
||||
let minDateTimePromise = props._minDate ? Promise.resolve(dayjs(props._minDate)) : Promise.resolve(null);
|
||||
let maxDateTimePromise = props._maxDate ? Promise.resolve(dayjs(props._maxDate)) : Promise.resolve(null);
|
||||
|
||||
if (isVariable(props._maxDate)) {
|
||||
maxDateTimePromise = parseVariable(props._maxDate, localVariables).then((result) => dayjs(result.value));
|
||||
}
|
||||
if (isVariable(props._minDate)) {
|
||||
minDateTimePromise = parseVariable(props._minDate, localVariables).then((result) => dayjs(result.value));
|
||||
}
|
||||
|
||||
const [minDateTime, maxDateTime] = await Promise.all([minDateTimePromise, maxDateTimePromise]);
|
||||
|
||||
const fullTimeArr = Array.from({ length: 60 }, (_, i) => i);
|
||||
|
||||
// 根据最小日期和最大日期限定日期时间
|
||||
const disabledDate = (current) => {
|
||||
if (!current || (!minDateTime && !maxDateTime)) {
|
||||
return false;
|
||||
}
|
||||
// 确保 current 是一个 dayjs 对象
|
||||
const currentDate = dayjs(current);
|
||||
//在minDateTime或maxDateTime为null时 dayjs的比较函数会默认返回false 所以不做特殊判断
|
||||
return currentDate.isBefore(minDateTime, 'minute') || currentDate.isAfter(maxDateTime, 'minute');
|
||||
};
|
||||
|
||||
// 禁用时分秒
|
||||
const disabledTime = (current) => {
|
||||
if (!current || (!minDateTime && !maxDateTime)) {
|
||||
return { disabledHours: () => [], disabledMinutes: () => [], disabledSeconds: () => [] };
|
||||
}
|
||||
|
||||
const currentDate = dayjs(current);
|
||||
const isCurrentMinDay = currentDate.isSame(minDateTime, 'day');
|
||||
const isCurrentMaxDay = currentDate.isSame(maxDateTime, 'day');
|
||||
|
||||
const disabledHours = () => {
|
||||
const hours = [];
|
||||
if (isCurrentMinDay) {
|
||||
hours.push(...Array.from({ length: minDateTime.hour() }, (_, i) => i));
|
||||
}
|
||||
if (isCurrentMaxDay) {
|
||||
hours.push(...Array.from({ length: 24 - maxDateTime.hour() }, (_, i) => i + maxDateTime.hour() + 1));
|
||||
}
|
||||
return hours;
|
||||
};
|
||||
|
||||
const getDisabledMinutes = (selectedHour: number) => {
|
||||
if (isCurrentMinDay && selectedHour === minDateTime.hour()) {
|
||||
return fullTimeArr.filter((i) => i < minDateTime.minute());
|
||||
}
|
||||
if (isCurrentMaxDay && selectedHour === maxDateTime.hour()) {
|
||||
return fullTimeArr.filter((i) => i > maxDateTime.minute());
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
const getDisabledSeconds = (selectedHour: number, selectedMinute: number) => {
|
||||
if (isCurrentMinDay && selectedHour === minDateTime.hour() && selectedMinute === minDateTime.minute()) {
|
||||
return fullTimeArr.filter((i) => i < minDateTime.second());
|
||||
}
|
||||
if (isCurrentMaxDay && selectedHour === maxDateTime.hour() && selectedMinute === maxDateTime.minute()) {
|
||||
return fullTimeArr.filter((i) => i > maxDateTime.second());
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
return {
|
||||
disabledHours,
|
||||
disabledMinutes: getDisabledMinutes,
|
||||
disabledSeconds: getDisabledSeconds,
|
||||
};
|
||||
};
|
||||
setDisabledDate(() => {
|
||||
return disabledDate;
|
||||
});
|
||||
setDisabledTime(() => {
|
||||
return disabledTime;
|
||||
});
|
||||
};
|
||||
|
||||
const newProps = {
|
||||
utc,
|
||||
...props,
|
||||
disabledDate,
|
||||
disabledTime,
|
||||
showTime: props.showTime ? { defaultValue: dayjs('00:00:00', 'HH:mm:ss') } : false,
|
||||
};
|
||||
return <InternalDatePicker {...newProps} value={value} />;
|
||||
|
@ -0,0 +1,184 @@
|
||||
/**
|
||||
* This file is part of the NocoBase (R) project.
|
||||
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
||||
* Authors: NocoBase Team.
|
||||
*
|
||||
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { ISchema, Schema, useField } from '@formily/react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaComponent } from '../schema-component';
|
||||
import { SchemaSettingsModalItem } from './SchemaSettings';
|
||||
import {
|
||||
useCollectionManager_deprecated,
|
||||
useRecord,
|
||||
useDesignable,
|
||||
VariableInput,
|
||||
useFormBlockContext,
|
||||
FlagProvider,
|
||||
useFlag,
|
||||
} from '..';
|
||||
import { isVariable } from '../variables/utils/isVariable';
|
||||
|
||||
export const SchemaSettingsDateRange = function DateRangeConfig(props: { fieldSchema: Schema }) {
|
||||
const { fieldSchema } = props;
|
||||
const field: any = useField();
|
||||
const { dn } = useDesignable();
|
||||
const { t } = useTranslation();
|
||||
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
||||
const { isInSubForm, isInSubTable } = useFlag() || {};
|
||||
const collectionField = getCollectionJoinField(fieldSchema?.['x-collection-field']) || {};
|
||||
const showTime =
|
||||
fieldSchema?.['x-component-props']?.showTime || collectionField?.uiSchema?.['x-component-props']?.showTime || false;
|
||||
const dateFormat =
|
||||
fieldSchema?.['x-component-props']?.dateFormat ||
|
||||
collectionField?.uiSchema?.['x-component-props']?.dateFormat ||
|
||||
'YYYY-MM-DD';
|
||||
const timeFormat =
|
||||
fieldSchema?.['x-component-props']?.timeFormat ||
|
||||
collectionField?.uiSchema?.['x-component-props']?.timeFormat ||
|
||||
'HH:mm:ss';
|
||||
const picker =
|
||||
fieldSchema?.['x-component-props']?.picker || collectionField?.uiSchema?.['x-component-props']?.picker || 'date';
|
||||
const isReadPretty = fieldSchema['x-read-pretty'] || field.readOnly || field.readPretty;
|
||||
const minDateDefaultValue = fieldSchema?.['x-component-props']?._minDate;
|
||||
const maxDateDefaultValue = fieldSchema?.['x-component-props']?._maxDate;
|
||||
const gmt = collectionField?.uiSchema?.['x-component-props'].gmt || false;
|
||||
const utc = collectionField?.uiSchema?.['x-component-props'].utc || false;
|
||||
const record = useRecord();
|
||||
const { form } = useFormBlockContext();
|
||||
|
||||
const renderSchemaComponent = useCallback(
|
||||
(props) => {
|
||||
return (
|
||||
<SchemaComponent
|
||||
schema={{
|
||||
'x-component': 'DatePicker',
|
||||
'x-component-props': {
|
||||
dateFormat,
|
||||
timeFormat,
|
||||
gmt,
|
||||
utc,
|
||||
picker,
|
||||
showTime,
|
||||
placeholder: '{{t("Please select time or variable")}}',
|
||||
style: {
|
||||
minWidth: 385,
|
||||
},
|
||||
},
|
||||
name: 'value',
|
||||
'x-read-pretty': false,
|
||||
'x-validator': undefined,
|
||||
'x-decorator': undefined,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[dateFormat, gmt, picker, showTime, timeFormat, utc],
|
||||
);
|
||||
const Component = useCallback(
|
||||
(props) => {
|
||||
return (
|
||||
<VariableInput
|
||||
{...props}
|
||||
form={form}
|
||||
record={record}
|
||||
noDisabled={true}
|
||||
renderSchemaComponent={renderSchemaComponent}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[fieldSchema, form, record, renderSchemaComponent],
|
||||
);
|
||||
|
||||
// 无论是日期还是变量的情况下当值为空的时候都转换成undefined
|
||||
function getDateValue(dateObject) {
|
||||
if (dateObject === null || dateObject === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof dateObject === 'string') {
|
||||
return dateObject;
|
||||
}
|
||||
if (typeof dateObject === 'object' && Object.prototype.hasOwnProperty.call(dateObject, 'value')) {
|
||||
return getDateValue(dateObject.value);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
title={t('Date range limit')}
|
||||
schema={
|
||||
{
|
||||
type: 'object',
|
||||
'x-decorator': '',
|
||||
properties: {
|
||||
_minDate: {
|
||||
type: 'string',
|
||||
title: '{{t("MinDate")}}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': Component,
|
||||
'x-component-props': {
|
||||
name: '_minDate',
|
||||
},
|
||||
//日期和使用变量设置的默认值不同
|
||||
default: isVariable(minDateDefaultValue) ? minDateDefaultValue : { value: minDateDefaultValue },
|
||||
},
|
||||
_maxDate: {
|
||||
type: 'string',
|
||||
title: '{{t("MaxDate")}}',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': Component,
|
||||
'x-component-props': {
|
||||
name: '_maxDate',
|
||||
},
|
||||
default: isVariable(maxDateDefaultValue) ? maxDateDefaultValue : { value: maxDateDefaultValue },
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
}
|
||||
onSubmit={(data) => {
|
||||
const schema: any = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
schema['x-component-props'] = field.componentProps || {};
|
||||
fieldSchema['x-component-props'] = {
|
||||
...(field.componentProps || {}),
|
||||
_maxDate: getDateValue(data?._maxDate),
|
||||
_minDate: getDateValue(data?._minDate),
|
||||
};
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps = fieldSchema['x-component-props'];
|
||||
|
||||
//子表格/表格区块
|
||||
const parts = (field.path.entire as string).split('.');
|
||||
parts.pop();
|
||||
const modifiedString = parts.join('.');
|
||||
field.query(`${modifiedString}.*[0:].${fieldSchema.name}`).forEach((f) => {
|
||||
if (f.props.name === fieldSchema.name) {
|
||||
f.setComponentProps({
|
||||
_maxDate: getDateValue(data?._maxDate),
|
||||
_minDate: getDateValue(data?._minDate),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
// 这里是为了在新增表单中设置日期范围时设置的值能正常显示
|
||||
ModalContextProvider={(props) => {
|
||||
return (
|
||||
<FlagProvider isInSubForm={isInSubForm} isInSubTable={isInSubTable} isInFormDataTemplate={true}>
|
||||
{props.children}
|
||||
</FlagProvider>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user