hookehuyr

fix(表单验证): 改进表单验证失败处理和身份证输入组件验证逻辑

添加表单验证失败的调试信息和更健壮的错误处理,确保即使没有错误信息也能显示合理的提示
重构身份证输入组件,移除键盘相关代码,添加输入和变化事件处理,改进验证逻辑和调试信息
<!--
* @Date: 2022-09-14 14:44:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-11-21 10:39:09
* @LastEditTime: 2025-10-07 10:44:04
* @FilePath: /data-table/src/components/IdentityField/index.vue
* @Description: 身份证输入控件
-->
......@@ -43,13 +43,15 @@
:readonly="item.component_props.readonly"
:border="false"
@blur="onBlur(item)"
@input="onInput"
@change="onChange"
>
<template #button>
<van-button size="small" type="primary" v-if="IdEditShow" @click="clickEdit()">编辑</van-button>
</template>
</van-field>
<!-- <div v-if="gender" class="gender"><span>性别:</span>{{ gender }}</div> -->
<van-number-keyboard
<!-- <van-number-keyboard
v-model="item.value"
:show="show"
extra-key="X"
......@@ -58,7 +60,7 @@
@input="onInput"
@delete="onDelete"
safe-area-inset-bottom
/>
/> -->
</div>
</template>
......@@ -70,6 +72,7 @@ import { showSuccessToast, showFailToast, showConfirmDialog } from "vant";
// import idCard from "idcard";
import { styleColor } from "@/constant.js";
import Cookies from 'js-cookie';
import { nextTick } from 'vue';
const $route = useRoute();
const props = defineProps({
......@@ -219,79 +222,120 @@ const clickRightIcon = () => { // 编辑模式
fieldRef.value?.focus();
})
}
const openKeyboard = (e) => {
if (readonly || e.target.className.indexOf('edit') > 0 || edit_mode.value) return false; // 如果为只读或者编辑模式,不能设置
// // 键盘上移动
// const target_to_view_height = window.innerHeight - e.target.getBoundingClientRect().y; // 元素到适口高度
// const target_top = document.body.scrollHeight - $(e.target).offset().top; // 元素到正文高度
// let scroll_height = "";
// console.warn(target_top);
// if (target_top < 250) {
// document.getElementById("app").style.paddingBottom = "250px";
// window.scrollTo(0, $("#app").height());
// } else {
// // 向上滚动位置
// document.documentElement.scrollTop = (target_top > 250 ? 0 : target_top) + 250;
// }
// 键盘上移动
const target_to_view_height =
window.innerHeight - e.target.getBoundingClientRect().bottom; // 元素到适口高度
const target_top = document.body.scrollHeight - $(e.target).offset().top; // 元素到正文高度
let scroll_height = "";
if (target_to_view_height <= 250) {
document.getElementById("app").style.paddingBottom = "250px";
// 向上滚动位置
document.documentElement.scrollTop = $(e.target).offset().top - 244;
}
// 选中添加border颜色
content = $(e.target).parent();
// TAG: 自定义主题颜色
content.css("border-color", "#c2915f");
setTimeout(() => {
show.value = true;
}, 300);
// 记录点击field名
store.changeFieldName(props.item.name);
};
const blurKeyboard = () => {
show.value = false;
document.getElementById("app").style.paddingBottom = "0";
// 还原border颜色
content.css("border-color", "#eaeaea");
// 键盘失焦检查输入和添加性别显示
const input_val = props.item.value;
if (required && !input_val) {
showFailToast("身份证号码不能为空");
} else if (input_val && !idCard.verify(input_val)) {
showFailToast("请输入正确身份证号码");
} else {
// gender.value = getGenderByIdNumber(input_val)
}
};
// const openKeyboard = (e) => {
// if (readonly || e.target.className.indexOf('edit') > 0 || edit_mode.value) return false; // 如果为只读或者编辑模式,不能设置
// // // 键盘上移动
// // const target_to_view_height = window.innerHeight - e.target.getBoundingClientRect().y; // 元素到适口高度
// // const target_top = document.body.scrollHeight - $(e.target).offset().top; // 元素到正文高度
// // let scroll_height = "";
// // console.warn(target_top);
// // if (target_top < 250) {
// // document.getElementById("app").style.paddingBottom = "250px";
// // window.scrollTo(0, $("#app").height());
// // } else {
// // // 向上滚动位置
// // document.documentElement.scrollTop = (target_top > 250 ? 0 : target_top) + 250;
// // }
// // 键盘上移动
// const target_to_view_height =
// window.innerHeight - e.target.getBoundingClientRect().bottom; // 元素到适口高度
// const target_top = document.body.scrollHeight - $(e.target).offset().top; // 元素到正文高度
// let scroll_height = "";
// if (target_to_view_height <= 250) {
// document.getElementById("app").style.paddingBottom = "250px";
// // 向上滚动位置
// document.documentElement.scrollTop = $(e.target).offset().top - 244;
// }
// // 选中添加border颜色
// content = $(e.target).parent();
// // TAG: 自定义主题颜色
// content.css("border-color", "#c2915f");
// setTimeout(() => {
// show.value = true;
// }, 300);
// // 记录点击field名
// store.changeFieldName(props.item.name);
// };
// const blurKeyboard = () => {
// show.value = false;
// document.getElementById("app").style.paddingBottom = "0";
// // 还原border颜色
// content.css("border-color", "#eaeaea");
// // 键盘失焦检查输入和添加性别显示
// const input_val = props.item.value;
// if (required && !input_val) {
// showFailToast("身份证号码不能为空");
// } else if (input_val && !idCard.verify(input_val)) {
// showFailToast("请输入正确身份证号码");
// } else {
// // gender.value = getGenderByIdNumber(input_val)
// }
// };
// 校验函数返回 true 表示校验通过,false 表示不通过
// 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
const required = props.item.component_props.required;
const validator = (val) => {
if (required && !val) {
// 添加调试信息,帮助排查问题
console.log('身份证验证器被调用:', {
value: val,
type: typeof val,
required: required,
isEmpty: !val,
length: val ? val.length : 0
});
// 确保val是字符串类型
const valStr = String(val || '');
if (required && !valStr) {
console.log('验证失败: 必填项为空');
return false;
} else if (val && !idCard.verify(val)) {
} else if (valStr && !idCard.verify(valStr)) {
console.log('验证失败: 身份证格式不正确');
return false;
} else {
console.log('验证通过');
return true;
}
};
// 错误提示文案
const validatorMessage = (val, rule) => {
if (required && !val) {
const valStr = String(val || '');
if (required && !valStr) {
return "身份证号码不能为空";
} else if (val && !idCard.verify(val)) {
} else if (valStr && !idCard.verify(valStr)) {
return "请输入正确身份证号码";
}
};
const rules = [{ validator, message: validatorMessage }];
const onInput = (value) => {};
const rules = [{
validator,
message: validatorMessage,
trigger: 'onBlur' // 明确指定触发时机
}];
const onInput = (value) => {
console.log('身份证输入事件触发:', value);
// 触发验证
nextTick(() => {
if (fieldRef.value) {
fieldRef.value.validate();
}
});
};
const onChange = (value) => {
console.log('身份证值变化事件触发:', value);
// 触发验证
nextTick(() => {
if (fieldRef.value) {
fieldRef.value.validate();
}
});
};
const onDelete = () => {};
const gender = ref('');
......
......@@ -1301,7 +1301,18 @@ const onSubmit = async (values) => { // 表单提交回调
};
const onFailed = (errorInfo) => { // 提交表单且验证不通过后触发
console.log('表单验证失败:', errorInfo); // 添加调试信息
// 检查是否有错误信息
if (!errorInfo || !errorInfo.errors || errorInfo.errors.length === 0) {
console.warn('没有具体的错误信息');
showToast('表单验证失败,请检查输入内容');
return;
}
const error_item = errorInfo.errors[0];
console.log('第一个错误项:', error_item); // 添加调试信息
// 通过name找到对应的label
let error_name = '';
formData.value.forEach(item => {
......@@ -1309,7 +1320,13 @@ const onFailed = (errorInfo) => { // 提交表单且验证不通过后触发
error_name = item.component_props.label
}
});
showToast(error_name + ': ' + error_item.message);
// 确保有错误名称和消息
const finalErrorName = error_name || error_item.name || '未知字段';
const finalErrorMessage = error_item.message || '验证失败';
console.log('显示错误提示:', finalErrorName + ': ' + finalErrorMessage);
showToast(finalErrorName + ': ' + finalErrorMessage);
}
// TAG: 监听formData的变化,当有新的字段添加时重新设置监听器
......