Skip to content

Commit 1127fa6

Browse files
authored
Merge pull request #250 from sunshineLixun/dev
feat: DatePicker
2 parents a21d02e + afa1694 commit 1127fa6

File tree

13 files changed

+227
-69
lines changed

13 files changed

+227
-69
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { defineComponent, type App, DefineComponent, Plugin } from 'vue';
2+
import Dayjs from 'dayjs';
3+
import { fieldDatePickerProps, FieldDatePickerProps } from './types';
4+
import { DatePicker } from 'ant-design-vue';
5+
import { getSlot } from '@ant-design-vue/pro-utils';
6+
import type { VueNode } from 'ant-design-vue/lib/_util/type';
7+
8+
const formatDate = (text: any, format: any) => {
9+
if (!text) {
10+
return '-';
11+
}
12+
if (typeof format === 'function') {
13+
return format(Dayjs(text));
14+
} else {
15+
return Dayjs(text).format(format || 'YYYY-MM-DD');
16+
}
17+
};
18+
19+
export const slots = ['suffixIcon', 'prevIcon', 'nextIcon', 'superPrevIcon', 'superNextIcon'];
20+
21+
const FieldDatePicker = defineComponent({
22+
name: 'FieldDatePicker',
23+
inheritAttrs: false,
24+
props: fieldDatePickerProps,
25+
slots,
26+
setup(props, { slots }) {
27+
const suffixIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'suffixIcon');
28+
const prevIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'prevIcon');
29+
const nextIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'nextIcon');
30+
const superPrevIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'superPrevIcon');
31+
const superNextIcon = getSlot<() => VueNode>(slots, props.fieldProps as Record<string, any>, 'superNextIcon');
32+
33+
const render = getSlot(slots, props.fieldProps as Record<string, any>, 'render') as any;
34+
const renderFormItem = getSlot(slots, props.fieldProps as Record<string, any>, 'renderFormItem') as any;
35+
36+
return () => {
37+
const { mode, text, dateFormat, fieldProps } = props;
38+
const { placeholder, format } = fieldProps || {};
39+
40+
if (mode === 'read') {
41+
const dom = formatDate(text, format || dateFormat);
42+
if (render) {
43+
return render(text, { mode, ...fieldProps }, <>{dom}</>);
44+
}
45+
return <>{dom}</>;
46+
}
47+
if (mode === 'edit' || mode === 'update') {
48+
const dom = (
49+
<DatePicker
50+
v-slots={{
51+
suffixIcon,
52+
prevIcon,
53+
nextIcon,
54+
superPrevIcon,
55+
superNextIcon,
56+
}}
57+
{...fieldProps}
58+
placeholder={placeholder || '请选择'}
59+
allowClear
60+
/>
61+
);
62+
if (renderFormItem) {
63+
return renderFormItem(text, { mode, ...fieldProps }, dom);
64+
}
65+
return dom;
66+
}
67+
return null;
68+
};
69+
},
70+
});
71+
72+
FieldDatePicker.install = (app: App) => {
73+
app.component(FieldDatePicker.name, FieldDatePicker);
74+
return app;
75+
};
76+
77+
export default FieldDatePicker as DefineComponent<FieldDatePickerProps> & Plugin;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { ExtractPropTypes, PropType } from 'vue';
2+
import type { CommonProps, DatePickerProps } from 'ant-design-vue/es/date-picker/generatePicker/props';
3+
import { proFieldFC } from '../typings';
4+
5+
export const fieldDatePickerProps = {
6+
...proFieldFC,
7+
/** 日期格式化 */
8+
dateFormat: {
9+
type: String,
10+
},
11+
fieldProps: {
12+
type: Object as PropType<CommonProps<any> & DatePickerProps<any>>,
13+
},
14+
};
15+
16+
export type FieldDatePickerProps = Partial<ExtractPropTypes<typeof fieldDatePickerProps>>;

