Arco-Design + Vue3 封装通过JSON数组类型配置表单组件

一、业务场景

在开发过程中频繁会使用到一些表单,封装一个简单的表单组件来处理这些业务逻辑

二、开发环境

Arco-Design + Vite + Vue3

三、挂载全局组件 TableForm

// components/index.ts注册组件
import {
    
     App } from 'vue';

// ...其它组件
import TableForm from './table-form/index.vue';

export default {
    
    
  install(Vue: App) {
    
    
  	// ...其它组件
    Vue.component('TableForm', TableForm);
  },
};

四、TableForm.vue组件介绍

<template>
  <a-row>
    <a-form ref="tableForm" :model="formModel" auto-label-width :rules="rules">
      <a-col
        v-for="field in (visibleFields as FieldProps)"
        :key="field.name"
        :span="22"
      >
        <a-form-item :field="field.name" :label="field.label">
          <component
            :is="field.type"
            v-model="formModel[field.name]"
            allow-clear
            :multiple="field.multiple"
            :style="field.style"
            :allow-search="field.search"
            :placeholder="field.placeholder"
            :options="field.options"
            :type="field.elType"
            :field-names="field.fieldNames"
          />
        </a-form-item>
      </a-col>
    </a-form>
  </a-row>
</template>

<script lang="ts" setup>
  import {
    
     toRefs, ref, watch, computed } from 'vue';
  import {
    
     FormInstance } from '@arco-design/web-vue';
  import type {
    
     FieldProps } from '@/types/global';

  const props = defineProps({
    
    
    // 表单json配置项
    formJson: {
    
    
      type: Array,
    },
    // 表单校验规则
    rules: {
    
    
      type: Object,
    },
    // 表单数据
    formState: {
    
    
      type: Object,
    },
  });

  // ref绑定组件
  const tableForm = ref<FormInstance>();
  const formModel = ref({
    
    } as any);
  const {
    
     formJson } = toRefs(props);

  defineExpose({
    
    
    formModel,
    tableForm,
  });

  /*
   ** 表单过滤,特殊业务场景需要,没有则可以删除
   ** 用于条件判断是否通过表单条件展示需要的内容
   */
  const visibleFields = computed(() => {
    
    
    if (formJson?.value === undefined) return false;
    return formJson.value.filter((field: FieldProps) => {
    
    
      if (field.name === 'pid') {
    
    
        return formModel.value.level === '2';
      }
      return true;
    });
  });

  // 监听表单数据变化赋值
  watch(
    () => props.formState,
    (val) => {
    
    
      if (!val) return;
      formModel.value = val;
    },
    {
    
     deep: true, immediate: true }
  );
</script>

<script lang="ts">
  export default {
    
    
    name: 'TableForm',
  };
</script>

<style lang="less" scoped>
  :deep(.arco-form) {
    
    
    align-items: center;
  }
</style>


表单配置项

  1. allow-clear 是否支持清空
  2. multiple 选择框是否支持多选
  3. style a-form-item的样式
  4. allow-search 选择框是否支持搜索
  5. placeholder 占位符
  6. options选择框的选择项
  7. 表单组件内的type样式
  8. field-names options选项值配置
    其它自定义可以依次添加

五、使用场景

<template>
  <a-modal v-model:visible="visible" @ok="handleOk" @cancel="handleCancel">
    <template #title>{
    
    {
    
     title }}</template>
    <TableForm
      ref="formRef"
      :form-json="newFormJson"
      :form-state="state.formModel"
      :rules="rules"
    ></TableForm>
  </a-modal>
</template>

