Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: DatePicker #250

Merged
merged 7 commits into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions packages/pro-field/src/components/DatePicker/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { defineComponent, type App, DefineComponent, Plugin } from 'vue';
import Dayjs from 'dayjs';
import { fieldDatePickerProps, FieldDatePickerProps } from './types';
import { DatePicker } from 'ant-design-vue';
import { getSlot } from '@ant-design-vue/pro-utils';
import type { VueNode } from 'ant-design-vue/lib/_util/type';

const formatDate = (text: any, format: any) => {
if (!text) {
return '-';
}
if (typeof format === 'function') {
return format(Dayjs(text));
} else {
return Dayjs(text).format(format || 'YYYY-MM-DD');
}
};

export const slots = ['suffixIcon', 'prevIcon', 'nextIcon', 'superPrevIcon', 'superNextIcon'];

const FieldDatePicker = defineComponent({
name: 'FieldDatePicker',
inheritAttrs: false,
props: fieldDatePickerProps,
slots,
setup(props, { slots }) {
const suffixIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'suffixIcon');
const prevIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'prevIcon');
const nextIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'nextIcon');
const superPrevIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'superPrevIcon');
const superNextIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'superNextIcon');

const render = getSlot(slots, props.fieldProps as Record<string, any>, 'render') as any;
const renderFormItem = getSlot(slots, props.fieldProps as Record<string, any>, 'renderFormItem') as any;

return () => {
const { mode, text, dateFormat, fieldProps } = props;
const { placeholder, format } = fieldProps || {};

if (mode === 'read') {
const dom = formatDate(text, format || dateFormat);
if (render) {
return render(text, { mode, ...fieldProps }, <>{dom}</>);
}
return <>{dom}</>;
}
if (mode === 'edit' || mode === 'update') {
const dom = (
<DatePicker
v-slots={{
suffixIcon,
prevIcon,
nextIcon,
superPrevIcon,
superNextIcon,
}}
{...fieldProps}
placeholder={placeholder || '请选择'}
allowClear
/>
);
if (renderFormItem) {
return renderFormItem(text, { mode, ...fieldProps }, dom);
}
return dom;
}
return null;
};
},
});

FieldDatePicker.install = (app: App) => {
app.component(FieldDatePicker.name, FieldDatePicker);
return app;
};

export default FieldDatePicker as DefineComponent<FieldDatePickerProps> & Plugin;
16 changes: 16 additions & 0 deletions packages/pro-field/src/components/DatePicker/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ExtractPropTypes, PropType } from 'vue';
import type { CommonProps, DatePickerProps } from 'ant-design-vue/es/date-picker/generatePicker/props';
import { proFieldFC } from '../typings';

export const fieldDatePickerProps = {
...proFieldFC,
/** 日期格式化 */
dateFormat: {
type: String,
},
fieldProps: {
type: Object as PropType<CommonProps<any> & DatePickerProps<any>>,
},
};