packages/pro-field/src/components/Password/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const FieldPassword = defineComponent({
1111
setup(props, { slots }) {
1212
return () => {
1313
const { mode, text, fieldProps } = props;
14+
const placeholder = fieldProps.placeholder || '请输入';
1415
const render = props.render ?? slots.render;
1516
const renderFormItem = props.renderFormItem ?? slots?.renderFormItem;
1617

@@ -34,7 +35,7 @@ const FieldPassword = defineComponent({
3435
return dom;
3536
}
3637
if (mode === 'edit' || mode === 'update') {
37-
const renderDom = <InputPassword allowClear {...props.fieldProps} />;
38+
const renderDom = <InputPassword {...props.fieldProps} allowClear placeholder={placeholder} />;
3839
if (renderFormItem) {
3940
return renderFormItem(text, { mode, fieldProps }, renderDom);
4041
}

packages/pro-field/src/components/Select/SearchSelect/index.tsx

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,14 @@ import { Select } from 'ant-design-vue';
33
import { searchSelectProps } from './types';
44
import { getSlot } from '@ant-design-vue/pro-utils';
55

6-
export const slots = [
7-
'notFoundContent',
8-
'suffixIcon',
9-
'itemIcon',
10-
'removeIcon',
11-
'clearIcon',
12-
'dropdownRender',
13-
'option',
14-
'placeholder',
15-
'tagRender',
16-
'maxTagPlaceholder',
17-
'optionLabel',
18-
'default',
19-
];
6+
export const slots = ['default'];
207

218
const SearchSelect = defineComponent({
229
props: searchSelectProps,
2310
slots,
2411
setup(props, { slots }) {
2512
const searchValue = ref(props.searchValue);
2613

27-
const notFoundContent = getSlot(slots, props, 'notFoundContent');
28-
const suffixIcon = getSlot(slots, props, 'suffixIcon');
29-
const itemIcon = getSlot(slots, props, 'itemIcon');
30-
const removeIcon = getSlot(slots, props, 'removeIcon');
31-
const clearIcon = getSlot(slots, props, 'clearIcon');
32-
const dropdownRender = getSlot(slots, props, 'dropdownRender');
33-
const option = getSlot(slots, props, 'option');
34-
const placeholder = getSlot(slots, props, 'placeholder');
35-
const tagRender = getSlot(slots, props, 'tagRender');
36-
const maxTagPlaceholder = getSlot(slots, props, 'maxTagPlaceholder');
37-
const optionLabel = getSlot(slots, props, 'optionLabel');
3814
const children = getSlot(slots, props, 'default');
3915

4016
return () => {
@@ -43,6 +19,7 @@ const SearchSelect = defineComponent({
4319
labelInValue,
4420
autoClearSearchValue = true,
4521
showSearch,
22+
placeholder,
4623
onSearch,
4724
onClear,
4825
fetchData,
@@ -52,22 +29,12 @@ const SearchSelect = defineComponent({
5229
return (
5330
<Select
5431
v-slots={{
55-
notFoundContent,
56-
suffixIcon,
57-
itemIcon,
58-
removeIcon,
59-
clearIcon,
60-
dropdownRender,
61-
option,
62-
placeholder,
63-
tagRender,
64-
maxTagPlaceholder,
65-
optionLabel,
6632
default: children,
6733
}}
6834
autoClearSearchValue={autoClearSearchValue}
6935
{...restProps}
7036
allowClear
37+
placeholder={placeholder || '请选择'}
7138
searchValue={searchValue.value}
7239
onClear={() => {
7340
onClear?.();

packages/pro-field/src/components/Text/index.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import { defineComponent, type App, type Plugin, type DefineComponent } from 'vue';
22
import { Input } from 'ant-design-vue';
3-
import { textFieldPorps, type TextFieldPorps } from './types';
3+
import { textFieldProps, type TextFieldProps } from './types';
44
import 'ant-design-vue/es/input/style/index.less';
55

66
const FieldText = defineComponent({
77
name: 'FieldText',
88
inheritAttrs: false,
9-
props: textFieldPorps,
9+
props: textFieldProps,
1010
slots: ['render', 'renderFormItem'],
1111
setup(props, { slots }) {
1212
return () => {
1313
const { type, mode, text, emptyText, fieldProps } = props;
14+
const placeholder = fieldProps.placeholder || '请输入';
1415
const render = props.render ?? slots?.render;
1516
const renderFormItem = props.renderFormItem ?? slots?.renderFormItem;
1617
if (mode === 'read') {
@@ -27,7 +28,7 @@ const FieldText = defineComponent({
2728
return dom;
2829
}
2930
if (mode === 'edit' || mode === 'update') {
30-
const renderDom = <Input type={type} allowClear {...fieldProps} />;
31+
const renderDom = <Input {...fieldProps} type={type} allowClear placeholder={placeholder} />;
3132
if (renderFormItem) {
3233
return renderFormItem(text, { mode, fieldProps }, renderDom);
3334
}
@@ -43,4 +44,4 @@ FieldText.install = (app: App) => {
4344
return app;
4445
};
4546

46-
export default FieldText as DefineComponent<TextFieldPorps> & Plugin;
47+
export default FieldText as DefineComponent<TextFieldProps> & Plugin;

packages/pro-field/src/components/Text/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { InputProps } from 'ant-design-vue/es/input/inputProps';
33
import type { VueNode } from '@ant-design-vue/pro-utils';
44
import { proFieldFC } from '../typings';
55

6-
export const textFieldPorps = {
6+
export const textFieldProps = {
77
...proFieldFC,
88
// 这里预留一个原生的input type属性
99
type: {
@@ -15,4 +15,4 @@ export const textFieldPorps = {
1515
},
1616
};
1717

18-
export type TextFieldPorps = Partial<ExtractPropTypes<typeof textFieldPorps>>;
18+
export type TextFieldProps = Partial<ExtractPropTypes<typeof textFieldProps>>;

packages/pro-field/src/index.tsx

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,21 @@ export {
4747
};
4848

4949
// pro-field
50-
import { textFieldPorps, type TextFieldPorps } from './components/Text/types';
50+
import { textFieldProps, type TextFieldProps } from './components/Text/types';
5151
import FieldText from './components/Text';
52-
export { FieldText, textFieldPorps, type TextFieldPorps };
52+
export { FieldText, textFieldProps, type TextFieldProps };
5353

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

5858
import { searchSelectProps, type SearchSelectProps } from './components/Select/SearchSelect/types';
5959
import FieldSelect from './components/Select';
60-
import { slots as searchSelectSlots } from './components/Select/SearchSelect';
61-
export { FieldSelect, searchSelectProps, searchSelectSlots, type SearchSelectProps };
60+
export { FieldSelect, searchSelectProps, type SearchSelectProps };
61+
62+
import { fieldDatePickerProps, type FieldDatePickerProps } from './components/DatePicker/types';
63+
import FieldDatePicker, { slots as fieldDatePickerSlots } from './components/DatePicker';
64+
export { FieldDatePicker, fieldDatePickerProps, fieldDatePickerSlots, FieldDatePickerProps };
6265

6366
// style
6467
import './default.less';
@@ -100,6 +103,21 @@ const defaultRenderText = (
100103
props: RenderProps
101104
// valueTypeMap: Record<string, ProRenderFieldPropsType>
102105
): VueNode => {
106+
if (valueType === 'date') {
107+
const { fieldProps } = props;
108+
return (
109+
<FieldDatePicker
110+
dateFormat="YYYY-MM-DD"
111+
fieldProps={{
112+
...fieldProps,
113+
mode: 'date',
114+
picker: 'date',
115+
}}
116+
{...props}
117+
text={dataValue as string}
118+
/>
119+
);
120+
}
103121
if (valueType === 'select') {
104122
let text = '';
105123
if (dataValue instanceof Array) {
@@ -143,7 +161,7 @@ const ProField = defineComponent({
143161
const omitFieldProps = omitUndefined({
144162
...fieldProps,
145163
value: unref(inputValue),
146-
'onUpdate:value'(value: string) {
164+
'onUpdate:value'(value: any) {
147165
inputValue.value = value;
148166
fieldProps?.['onUpdate:value']?.(value);
149167
},

packages/pro-form/examples/views/ProForm.vue

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,25 +139,40 @@
139139
name="lang"
140140
label="语言"
141141
:field-props="{
142-
placeholder: '请选择',
142+
placeholder: '请选择语言',
143143
}"
144144
>
145145
<SelectOption v-for="lang in langs" :key="lang.value" :value="lang.value">
146146
<span role="img" :aria-label="lang.value">{{ lang.icon }}</span
147147
>&nbsp;&nbsp;{{ lang.label }}</SelectOption
148148
>
149+
<template #suffixIcon>
150+
<plus-outlined />
151+
</template>
149152
</pro-form-select>
150153
<pro-form-select
151154
name="country"
152155
label="国家"
153156
:field-props="{
154-
placeholder: '请选择',
155157
showSearch: true,
156158
mode: 'multiple',
157159
filterOption: false,
158160
}"
159161
:request="fetchUser"
160-
/>
162+
>
163+
<template #placeholder> 请选择国家 </template>
164+
</pro-form-select>
165+
<pro-form-date-picker
166+
name="expirationTime"
167+
label="合同失效时间"
168+
:field-props="{
169+
placeholder: '请选择合同失效时间',
170+
}"
171+
>
172+
<template #superPrevIcon>
173+
<plus-outlined />
174+
</template>
175+
</pro-form-date-picker>
161176
</pro-form>
162177
</template>
163178

@@ -166,7 +181,7 @@ import { reactive, ref, FunctionalComponent } from 'vue';
166181
import { PlusOutlined } from '@ant-design/icons-vue';
167182
import { RadioGroup, RadioButton, Switch, Divider, SelectOption, type SelectProps } from 'ant-design-vue';
168183
import type { FormLayout } from 'ant-design-vue/es/form/Form';
169-
import { ProForm, ProFormText, ProFormPassword, ProFormSelect } from '@ant-design-vue/pro-form';
184+
import { ProForm, ProFormText, ProFormPassword, ProFormSelect, ProFormDatePicker } from '@ant-design-vue/pro-form';
170185
171186
let lastFetchId = 0;
172187
@@ -201,6 +216,7 @@ const formModel = reactive({
201216
girlName: undefined,
202217
lang: undefined,
203218
country: undefined,
219+
expirationTime: undefined,
204220
});
205221
206222
const sex = ref([

packages/pro-form/src/BaseForm/hooks/useFormMethods.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { toRaw, isProxy } from 'vue';
21
import { proxyToRaw } from '@ant-design-vue/pro-utils';
32
import type { Recordable } from '../../typings';
43

0 commit comments

Comments
 (0)