automated_uniapp/uni_modules/cool-ui/components/cl-form/cl-form.vue

245 lines
4.5 KiB
Vue
Raw Normal View History

2025-01-09 16:16:11 +08:00
<template>
<view
:class="[
'cl-form',
{
'is-border': border,
},
]"
>
<slot></slot>
<!-- 提示 -->
<cl-toast :ref="setRefs('toast')"></cl-toast>
</view>
</template>
<script lang="ts">
import { defineComponent, getCurrentInstance, ref, watch, type PropType } from "vue";
import { cloneDeep, isArray, isEmpty } from "lodash-es";
import { useCool } from "/@/cool";
import AsyncValidator from "../../utils/async-validator";
export default defineComponent({
name: "cl-form",
props: {
// 表单数据对象
modelValue: {
type: Object,
default: () => {
return {};
},
},
// 表单验证规则
rules: Object,
// 是否带有边框
border: Boolean,
// 是否禁用
disabled: Boolean,
// 水平布局
justify: String as PropType<"start" | "center" | "end">,
// 消息提示方式
tips: {
type: String as PropType<"toast" | "inner" | "none">,
default: "toast",
},
// 标签的宽度
labelWidth: {
type: [String, Number],
default: 150,
},
// 标签的位置
labelPosition: {
type: String,
default: "left",
},
// 是否在 rules 属性改变后立即触发一次验证
validateOnRuleChange: {
type: Boolean,
default: false,
},
// 是否滚动到错误项
scrollToError: {
type: Boolean,
default: true,
},
},
emits: ["update:modelValue", "change", "reset", "clear"],
setup(props, { emit }) {
const { proxy }: any = getCurrentInstance();
const { refs, setRefs } = useCool();
// 校验关键字
const fields = ref<string[]>([]);
// 表单值
const form = ref<any>({});
// 旧值
const _form = cloneDeep(props.modelValue);
watch(
() => props.modelValue,
(val: any) => {
form.value = val;
},
{
immediate: true,
deep: true,
},
);
// 规则
const rules = ref<any>({});
// 设置规则
function setRules(value: any) {
rules.value = value || {};
}
// 监听规则变化
watch(() => props.rules, setRules, {
immediate: true,
deep: true,
});
// 添加校验关键字
function addField(value: string, rule?: any) {
const item: string | unknown = fields.value.find((e: string) => e == value);
if (!item && value) {
fields.value.push(value);
// 添加规则
if (rule) {
rules.value[value] = rule;
}
}
}
// 移除校验关键字
function removeField(value: string) {
fields.value.splice(fields.value.indexOf(value), 1);
}
// 校验表单
function validate(callback: Function) {
if (!props.disabled) {
validateField(fields.value, (valid: boolean, errors: any[], fields: any) => {
if (callback) {
callback(valid, errors);
}
if (!valid) {
const { field, message } = errors[0];
if (props.scrollToError) {
proxy.__children.forEach((e: any) => {
e.scrollTo(field);
});
}
switch (props.tips) {
case "toast":
refs.toast.open({
message,
icon: "cl-icon-toast-warning",
});
break;
case "inner":
proxy.__children.forEach((e: any) => {
e.onError(errors);
});
break;
}
}
});
}
}
// 根据字段校验表单
function validateField(value: string[] | string, callback: Function) {
if (!isEmpty(value)) {
const r: any = {};
fields.value.forEach((e) => {
if (rules.value[e]) {
r[e] = rules.value[e];
}
});
//@ts-ignore
const validator = new AsyncValidator(r);
const values: any = isArray(value) ? value : [value];
const data: any = {};
values.forEach((e: string) => {
let d = form.value;
if (e) {
if (e.includes(".")) {
e.split(".").forEach((e) => {
d = d[e];
});
} else {
d = d[e];
}
data[e] = d;
}
});
validator.validate(data, (errors: any[]) => {
if (callback) {
callback(!errors, errors);
}
});
} else {
callback(true, []);
}
}
// 重置表单
function reset() {
form.value = cloneDeep(_form);
emit("update:modelValue", form.value);
emit("reset");
clearValidate();
}
// 清空表单
function clear() {
form.value = {};
emit("update:modelValue", form.value);
emit("clear");
clearValidate();
}
// 移除表单校验结果
function clearValidate() {
(proxy.__children || []).forEach((e: any) => {
e.clearValidate();
});
}
return {
refs,
setRefs,
form,
rules,
setRules,
validate,
validateField,
reset,
clear,
clearValidate,
addField,
removeField,
};
},
});
</script>