- 表单
hook
import type { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
export function useFormFun(data: any) {
/**表单model */
const formState = <any>ref(data);
/**表单校验提示 */
const validateMessages = { required: '${label}不能为空' };
/**表单对象ref */
const formRef = ref<any>();
/**
* @method 设置表单数据
* @param data 需要设置的数据
* @returns void
*/
function setFormStateData(data: Record<string, any>) {
Object.assign(formState.value, data);
console.log(Object.assign(formState.value, data));
}
/**
* @method 表单校验
* @returns Promise<Record<string, any> | ValidateErrorEntity>
*/
async function formValidateFields(): Promise<
Record<string, any> | ValidateErrorEntity
> {
return new Promise<Record<string, any> | ValidateErrorEntity>(
async (resolve, reject) => {
try {
const res = await formRef.value?.validateFields();
resolve(formState.value);
} catch (error: any) {
// alertError(error);
reject(error);
}
}
);
}
/**
* @method 移除表单项的校验结果。传入待移除的表单项的 name 属性或者 name 组成的数组,如不传则移除整个表单的校验结果
* @param nameList 表单对应的name字段组成的数组
* @returns void
*/
function clearValidate(nameList?: string | (string | number)[]) {
if (!nameList) {
nextTick(() => {
formRef.value?.clearValidate();
return;
});
}
if (nameList?.length) {
if (!Array.isArray(nameList)) {
throw new Error('移除表单校验的name必须为一个数组');
} else {
formRef.value?.clearValidate(nameList);
}
}
}
/**
* @method 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
* @param nameList 表单对应的name字段组成的数组
* @returns void
*/
function resetFields(nameList?: string | (string | number)[]) {
if (!nameList) {
formRef.value?.resetFields();
return;
}
if (nameList?.length) {
if (!Array.isArray(nameList)) {
throw new Error('重置的name必须为一个数组');
} else {
formRef.value?.resetFields(nameList);
}
}
}
return {
formRef,
formState,
resetFields,
clearValidate,
validateMessages,
setFormStateData,
formValidateFields,
};
}
配置文件:
export const editItem: SchemaItem[] = [
{
label: '工单类型',
name: 'orderType',
component: 'Select',
componentProps: {
allowClear: true,
placeholder: '工单类型',
options: [
{ value: '1', label: '装维单' },
{ value: '2', label: '勘察单' },
],
},
formItemProps: {
rules: [
{
required: true,
message: '请选择工单类型',
trigger: 'blur',
},
],
},
},
{
label: '需求区域',
name: 'demandName',
component: 'slot',
formItemProps: {
rules: [
{
required: true,
message: '请选择需求区域',
trigger: 'blur',
},
],
},
},
{
label: '下发对象',
name: 'issuingType',
component: 'RadioGroup',
componentProps: {
allowClear: true,
placeholder: '下发对象',
options: [
{ label: '云中台接口人', value: '1' },
{ label: '交付队伍', value: '2' },
],
},
formItemProps: {
rules: [
{
required: true,
message: '请选择下发对象',
trigger: 'blur',
},
],
},
},
{
label: '云中台接口人',
// name: 'cloudInterfacePerson',
name: 'issuingObj',
component: 'Select',
componentProps: {
allowClear: true,
placeholder: '接口人/交付队伍',
options: [],
},
formItemProps: {
rules: [
{
required: true,
message: '请选择云中台接口人/交付队伍',
trigger: 'blur',
},
],
},
},
{
label: '备注',
name: 'remark',
component: 'Textarea',
componentProps: {
showCount: true,
maxlength: 100,
},
},
];
组件封装:
import {
Input,
Textarea,
InputNumber,
Select,
RadioGroup,
CheckboxGroup,
DatePicker,
TimePicker,
} from 'ant-design-vue';
export const componentsMap = <any>{
Input,
Textarea,
InputNumber,
Select,
RadioGroup,
CheckboxGroup,
DatePicker,
TimePicker,
};
<template>
<a-form :model="formState" ref="formRef" v-bind="$attrs">
<a-row class="row">
<a-col :span="col" v-for="item in props.schema" :key="item.name">
<a-form-item :name="item.name" :label="item.label" v-bind="item.formItemProps">
<template v-if="componentsMap[item.component]">
<component :is="componentsMap[item.component]" v-bind="item.componentProps"
v-model:value="formState[item.name]" @change="(value: any, option: any) =>
onItemChange(value, option, item.name, item.component)
">
<template v-if="item.componentProps?.prefixOBj" #prefix>
<component v-if="item.componentProps.prefixOBj.icon" :is="item.componentProps.prefixOBj.icon" />
<span v-else v-html="item.componentProps?.prefixOBj.html"></span>
</template>
<template v-if="item.componentProps?.suffixOBj" #suffix>
<component v-if="item.componentProps.suffixOBj.icon" :is="item.componentProps.suffixOBj.icon" />
<span v-else v-html="item.componentProps?.suffixOBj.html"></span>
</template>
</component>
</template>
<template v-else>
<slot :name="item.name"></slot>
</template>
</a-form-item>
</a-col>
<a-col :span="btnCol">
<!-- 页脚 -->
<a-form-item v-if="footer">
<a-button type="primary" :icon="h(SearchOutlined)" @click="search">
搜索
</a-button>
<a-button type="default" :icon="h(ReloadOutlined)" style="margin-left: 10px" @click="reset()">
重置
</a-button>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
<script setup lang="ts">
import { h } from 'vue';
import { useFormFun } from '@/hooks/useFormFun';
import { componentsMap } from './config.js';
import { SearchOutlined, ReloadOutlined } from '@ant-design/icons-vue';
const props = defineProps({
footer: {
type: Boolean,
default: true,
},
schemaData: {
type: Object,
default: () => ({}),
},
// 表单项配置
schema: {
type: Array as PropType<SchemaItem[]>,
default: () => [],
},
col: {
type: Number,
default: 24,
},
btnCol: {
type: Number,
default: 24,
},
});
const emit = defineEmits(['search', 'reset', 'change']);
const { formRef, formState, formValidateFields, resetFields } = useFormFun(
props.schemaData
);
// 验证结果
const validForm = async () => {
return await formValidateFields();
};
const reset = (nameList?: string | (string | number)[]) => {
emit('reset', formRef.value?.resetFields(nameList));
};
const search = () => {
emit('search', formState);
};
const onItemChange = (
value: any,
name: string,
com: string
) => {
console.log(value, name, com);
emit('change', { value: formState.value[name], name });
};
使用:
<DynamicForm
:schema="schema"
:schemaData="formData"
:layout="'inline'"
:col="4"
:btnCol="5"
@search="search"
@reset="reset"
>
<template #demandCode>
// 插槽
</template>
</DynamicForm>
配置文件:
export const editItem: SchemaItem[] = [
{
label: '工单类型',
name: 'orderType',
component: 'Select',
componentProps: {
allowClear: true,
placeholder: '工单类型',
options: [
{ value: '1', label: '装维单' },
{ value: '2', label: '勘察单' },
],
},
formItemProps: {
rules: [
{
required: true,
message: '请选择工单类型',
trigger: 'blur',
},
],
},
},
{
label: '需求区域',
name: 'demandName',
component: 'slot',
formItemProps: {
rules: [
{
required: true,
message: '请选择需求区域',
trigger: 'blur',
},
],
},
},
{
label: '下发对象',
name: 'issuingType',
component: 'RadioGroup',
componentProps: {
allowClear: true,
placeholder: '下发对象',
options: [
{ label: '云中台接口人', value: '1' },
{ label: '交付队伍', value: '2' },
],
},
formItemProps: {
rules: [
{
required: true,
message: '请选择下发对象',
trigger: 'blur',
},
],
},
},
{
label: '云中台接口人',
// name: 'cloudInterfacePerson',
name: 'issuingObj',
component: 'Select',
componentProps: {
allowClear: true,
placeholder: '接口人/交付队伍',
options: [],
},
formItemProps: {
rules: [
{
required: true,
message: '请选择云中台接口人/交付队伍',
trigger: 'blur',
},
],
},
},
{
label: '备注',
name: 'remark',
component: 'Textarea',
componentProps: {
showCount: true,
maxlength: 100,
},
},
];
- 表格hook
/**
* @param fetchFunction - 获取数据的方法
* @param pageSize - 默认每页显示的条数
* @param defaultCurrent - 默认当前页码
*/
export function useTablePage(
fetchFunction: any,
innitParams: any,
pageSize = 10,
defaultCurrent = 1
) {
const currentPage = ref(defaultCurrent);
const loading = ref(false);
const data = ref([]);
const total = ref(0);
const size = ref(pageSize);
const selectedRowKeys = ref([]);
const pagination = ref({
current: currentPage.value,
pageSize: size.value,
total,
showTotal: () => `共 ${total.value} 条`,
onChange: (page: number) => {
currentPage.value = page;
getTableData(innitParams);
},
});
const getTableData = async (innitParams: any) => {
loading.value = true;
try {
const result = await fetchFunction({
pageNow: currentPage.value,
pageSize: size.value,
...innitParams,
});
data.value = result.data || [];
total.value = result.total || 0;
} catch (error) {
console.error('Error:', error);
} finally {
loading.value = false;
}
};
getTableData(innitParams);
const onSelectChange = (keys: Array<string>, data: []) => {
console.log(keys, data);
};
// watchEffect(() => {
// getTableData(currentPage.value, pageSize);
// });
return {
size,
pagination,
currentPage,
loading,
data,
total,
selectedRowKeys,
getTableData,
onSelectChange,
};
}
配置文件:
export const tableCol: tableColumn[] = [
{
title: '工单类型',
dataIndex: 'orderType',
key: 'orderType',
align: 'center',
customRender: function ({ text, record, index, column }: any) {
return text === 1 ? '勘察单' : '装维单';
},
},
{
title: '需求区域',
dataIndex: 'province',
key: 'province',
align: 'center',
customRender: function ({ text, record, index, column }: any) {
return (
[record.province, record.city ?? '', record.district ?? '']
.filter((s) => s)
.join('/') || text
);
},
},
{
title: '包含下级',
dataIndex: 'isInclude',
key: 'isInclude',
align: 'center',
customRender: function ({ text, record, index, column }: any) {
if (text) {
return '是';
} else {
return record.district !== null ? '否' : '-';
}
},
},
{
title: '下发对象',
dataIndex: 'issuingType',
key: 'issuingType',
align: 'center',
customRender: function ({ text, record, index, column }: any) {
return text === '1' ? '云中台接口人' : '交付队伍';
},
},
{
title: '接口人/队伍',
dataIndex: 'issuingObj',
key: 'issuingObj',
align: 'center',
// customRender: function ({ text, record, index, column }: any) {
// return text === null ? record.deliveryTeam : text || '-';
// },
},
{
title: '备注',
dataIndex: 'remark',
key: 'remark',
align: 'center',
ellipsis: true,
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
align: 'center',
},
];
使用:
<a-table
class="m-t-10 table"
:dataSource="data"
:columns="columns"
:pagination="pagination"
row-class-name="rowClass"
:loading="loading"
>
<template #bodyCell="{ column }">
<template v-if="column.key === 'action'">
<a-button type="link" block>修改</a-button>
<a-button type="link" danger>删除</a-button>
</template>
</template>
</a-table>
<script>
import { useTablePage } from '@/hooks/useTablePage.ts';
const getList = async (params: any) => {
console.log('请求', params);
// const res = await createApiAction(apiParams).dispatch.listCreate(params);
// console.log(res);
const mockData = [
{
id: 100,
orderType: '1',
province: '山西省',
provinceCode: '17',
city: '桃园县',
cityCode: '91',
district: null,
districtCode: null,
isInclude: true,
issuingType: '1',
issuingObj: 'culpa labore',
remark:
'adipisicing non occaecat culpaadipisicing non occaecat culpaadipisicing non occaecat culpaadipisicing non occaecat culpaadipisicing non occaecat culpaadipisicing non occaecat culpa',
},
{
id: 101,
orderType: '2',
province: '山西省',
provinceCode: '17',
city: '桃园县',
cityCode: '91',
district: '沙河口区',
districtCode: '54',
isInclude: false,
issuingType: '2',
issuingObj: 'culpa labore',
remark: 'adipisicing non occaecat culpa',
},
{
id: 101,
orderType: '1',
province: '山西省',
provinceCode: '17',
city: null,
cityCode: null,
district: null,
districtCode: null,
isInclude: true,
issuingType: '1',
issuingObj: 'culpa labore',
remark: 'adipisicing non occaecat culpa',
},
];
return {
data: mockData,
total: 12,
};
};
const { getTableData, pagination, data, total, loading } = useTablePage(
getList,
formData.value
);
</script>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。