<script setup lang="ts">
  import {
    
     reactive, toRefs, ref, watch, computed } from 'vue';
  import {
    
     omit } from 'lodash';
  import {
    
     cpDetail } from '@/api/settings';
  import {
    
     jsonToFormData } from '@/utils';
  import {
    
     FormModelProps } from '../types';
  import {
    
     adminFormJson } from '../formJson';

  const props = defineProps({
    
    
    visible: {
    
    
      type: Boolean,
      default: false,
    },
    title: {
    
    
      type: String,
      default: '',
    },
    type: {
    
    
      type: String,
      default: '',
    },
    record: {
    
    
      type: Object,
      default: () => ({
    
    }),
    },
    serviceList: {
    
    
      type: Array,
      default: () => [],
    },
    logList: {
    
    
      type: Array,
      default: () => [],
    },
  });

  const rules = {
    
    
    real_name: [
      {
    
    
        required: true,
        message: `所属人员不能为空!`,
      },
    ],
    account: [
      {
    
    
        required: true,
        message: `账号不能为空!`,
      },
    ],
    pwd: [
      {
    
    
        required: true,
        message: `请输入密码!`,
      },
      {
    
    
        minLength: 6,
        message: `密码不能少于六位!`,
      },
    ],
    comfirmpwd: [
      {
    
    
        required: true,
        message: `请确认密码!`,
      },
      {
    
    
        minLength: 6,
        message: `密码不能少于六位!`,
      },
    ],
    pid: [
      {
    
    
        required: true,
        message: `上级账号不能为空!`,
      },
    ],
    status: [
      {
    
    
        required: true,
        message: `状态不能为空!`,
      },
    ],
  };
  
  const {
    
     visible, title, type, record, serviceList, logList } = toRefs(props);
  const state = reactive({
    
    
    formModel: {
    
    
      level: '1',
    } as FormModelProps,
  });
  const formRef = ref();
  // 生成一个新的json,补全选择框的options
  const newFormJson = computed(() => {
    
    
    return adminFormJson.map((item: any) => {
    
    
      if (item.name === 'service_ids') {
    
    
        return {
    
    
          ...item,
          options: serviceList.value,
        };
      }
      return {
    
     ...item };
    });
  });

  const emit = defineEmits(['onOk', 'onCancel']);
  const handleCancel = async () => {
    
    
    emit('onCancel', false);
  };
  const handleOk = async () => {
    
    
  	// 表单校验
    const res = await formRef.value.tableForm?.validate();
    if (!res) {
    
    
      state.formModel.service_ids = state.formModel.service_ids.join();
      if (state.formModel.level === '1')
        state.formModel = omit(state.formModel, ['pid']);
      emit('onOk', false, state.formModel);
    }
  };

  const getCpDetail = async (id: string) => {
    
    
    const {
    
     result } = await cpDetail(jsonToFormData({
    
     id }));
    state.formModel = result;
    state.formModel.service_ids = result.service_list.map((item) => item.service_id);
    state.formModel.pid = data.pid === '0' ? '' : data.pid;
  };

  watch(
    () => type,
    (val) => {
    
    
      if (val.value === 'edit') {
    
    
        getCpDetail(record.value.id);
         state.formModel = omit(state.formModel, [
           'last_time',
           'service_list',
           'p_name',
         ]);
      }
    },
    {
    
     deep: true, immediate: true }
  );
</script>

<style scoped lang="less">
  .arco-btn {
    
    
    width: 80px;
  }
  .arco-col {
    
    
    text-align: center;
  }
</style>

在这里插入图片描述

选择否也就是条件判断是否需要显示其它表单组件

在这里插入图片描述

下面贴一下formJson.ts

export const adminFormJson = [
  {
    
    
    name: 'real_name',
    label: '所属人员',
    type: 'a-input',
    placeholder: '请输入所属人员名称',
    options: [],
  },
  {
    
    
    name: 'account',
    label: '账号',
    type: 'a-input',
    placeholder: '请输入账号',
    options: [],
  },
  {
    
    
    name: 'service_ids',
    label: '授权小程序',
    type: 'a-select',
    multiple: true,
    style: `{textAlign: 'left'}`,
    placeholder: '请选择授权小程序',
    fieldNames: {
    
     value: 'id', label: 'service_name' },
    options: [],
  },
  {
    
    
    name: 'pwd',
    label: '密码',
    type: 'a-input',
    placeholder: '请输入密码',
    options: [],
  },
  {
    
    
    name: 'comfirmpwd',
    label: '确认密码',
    type: 'a-input',
    placeholder: '请确认密码',
    options: [],
  },
  {
    
    
    name: 'level',
    label: '是否一级账号',
    type: 'a-radio-group',
    placeholder: '',
    elType: 'button',
    options: [
      {
    
    
        value: '1',
        label: '是',
      },
      {
    
    
        value: '2',
        label: '否',
      },
    ],
  },
  {
    
    
    name: 'pid',
    label: '上级账号ID',
    type: 'a-select',
    placeholder: '请选择上级账号ID',
    fieldNames: {
    
     value: 'id', label: 'real_name' },
    options: [],
  },
  {
    
    
    name: 'status',
    label: '状态',
    type: 'a-select',
    placeholder: '请选择账号状态',
    options: [
      {
    
    
        value: '1',
        label: '正常',
      },
      {
    
    
        value: '2',
        label: '禁用',
      },
    ],
  },
];

猜你喜欢

转载自blog.csdn.net/m0_48995032/article/details/131581298
今日推荐