hookehuyr

✨ feat: 新增表单预约时间控件

......@@ -7,11 +7,14 @@ export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
Appointment: typeof import('./src/components/Appointment/index.vue')['default']
AppointmentField: typeof import('./src/components/AppointmentField/index.vue')['default']
AreaPickerField: typeof import('./src/components/AreaPickerField/index.vue')['default']
ButtonField: typeof import('./src/components/ButtonField/index.vue')['default']
CalendarField: typeof import('./src/components/CalendarField/index.vue')['default']
CheckboxField: typeof import('./src/components/CheckboxField/index.vue')['default']
ContactField: typeof import('./src/components/ContactField/index.vue')['default']
copy: typeof import('./src/components/DesField copy/index.vue')['default']
DatePickerField: typeof import('./src/components/DatePickerField/index.vue')['default']
DateTimePickerField: typeof import('./src/components/DateTimePickerField/index.vue')['default']
DesField: typeof import('./src/components/DesField/index.vue')['default']
......@@ -48,11 +51,13 @@ declare module '@vue/runtime-core' {
VanCol: typeof import('vant/es')['Col']
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
VanDatePicker: typeof import('vant/es')['DatePicker']
VanDialog: typeof import('vant/es')['Dialog']
VanDivider: typeof import('vant/es')['Divider']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
VanIcon: typeof import('vant/es')['Icon']
VanImage: typeof import('vant/es')['Image']
VanInput: typeof import('vant/es')['Input']
VanLoading: typeof import('vant/es')['Loading']
VanNoticeBar: typeof import('vant/es')['NoticeBar']
VanNumberKeyboard: typeof import('vant/es')['NumberKeyboard']
......
<!--
* @Date: 2022-08-29 14:31:20
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-03-27 17:52:50
* @FilePath: /data-table/src/components/AppointmentField/index.vue
* @Description: 描述文本控件
-->
<template>
<div class="Appointment-field-page">
<div class="label">
<span v-if="item.component_props.required">&nbsp;*</span>
{{ item.component_props.label }}
</div>
<van-row v-for="(opt, index) in item.component_props.options" :key="index" style="padding: 0 1rem 0rem 1rem;">
<van-col span="6">
<div style="font-size: 1rem; line-height: 3;">{{ opt.title }}</div>
</van-col>
<van-col span="18">
<van-field
v-model="opt.value"
is-link
readonly
:placeholder="opt.placeholder"
@click="onClick(index, opt)"
:border="false"
style="width: 100%;"
/>
</van-col>
</van-row>
<div
v-if="show_empty"
class="van-field__error-message"
style="padding: 0 1rem 1rem 1rem"
>
预约时间不能为空
</div>
</div>
<van-popup v-model:show="showPicker" position="bottom">
<van-picker
:title="item.component_props.appointment_title"
:columns="columns"
@confirm="onConfirm"
@cancel="showPicker = false"
/>
</van-popup>
</template>
<script setup>
import { styleColor } from "@/constant.js";
import { showDialog } from 'vant';
const props = defineProps({
item: Object,
});
const emit = defineEmits(["active"]);
const showPicker = ref(false);
const picker_value = ref(props.item.component_props.default);
const columns = ref([])
const current_index = ref(0)
const show_empty = ref(false);
const onClick = (index, opt) => {
if (opt.disabled) {
showDialog({
title: '温馨提示',
message: '暂时不能预约!',
theme: 'round-button',
width: '320px',
confirmButtonColor: styleColor.baseColor
}).then(() => {
// on close
});
return false;
}
current_index.value = index;
columns.value = props.item.component_props.options[index]['columns'];
showPicker.value = true
}
const onConfirm = ({ selectedOptions }) => {
props.item.component_props.options.forEach(item => {
item.value = ''
})
props.item.component_props.options[current_index.value]['value'] = selectedOptions[0]?.text;
picker_value.value = selectedOptions[0]?.value;
showPicker.value = false;
// 触发点自定义监听事件,配合规则显示隐藏其他字段
props.item.value = { key: props.item.key, value: picker_value.value, type: "appointment" };
emit("active", props.item.value);
};
// 隐藏显示
const HideShow = computed(() => {
return !props.item.component_props.disabled
})
const validAppointment = () => {
// 必填项
if (props.item.component_props.required && !picker_value.value) {
show_empty.value = true;
} else {
show_empty.value = false;
}
return !show_empty.value;
};
defineExpose({ validAppointment });
</script>
<style lang="less" scoped>
.Appointment-field-page {
.label {
padding: 1rem 1rem 0 1rem;
font-size: 0.9rem;
font-weight: bold;
span {
color: red;
}
}
}
// :deep(.van-field__body) {
// border: 1px solid #eaeaea;
// border-radius: 0.25rem;
// padding: 0.25rem 0.5rem;
// }
:deep(.van-cell--clickable) {
border: 1px solid #eaeaea;
border-radius: 0.25rem;
padding: 0.25rem 0.5rem;
margin-top: 0.5rem;
}
</style>
<!--
* @Date: 2022-08-30 13:46:51
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-03-03 21:11:24
* @LastEditTime: 2023-03-27 16:55:35
* @FilePath: /data-table/src/components/PickerField/index.vue
* @Description: 单列选择器组件
-->
......
<!--
* @Date: 2022-09-08 15:47:54
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-01-31 22:57:40
* @LastEditTime: 2023-03-27 17:14:53
* @FilePath: /data-table/src/components/RatePickerField/index.vue
* @Description: 评分选择控件
-->
......
......@@ -29,6 +29,7 @@ import ButtonField from '@/components/ButtonField/index.vue'
import NoteField from '@/components/NoteField/index.vue';
import NameField from '@/components/NameField/index.vue';
import GenderField from '@/components/GenderField/index.vue';
import AppointmentField from '@/components/AppointmentField/index.vue';
/**
* 生成自定义组件类型
......@@ -58,6 +59,7 @@ import GenderField from '@/components/GenderField/index.vue';
* @type note 富文本控件 NoteField
* @type name 姓名控件 NameField
* @type gender 性别控件 GenderField
* @type appointment 预约控件 AppointmentField
*/
export function createComponentType(data) {
// 判断类型和使用组件
......@@ -178,5 +180,9 @@ export function createComponentType(data) {
item.name = item.key;
item.component = GenderField;
}
if (item.component_props.tag === 'appointment') {
item.name = item.key;
item.component = AppointmentField;
}
})
}
......
<!--
* @Date: 2022-07-18 10:22:22
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-03-14 14:41:17
* @LastEditTime: 2023-03-27 18:30:02
* @FilePath: /data-table/src/views/index.vue
* @Description: 首页
-->
......@@ -26,13 +26,13 @@
<van-cell-group :border="false">
<component v-for="(item, index) in formData" :id="item.key" :ref="(el) => setRefMap(el, item)" :key="index"
:is="item.component" :item="item" @active="onActive" />
</van-cell-group>
<div v-if="formData.length && PCommit.visible" style="margin: 16px">
<van-button round block type="primary" native-type="submit">
{{ PCommit.text ? PCommit.text : '提交' }}
</van-button>
</div>
<!-- <van-cell-group :border="false">
</van-cell-group>
<div v-if="formData.length && PCommit.visible" style="margin: 16px">
<van-button round block type="primary" native-type="submit">
{{ PCommit.text ? PCommit.text : '提交' }}
</van-button>
</div>
<!-- <van-cell-group :border="false">
<component
v-for="(item, index) in mockData"
:id="item.key"
......@@ -42,12 +42,12 @@
:item="item"
@active="onActive"
/>
</van-cell-group>
<div v-if="mockData.length && PCommit.visible" style="margin: 16px">
<van-button round block type="primary" native-type="submit">
{{ PCommit.text ? PCommit.text : '提交' }}
</van-button>
</div> -->
</van-cell-group>
<div v-if="mockData.length && PCommit.visible" style="margin: 16px">
<van-button round block type="primary" native-type="submit">
{{ PCommit.text ? PCommit.text : '提交' }}
</van-button>
</div> -->
</van-form>
</van-config-provider>
</div>
......@@ -159,6 +159,7 @@ const image_uploader = ref([]);
const file_uploader = ref([]);
const sign = ref([]);
const rate_picker = ref([]);
const appointment = ref([]);
// 动态绑定ref数据
const setRefMap = (el, item) => {
if (el) {
......@@ -177,6 +178,9 @@ const setRefMap = (el, item) => {
if (item.component_props.tag === "rate_picker") {
rate_picker.value.push(el);
}
if (item.component_props.tag === "appointment") {
appointment.value.push(el);
}
}
};
......@@ -248,26 +252,66 @@ onMounted(async () => {
formData.value = formatData(page_form);
mockData.value = [
{
key: "111",
value: "",
component: "",
component_props: {
name: "name",
tag: "name",
label: "姓名",
required: true,
},
},
{
key: "222",
key: "field_1",
value: "",
component: "",
component_props: {
name: "gender",
tag: "gender",
label: "性别",
default: '',
name: "appointment",
tag: "appointment",
label: "预约时间",
default: '',
required: true,
placeholder: '',
appointment_title: '选择入寺时间',
options: [{
title: '03月27日',
placeholder: '剩余余量 9878',
value: '',
disabled: false,
columns: [{
checked : false,
disabled : false,
value: '1',
text : "16:00-17:30 余1399",
}, {
checked : false,
disabled : true,
value: '2',
text : "18:00-19:30 余1399",
}]
}, {
title: '03月28日',
placeholder: '剩余余量 9878',
value: '',
disabled: false,
columns: [{
checked : false,
disabled : true,
value: '3',
text : "16:00-17:30 余1399",
}, {
checked : false,
disabled : false,
value: '4',
text : "16:00-17:30 余1399",
}]
}, {
title: '03月28日',
placeholder: '等待预约(提前一天)',
value: '',
disabled: true,
columns: [{
checked : false,
disabled : true,
value: '5',
text : "12:00-13:30 余1399",
}, {
checked : false,
disabled : false,
value: '6',
text : "14:00-15:30 余1399",
}]
}]
},
},
];
......@@ -404,6 +448,9 @@ const onActive = (item) => {
if (item.type === "picker") { // 下拉框控件
postData.value = _.assign(postData.value, { [item.key]: item.value });
}
if (item.type === "appointment") { // 预约控件
postData.value = _.assign(postData.value, { [item.key]: item.value });
}
if (item.type === "radio") { // 单选控件
postData.value = _.assign(postData.value, { [item.key]: item.affix ? item.affix : item.value });
}
......@@ -488,6 +535,18 @@ const validOther = () => {
}
});
}
if (appointment.value) {
// 预约时间控件
appointment.value.forEach((item, index) => {
if (!appointment.value[index].validAppointment()) {
valid = {
status: appointment.value[index].validAppointment(),
key: "appointment",
};
return false;
}
});
}
return valid;
};
......