export type FieldDatePickerProps = Partial<ExtractPropTypes<typeof fieldDatePickerProps>>;
3 changes: 2 additions & 1 deletion packages/pro-field/src/components/Password/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const FieldPassword = defineComponent({
setup(props, { slots }) {
return () => {
const { mode, text, fieldProps } = props;
const placeholder = fieldProps.placeholder || '请输入';
const render = props.render ?? slots.render;
const renderFormItem = props.renderFormItem ?? slots?.renderFormItem;

Expand All @@ -34,7 +35,7 @@ const FieldPassword = defineComponent({
return dom;
}
if (mode === 'edit' || mode === 'update') {
const renderDom = <InputPassword allowClear {...props.fieldProps} />;
const renderDom = <InputPassword {...props.fieldProps} allowClear placeholder={placeholder} />;
if (renderFormItem) {
return renderFormItem(text, { mode, fieldProps }, renderDom);
}
Expand Down
39 changes: 3 additions & 36 deletions packages/pro-field/src/components/Select/SearchSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,14 @@ import { Select } from 'ant-design-vue';
import { searchSelectProps } from './types';
import { getSlot } from '@ant-design-vue/pro-utils';

export const slots = [
'notFoundContent',
'suffixIcon',
'itemIcon',
'removeIcon',
'clearIcon',
'dropdownRender',
'option',
'placeholder',
'tagRender',
'maxTagPlaceholder',
'optionLabel',
'default',
];
export const slots = ['default'];

const SearchSelect = defineComponent({
props: searchSelectProps,
slots,
setup(props, { slots }) {
const searchValue = ref(props.searchValue);

const notFoundContent = getSlot(slots, props, 'notFoundContent');
const suffixIcon = getSlot(slots, props, 'suffixIcon');
const itemIcon = getSlot(slots, props, 'itemIcon');
const removeIcon = getSlot(slots, props, 'removeIcon');
const clearIcon = getSlot(slots, props, 'clearIcon');
const dropdownRender = getSlot(slots, props, 'dropdownRender');
const option = getSlot(slots, props, 'option');
const placeholder = getSlot(slots, props, 'placeholder');
const tagRender = getSlot(slots, props, 'tagRender');
const maxTagPlaceholder = getSlot(slots, props, 'maxTagPlaceholder');
const optionLabel = getSlot(slots, props, 'optionLabel');
const children = getSlot(slots, props, 'default');

return () => {
Expand All @@ -43,6 +19,7 @@ const SearchSelect = defineComponent({
labelInValue,
autoClearSearchValue = true,
showSearch,
placeholder,
onSearch,
onClear,
fetchData,
Expand All @@ -52,22 +29,12 @@ const SearchSelect = defineComponent({
return (
<Select
v-slots={{
notFoundContent,
suffixIcon,
itemIcon,
removeIcon,
clearIcon,
dropdownRender,
option,
placeholder,
tagRender,
maxTagPlaceholder,
optionLabel,
default: children,
}}
autoClearSearchValue={autoClearSearchValue}
{...restProps}
allowClear
placeholder={placeholder || '请选择'}
searchValue={searchValue.value}
onClear={() => {
onClear?.();
Expand Down
9 changes: 5 additions & 4 deletions packages/pro-field/src/components/Text/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { defineComponent, type App, type Plugin, type DefineComponent } from 'vue';
import { Input } from 'ant-design-vue';
import { textFieldPorps, type TextFieldPorps } from './types';
import { textFieldProps, type TextFieldProps } from './types';
import 'ant-design-vue/es/input/style/index.less';

const FieldText = defineComponent({
name: 'FieldText',
inheritAttrs: false,
props: textFieldPorps,
props: textFieldProps,
slots: ['render', 'renderFormItem'],
setup(props, { slots }) {
return () => {
const { type, mode, text, emptyText, fieldProps } = props;
const placeholder = fieldProps.placeholder || '请输入';
const render = props.render ?? slots?.render;
const renderFormItem = props.renderFormItem ?? slots?.renderFormItem;
if (mode === 'read') {
Expand All @@ -27,7 +28,7 @@ const FieldText = defineComponent({
return dom;
}
if (mode === 'edit' || mode === 'update') {
const renderDom = <Input type={type} allowClear {...fieldProps} />;
const renderDom = <Input {...fieldProps} type={type} allowClear placeholder={placeholder} />;
if (renderFormItem) {
return renderFormItem(text, { mode, fieldProps }, renderDom);
}
Expand All @@ -43,4 +44,4 @@ FieldText.install = (app: App) => {
return app;
};

export default FieldText as DefineComponent<TextFieldPorps> & Plugin;
export default FieldText as DefineComponent<TextFieldProps> & Plugin;
4 changes: 2 additions & 2 deletions packages/pro-field/src/components/Text/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { InputProps } from 'ant-design-vue/es/input/inputProps';
import type { VueNode } from '@ant-design-vue/pro-utils';
import { proFieldFC } from '../typings';

export const textFieldPorps = {
export const textFieldProps = {
...proFieldFC,
// 这里预留一个原生的input type属性
type: {
Expand All @@ -15,4 +15,4 @@ export const textFieldPorps = {
},
};

export type TextFieldPorps = Partial<ExtractPropTypes<typeof textFieldPorps>>;
export type TextFieldProps = Partial<ExtractPropTypes<typeof textFieldProps>>;
28 changes: 23 additions & 5 deletions packages/pro-field/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,21 @@ export {
};

// pro-field
import { textFieldPorps, type TextFieldPorps } from './components/Text/types';
import { textFieldProps, type TextFieldProps } from './components/Text/types';
import FieldText from './components/Text';
export { FieldText, textFieldPorps, type TextFieldPorps };
export { FieldText, textFieldProps, type TextFieldProps };

import { passwordTextProps, type PasswordTextProps } from './components/Password/types';
import FieldPassword from './components/Password';
export { FieldPassword, passwordTextProps, type PasswordTextProps };

import { searchSelectProps, type SearchSelectProps } from './components/Select/SearchSelect/types';
import FieldSelect from './components/Select';
import { slots as searchSelectSlots } from './components/Select/SearchSelect';
export { FieldSelect, searchSelectProps, searchSelectSlots, type SearchSelectProps };
export { FieldSelect, searchSelectProps, type SearchSelectProps };

import { fieldDatePickerProps, type FieldDatePickerProps } from './components/DatePicker/types';
import FieldDatePicker, { slots as fieldDatePickerSlots } from './components/DatePicker';
export { FieldDatePicker, fieldDatePickerProps, fieldDatePickerSlots, FieldDatePickerProps };

// style
import './default.less';
Expand Down Expand Up @@ -100,6 +103,21 @@ const defaultRenderText = (
props: RenderProps
// valueTypeMap: Record<string, ProRenderFieldPropsType>
): VueNode => {
if (valueType === 'date') {
const { fieldProps } = props;
return (
<FieldDatePicker
dateFormat="YYYY-MM-DD"
fieldProps={{
...fieldProps,
mode: 'date',
picker: 'date',
}}
{...props}
text={dataValue as string}
/>
);
}
if (valueType === 'select') {
let text = '';
if (dataValue instanceof Array) {
Expand Down Expand Up @@ -143,7 +161,7 @@ const ProField = defineComponent({
const omitFieldProps = omitUndefined({
...fieldProps,
value: unref(inputValue),
'onUpdate:value'(value: string) {
'onUpdate:value'(value: any) {
inputValue.value = value;
fieldProps?.['onUpdate:value']?.(value);
},
Expand Down
24 changes: 20 additions & 4 deletions packages/pro-form/examples/views/ProForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -139,25 +139,40 @@
name="lang"
label="语言"
:field-props="{
placeholder: '请选择',
placeholder: '请选择语言',
}"
>
<SelectOption v-for="lang in langs" :key="lang.value" :value="lang.value">
<span role="img" :aria-label="lang.value">{{ lang.icon }}</span
>&nbsp;&nbsp;{{ lang.label }}</SelectOption
>
<template #suffixIcon>
<plus-outlined />
</template>
</pro-form-select>
<pro-form-select
name="country"
label="国家"
:field-props="{
placeholder: '请选择',
showSearch: true,
mode: 'multiple',
filterOption: false,
}"
:request="fetchUser"
/>
>
<template #placeholder> 请选择国家 </template>
</pro-form-select>
<pro-form-date-picker
name="expirationTime"
label="合同失效时间"
:field-props="{
placeholder: '请选择合同失效时间',
}"
>
<template #superPrevIcon>
<plus-outlined />
</template>
</pro-form-date-picker>
</pro-form>
</template>

Expand All @@ -166,7 +181,7 @@ import { reactive, ref, FunctionalComponent } from 'vue';
import { PlusOutlined } from '@ant-design/icons-vue';
import { RadioGroup, RadioButton, Switch, Divider, SelectOption, type SelectProps } from 'ant-design-vue';
import type { FormLayout } from 'ant-design-vue/es/form/Form';
import { ProForm, ProFormText, ProFormPassword, ProFormSelect } from '@ant-design-vue/pro-form';
import { ProForm, ProFormText, ProFormPassword, ProFormSelect, ProFormDatePicker } from '@ant-design-vue/pro-form';

let lastFetchId = 0;

Expand Down Expand Up @@ -201,6 +216,7 @@ const formModel = reactive({
girlName: undefined,
lang: undefined,
country: undefined,
expirationTime: undefined,
});

const sex = ref([
Expand Down
1 change: 0 additions & 1 deletion packages/pro-form/src/BaseForm/hooks/useFormMethods.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { toRaw, isProxy } from 'vue';
import { proxyToRaw } from '@ant-design-vue/pro-utils';
import type { Recordable } from '../../typings';

Expand Down
Loading