hookehuyr

✨ feat(预约时间控件): 自定义表单项钩子函数改造

1 +<!--
2 + * @Date: 2023-03-28 15:38:09
3 + * @LastEditors: hookehuyr hookehuyr@gmail.com
4 + * @LastEditTime: 2023-03-28 16:10:58
5 + * @FilePath: /data-table/src/components/AppointmentField/MyComponent.vue
6 + * @Description: 自定义组件
7 +-->
8 +<template>
9 + <div style="width: 100%;">
10 + <van-row v-for="(opt, index) in props.component_props.options" :key="index">
11 + <van-col span="7">
12 + <div style="font-size: 1rem; line-height: 3;">{{ opt.title }}</div>
13 + </van-col>
14 + <van-col span="17">
15 + <van-field
16 + v-model="opt.value"
17 + is-link
18 + readonly
19 + :placeholder="opt.placeholder"
20 + @click="onClick(index, opt)"
21 + :border="false"
22 + />
23 + </van-col>
24 + </van-row>
25 + </div>
26 + <van-popup v-model:show="showPicker" position="bottom">
27 + <van-picker
28 + :title="props.component_props.appointment_title"
29 + :columns="columns"
30 + @confirm="onConfirm"
31 + @cancel="showPicker = false"
32 + />
33 + </van-popup>
34 +</template>
35 +
36 +<script setup>
37 +import { inject, ref } from 'vue'
38 +import { useCustomFieldValue } from '@vant/use';
39 +import { styleColor } from "@/constant.js";
40 +import { showDialog } from 'vant';
41 +
42 +// 获取父组件传值
43 +const props = inject('props');
44 +
45 +const showPicker = ref(false);
46 +const picker_value = ref('');
47 +const columns = ref([]);
48 +const current_index = ref(0);
49 +
50 +const onClick = (index, opt) => {
51 + if (opt.disabled) {
52 + showDialog({
53 + title: '温馨提示',
54 + message: '暂时不能预约!',
55 + theme: 'round-button',
56 + width: '320px',
57 + confirmButtonColor: styleColor.baseColor
58 + }).then(() => {
59 + // on close
60 + });
61 + return false;
62 + }
63 + current_index.value = index;
64 + columns.value = props.component_props.options[index]['columns'];
65 + showPicker.value = true;
66 +}
67 +
68 +const onConfirm = ({ selectedOptions }) => {
69 + props.component_props.options.forEach(item => {
70 + item.value = ''
71 + })
72 + props.component_props.options[current_index.value]['value'] = selectedOptions[0]?.text;
73 + picker_value.value = selectedOptions[0]?.value;
74 + showPicker.value = false;
75 +};
76 +
77 +// 此处传入的值会替代 Field 组件内部的 value
78 +useCustomFieldValue(() => picker_value.value);
79 +</script>
80 +
81 +<style lang="less" scoped>
82 +
83 +:deep(.van-cell--clickable) {
84 + border: 1px solid #eaeaea;
85 + border-radius: 0.25rem;
86 + padding: 0.25rem 0.5rem;
87 + margin-top: 0.5rem;
88 +}
89 +</style>
1 <!-- 1 <!--
2 * @Date: 2022-08-29 14:31:20 2 * @Date: 2022-08-29 14:31:20
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2023-03-27 17:52:50 4 + * @LastEditTime: 2023-03-28 16:16:47
5 * @FilePath: /data-table/src/components/AppointmentField/index.vue 5 * @FilePath: /data-table/src/components/AppointmentField/index.vue
6 - * @Description: 描述文本控件 6 + * @Description: 预约时间控件
7 --> 7 -->
8 <template> 8 <template>
9 <div class="Appointment-field-page"> 9 <div class="Appointment-field-page">
...@@ -11,99 +11,46 @@ ...@@ -11,99 +11,46 @@
11 <span v-if="item.component_props.required">&nbsp;*</span> 11 <span v-if="item.component_props.required">&nbsp;*</span>
12 {{ item.component_props.label }} 12 {{ item.component_props.label }}
13 </div> 13 </div>
14 - <van-row v-for="(opt, index) in item.component_props.options" :key="index" style="padding: 0 1rem 0rem 1rem;"> 14 + <van-field :name="item.name" :rules="rules">
15 - <van-col span="6"> 15 + <template #input>
16 - <div style="font-size: 1rem; line-height: 3;">{{ opt.title }}</div> 16 + <my-component />
17 - </van-col> 17 + </template>
18 - <van-col span="18"> 18 + </van-field>
19 - <van-field
20 - v-model="opt.value"
21 - is-link
22 - readonly
23 - :placeholder="opt.placeholder"
24 - @click="onClick(index, opt)"
25 - :border="false"
26 - style="width: 100%;"
27 - />
28 - </van-col>
29 - </van-row>
30 - <div
31 - v-if="show_empty"
32 - class="van-field__error-message"
33 - style="padding: 0 1rem 1rem 1rem"
34 - >
35 - 预约时间不能为空
36 - </div>
37 </div> 19 </div>
38 - <van-popup v-model:show="showPicker" position="bottom">
39 - <van-picker
40 - :title="item.component_props.appointment_title"
41 - :columns="columns"
42 - @confirm="onConfirm"
43 - @cancel="showPicker = false"
44 - />
45 - </van-popup>
46 </template> 20 </template>
47 21
48 <script setup> 22 <script setup>
49 -import { styleColor } from "@/constant.js"; 23 +import { provide } from 'vue'
50 -import { showDialog } from 'vant'; 24 +import MyComponent from './MyComponent.vue';
51 25
52 const props = defineProps({ 26 const props = defineProps({
53 item: Object, 27 item: Object,
54 }); 28 });
55 -const emit = defineEmits(["active"]);
56 -const showPicker = ref(false);
57 -const picker_value = ref(props.item.component_props.default);
58 -const columns = ref([])
59 -const current_index = ref(0)
60 -const show_empty = ref(false);
61 -
62 -const onClick = (index, opt) => {
63 - if (opt.disabled) {
64 - showDialog({
65 - title: '温馨提示',
66 - message: '暂时不能预约!',
67 - theme: 'round-button',
68 - width: '320px',
69 - confirmButtonColor: styleColor.baseColor
70 - }).then(() => {
71 - // on close
72 - });
73 - return false;
74 - }
75 - current_index.value = index;
76 - columns.value = props.item.component_props.options[index]['columns'];
77 - showPicker.value = true
78 -}
79 29
80 -const onConfirm = ({ selectedOptions }) => {
81 - props.item.component_props.options.forEach(item => {
82 - item.value = ''
83 - })
84 - props.item.component_props.options[current_index.value]['value'] = selectedOptions[0]?.text;
85 - picker_value.value = selectedOptions[0]?.value;
86 - showPicker.value = false;
87 - // 触发点自定义监听事件,配合规则显示隐藏其他字段
88 - props.item.value = { key: props.item.key, value: picker_value.value, type: "appointment" };
89 - emit("active", props.item.value);
90 -};
91 // 隐藏显示 30 // 隐藏显示
92 const HideShow = computed(() => { 31 const HideShow = computed(() => {
93 return !props.item.component_props.disabled 32 return !props.item.component_props.disabled
94 }) 33 })
95 34
96 -const validAppointment = () => { 35 +// 注入子组件属性
97 - // 必填项 36 +provide('props', props.item);
98 - if (props.item.component_props.required && !picker_value.value) { 37 +
99 - show_empty.value = true; 38 +// 规则校验
39 +const required = props.item.component_props.required;
40 +const validator = (val) => {
41 + if (required && !val) {
42 + return false;
100 } else { 43 } else {
101 - show_empty.value = false; 44 + return true;
102 } 45 }
103 - return !show_empty.value;
104 }; 46 };
105 - 47 +// 错误提示文案
106 -defineExpose({ validAppointment }); 48 +const validatorMessage = (val, rule) => {
49 + if (required && !val) {
50 + return "必填项不能为空";
51 + }
52 +};
53 +const rules = [{ validator, message: validatorMessage }];
107 </script> 54 </script>
108 55
109 <style lang="less" scoped> 56 <style lang="less" scoped>
...@@ -123,10 +70,4 @@ defineExpose({ validAppointment }); ...@@ -123,10 +70,4 @@ defineExpose({ validAppointment });
123 // border-radius: 0.25rem; 70 // border-radius: 0.25rem;
124 // padding: 0.25rem 0.5rem; 71 // padding: 0.25rem 0.5rem;
125 // } 72 // }
126 -:deep(.van-cell--clickable) {
127 - border: 1px solid #eaeaea;
128 - border-radius: 0.25rem;
129 - padding: 0.25rem 0.5rem;
130 - margin-top: 0.5rem;
131 -}
132 </style> 73 </style>
......