Skip to content

Commit

Permalink
Merge pull request #250 from sunshineLixun/dev
Browse files Browse the repository at this point in the history
feat: DatePicker
  • Loading branch information
sendya authored Oct 25, 2022
2 parents a21d02e + afa1694 commit 1127fa6
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 69 deletions.
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

0 comments on commit 1127fa6

Please sign in to comment.