bigWhiteWhite / white-awesome-vue

基于AntDesige二次封装的组件

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Ant-design

基础组件

base-form

基础表单组件,可以扩展成搜索表单,也可以用作添加和编辑,只要配置好传入值

示例

<base-form v-bind="initForm" v-model="formData" ref="baseFormRef">
    <!-- 搜索重置按钮插槽 -->
    <template #footer>
      <a-row :gutter="16" type="flex" justify="space-between">
        <slot name="add">添加</slot>
        <a-col v-bind="initForm.footerLayout">
          <div class="footer">
            <a-button @click="reset('formData')">重置</a-button>
            <a-button class="mar_right" type="primary" @click="search">搜索</a-button>
          </div>
        </a-col>
      </a-row>
    </template>
</base-form>
<script>
export default {
	data() {
		return {
			formData: {}
		}
	}
}
</script>

插槽

  • 上方标题插槽
  • 左边标题插槽
  • 底部插槽,可以插入按钮

props

  props: {
    step: { // 在弹窗添加时可以会有几个步骤,一个步骤可能会配置一个表单,step用来标识这是第几步的表单
      type: Number,
      default: 1
    },
    value: { // 双向绑定触发的value
      type: Object,
      required: true
    },
    formMain: { // 表单项的配置[{value, type, label, options}]
      // value:字段名
      // type:表单项类型(input,inputNum,password,select,cascader )
      // label:显示label, itemOptions:其他的表单项配置(style,)
      // options:选择框选项
      type: Array,
      required: true
    },
    disabledList: { // 禁止输入的表单项
      type: Array,
      default: () => []
    },
    labelProps: { // 表单项里面布局
      type: Object,
      default: () => ({
        labelCol: { span: 3, offset: 12 }, // 表单项左边标题所占空间,总数24
        wrapperCol: { span: 4 },// 表单项右边输入框所占空间
        labelAlign: 'right'// 表单项左边标题对齐方向
      })
    },
    layout: { // 表单项之间的布局
      type: Object,
      default: () => ({
        // 以下4个属性都使用v-bind,可以额外添加其他属性,例如style或者组件文档中的其他属性
        // a-row: 可以设置表单项是否启用flex布局,或者整一个实例所占的空间为多少
        layoutRow: { type: 'flex', justify="center", span: 24 } // start;end;space-between;space-around
		// a-row: 表单标题如果在上面的布局,占据一行的多少宽度
        topTitle: { xl: 4 },
        // a-col: 表单标题如果在左边的布局,占据一行的多少宽度
        leftTitle:{ xl: 4 },
        // a-col: 每一个表单项外面布局,也就是每一个表单项占据表单一行的多少,总数24,span为8,也就是一行有3个表单项
        content: { xl: 7, lg: 6, md: 12, sm: 24, xs: 24 }
        // 在这里设置style固定每一个表单项的高度,不然校验的时候会偏移(一般不在这里设置)
      })
    },
    itemStyle: {
      type: Object,
      default: () => ({ padding: '5px 0', height: '55px' })
    },
    rules: {
      // 每一个表单项的校验规则
      type: Object,
      default: () => ({
          Id: [required: true,message: 'Please input the Id',trigger: 'change']
      })
    }
  },

emit

emits: ['value', 'cascaderUpdate', 'selectUpdate', 'inputFocus']
// value 双向绑定
// cascaderUpdate级联选择器发生变化
// selectUpdate 选择器发生变化
// inputFocus 输入框聚焦

computed

  computed: {
    antFormRef () {
      // 返回表单ref组件实例
      return this.$refs.antFormRef || {}
    },
    handleValueChange () { // 表单项发生改变时触发绑定
      return (value, key) => {
        return this.$emit('value', { ...this.props.value, [key]: value })
      }
    },
    handleSelectChange () {// 可以运用于选择器发生改变时触发某些事件
	  // 利用闭包的特性,computed返回一个函数就可以往computed中传递参数
      return (value, key) => {
        return this.$emit('selectUpdate', { value, key, step: this.step })
      }
    },
    handleCascaderChange () {// 可以运用于级联选择器发生改变时触发某些事件
      return (value, key) => {
        return this.$emit('cascaderUpdate', { value, key, step: this.step })
      }
    }
  }

配置文件示例

export const comLayout01 = {
	layout: {
		// 表单外部布局
		content: { span: 8 } // 高度设置好,不然会出现校验的时候错位
		// , style: { height: '75px' }
	},
	labelProps: {
		// 输入框以及label布局
		labelCol: { xl: 10 }, // 总数为24
		wrapperCol: { span: 14 },
		labelAlign: 'left'
	}
}
// 产品弹窗添加编辑配置
const proActionForm = (vue) => {
	return {
		...comLayout01,
		formMain: [
			{
				value: 'productName',
				type: 'input',
				label: 'setProduct.productName',
				itemOptions: {}
			},
			{
				value: 'appId',
				type: 'select',
				label: 'setProduct.appId'
			},
			{
				value: 'productType',
				type: 'select',
				label: 'setProduct.productType',
				options: [
					{
						label: 'setProduct.defaultProduct', // 默认产品
						value: 1
					},
					{
						label: 'setProduct.arraignmentProduct', // 提审产品
						value: 2
					},
					{
						label: 'setProduct.ordinaryProduct', // 其他产品
						value: 3
					}
				]
			},
			{
				value: 'availableAmount',
				type: 'inputNum',
				label: 'setProduct.availableAmount'
			},
			{
				value: 'repayOrder',
				type: 'cascader',
				label: 'setProduct.repayOrder',
				options: [
					{
						value: 'interestRate',
						label: vue.$t('setProduct.interest'),
						children: [
							{
								value: 'penaltyInterest',
								label: vue.$t('setProduct.penaltyInterest'),
								children: [
									{
										value: 'principal',
										label: vue.$t('setProduct.principal')
									}
								]
							}
						]
					},
					{
						value: 'penaltyInterest',
						label: vue.$t('setProduct.penaltyInterest'),
						children: [
							{
								value: 'interestRate',
								label: vue.$t('setProduct.interest'),
								children: [
									{
										value: 'principal',
										label: vue.$t('setProduct.principal')
									}
								]
							}
						]
					}
				]
			}
		],
		rules: {
			productName: [
				{
					required: true,
					message: 'Please input the productName',
					trigger: 'change'
				}
			],
			appId: [{ required: true, message: 'Please input the appId', trigger: 'change' }],
			productType: [
				{
					required: true,
					message: 'Please input the productType',
					trigger: 'change'
				}
			],
			availableAmount: [
				{
					validator: (rule, value, callback) => {
						if (value === '') {
							return callback(new Error('Please input the availableAmount'))
						} else if (noInt(value)) {
							return callback(new Error('availableAmount is illegal!'))
						}
						callback()
					},
					required: true,
					trigger: 'change'
				}
			],
			minApplyAmount: [
				{
					validator: (rule, value, callback) => {
						if (value === '') {
							return callback(new Error('Please input the minApplyAmount'))
						} else if (noInt(value)) {
							return callback(new Error('minApplyAmount is illegal!'))
						}
						callback()
					},
					required: true,
					trigger: 'change'
				}
			],
			interestRate: [
				{
					validator: (rule, value, callback) => {
						if (value === '') {
							return callback(new Error('Please input the interestRate'))
						} else if (noInt(value) || value * 1 > 0.05 || value * 1 < 0) {
							// console.log(value > 0.05)
							return callback(new Error('interestRate is illegal!'))
						}
						callback()
					},
					required: true,
					trigger: 'change'
				}
			],
			penaltyInterestRate: [
				{
					validator: (rule, value, callback) => {
						if (value === '') {
							return callback(new Error('Please input the penaltyInterestRate'))
						} else if (noInt(value) || value * 1 > 0.05 || value * 1 < 0) {
							// console.log(value > 0.05)
							return callback(new Error('penaltyInterestRate is illegal!'))
						}
						callback()
					},
					required: true,
					trigger: 'change'
				}
			],
			limitDays: [
				{
					validator: (rule, value, callback) => {
						if (value === '') {
							return callback(new Error('Please input the limitDays'))
						} else if (!/^([7-9]|[1-2]\d|3[0-1])$/.test(value)) {
							return callback(new Error('limitDays is illegal!'))
						}
						callback()
					},
					required: true,
					trigger: 'change'
				}
			],
			repayOrder: [
				{
					required: true,
					message: 'Please input the repayOrder',
					trigger: 'change'
				}
			],
			homeAmount: [
				{
					validator: (rule, value, callback) => {
						if (value === '') {
							return callback(new Error('Please input the homeAmount'))
						} else if (noInt(value)) {
							return callback(new Error('homeAmount is illegal!'))
						}
						callback()
					},
					required: true,
					trigger: 'change'
				}
			],
			applyCoolDownHours: [
				{
					validator: (rule, value, callback) => {
						if (value === '') {
							return callback(new Error('Please input the applyCoolDownHours'))
						} else if (!/^([0-9]|[1-3]\d|4[0-8])$/.test(value)) {
							return callback(new Error('applyCoolDownHours is illegal!'))
						}
						callback()
					},
					required: true,
					trigger: 'change'
				}
			]
		}
	}
}

base-table

基础表格组件,可以用作封装二次组件,也可以只做展示表格,没有任何操作,也没有分页器(可以加)

props

  props: {
    rowKey: { // 表格项的唯一标识,也就是数据的唯一标识'Id'
      type: String,
      required: true
    },
    locale: { // ant-design的容器
      type: Object,
      default: () => zhCN
    },
    listData: { // 表格数据,也就是后端返回的表格数据
      type: Array,
      default: () => []
    },
    columns: { // 表格列的配置
      type: Array,
      default: () => []
    },
    total: { // 表格总共有多少条数据
      type: Number,
      default: () => 0
    },
    current_size: { // 初始化的分页器选项,要传入data中做绑定
      type: Object,
      default: () => ({
        pageIndex: 1, // 默认在第几页
        pageSize: 10, // 默认一页有多少条数据
        pageSizes: ['10', '20', '30', '40', '50'] // 默认可以选择几条数据一页
      })
    },
    tableShowList: {// 需要的表格选项
      type: Object,
      default: () => ({
        select: {
            'row-selection':"rowSelection"
        },
        paginationOptions: { // 分页器
          'show-size-changer': true,
          'show-quick-jumper': true
        }
      })
    },
    tableOptions: { // 设置表格其他属性,例如style或者文档中的其他属性
      type: Object,
      default: () => ({})
    },
    layout: { // 表单项之间的布局
      type: Object,
      default: () => ({
        // 以下4个属性都使用v-bind,可以额外添加其他属性,例如style或者组件文档中的其他属性
        // a-row: 可以设置表单项是否启用flex布局
        layoutRow: { type: 'flex', justify="center", span: 24 } // start;end;space-between;space-around
		// a-row: 表单标题如果在上面的布局,占据一行的多少宽度
        topTitle: { xl: 4 },
        // a-col: 表单标题如果在左边的布局,占据一行的多少宽度
        leftTitle:{ xl: 4 },
        // a-col: 每一个表单项外面布局,也就是每一个表单项占据表单一行的多少,总数24,span为8,也就是一行有3个表单项
        content: { xl: 7, lg: 6, md: 12, sm: 24, xs: 24 }
        // 在这里设置style固定每一个表单项的高度,不然校验的时候会偏移(一般不在这里设置)
      })
    }
  }

data

  data () { // 要将分页器双向绑定,保留之前的状态
    return {
      pageArg: { ...this.current_size }
    }
  }

methods

  emits: ['updatePage', 'updateSelect'],
  methods: {
    antTableRef () { // 返回表格ref示例
      return this.$refs.antTableRef || {}
    },
    indexMethod (index) { // 表格显示序号
      const { pageIndex, pageSize } = this.pageArg
      return pageIndex !== 1
        ? (pageIndex - 1) * pageSize + index + 1
        : index + 1
    },
    currentUpdate (pageIndex, b) { // 当前页发生变化
      this.$set(this.pageArg, 'pageIndex', pageIndex)
      this.$emit('updatePage', { ...this.pageArg,pageIndex,typeof: 'updateCurrent' })
    },
    sizeUpdate (pageIndex, pageSize) { // 页码发生变化
      this.$set(this.pageArg, 'pageSize', pageSize)
      this.$emit('updatePage', { ...this.pageArg,pageSize,typeof: 'updateSize' })
    },
    selectionUpdate (select) { // 表格选择发生变化
      this.$emit('updateSelect', select)
    }
  }

配置文件示例

export const proTableConfig = {
	layout: {
		content: { xl: 24 }
	}, // 表格宽度
	tableOptions: {
		style: { width: '100%' }
	},
	rowKey: 'productId', // 列表唯一id
	columns: [
		{
			dataIndex: 'productId',
			title: 'setProduct.productId'
		},
		{
			dataIndex: 'appId',
			title: 'setProduct.appId'
		},
		{
			dataIndex: 'productType',
			title: 'setProduct.productType'
		},
		{
			dataIndex: 'limitDays',
			title: 'setProduct.limitDays'
		},
		{
			dataIndex: 'afterLoanFeeName',
			title: 'setProduct.afterLoanFeeName'
		},
		{
			dataIndex: 'rate',
			title: 'setProduct.interestRate'
		},
		{
			dataIndex: 'fixedCharge',
			title: 'setProduct.fixedCharge'
		},
		{
			dataIndex: 'penaltyInterestRate',
			title: 'setProduct.penaltyInterestRate'
		},

		{ dataIndex: 'handle', title: '操作', minWidth: '80' }
	],
	current_size: comLayout02.currentSize,
	tableShowList: comLayout02.tableShowList
}

edit-table

props

props: {
    rowKey: {// 列的唯一标识
      type: String,
      required: true
    },
    locale: {
      type: Object,
      default: () => zhCN
    },
    tableForm: { // 表格里面的表单组件
      type: Object,
      default: () => ({
        rules: {}
      })
    },
    listData: { // 表格数据
      type: Array,
      default: () => []
    },
    queryName: { // 是哪一个界面在使用这个组件的标识
      type: String,
      required: true
    },
    columns: {
      type: Array,
      default: () => []
    },
    total: { // 表格总条数
      type: Number,
      default: () => 0
    },
    current_size: { // 当前页和一页条数
      type: Object,
      default: () => ({
        currentPage: 1,
        pageSize: 10,
        pageSizeOptions: [5, 10, 20, 30, 40]
      })
    },
    tableShowList: { // 是否显示的选项
      type: Object,
      default: () => ({})
    },
    tableOptions: { // 设置表格其他属性
      type: Object,
      default: () => ({})
    },
    layout: { // 表格布局
      type: Object,
      default: () => ({})
    },
}

data

data () {
    return {
      ruleForm: {},
      dataSource: [...this.listData], // 表格数据
      pageArg: { ...this.current_size }// 要将分页器双向绑定,保留之前的状态
    }
}

methods

antTableRef () { // 传出去表格a-table示例
  return this.$refs.antTableRef || {}
}
外部改变表格里的值
changeData (result) { // ref调用
  this.dataSource = result
}
编辑表格中的输入框改变 dataSource
handleChange (value, name, scope) { // 输入框发生变化
  const dataSource = this.dataSource
  const uniqueId = scope[this.rowKey] // 唯一标识
  dataSource.forEach((item) => {
    if (item[this.rowKey] === scope[this.rowKey]) { // 改变对应的数值
      return (item[name] = value)
    }
  })
  this.$set(this.ruleForm, name, value) // 设置校验表单对象,好进行校验
  this.$emit('updateData', { data: dataSource, name, value, uniqueId }) // 传出去: 数据/属性名/值/唯一标识
}
分页器和选择器
currentUpdate (pageIndex) { // 编辑表格还没有做分页功能
  this.pageArg.pageIndex = pageIndex
  this.$emit('updatePage', {
    ...this.pageArg,
    pageIndex,
    typeof: 'updateCurrent'
  })
},
sizeUpdate (pageIndex, pageSize) {
  this.pageArg.pageSize = pageSize
  this.$emit('updatePage', {
    ...this.pageArg,
    pageSize,
    typeof: 'updateSize'
  })
},
selectionUpdate (select) {
  this.$emit('updateSelect', select)
}
增加删除单元格
// 增加删除单元格
handleAddDelete (action = 'add', _) { // _:如果是添加add,则为数据,如果是删除delete,则为key
  const { count, dataSource } = this
  if (action === 'add') {
    this.count = count + 1
    this.dataSource = [...dataSource, _]
  } else if (action === 'delete') {
    this.count = count - 1
    this.dataSource = dataSource.filter((item) => item[this.rowKey] !== _)
    console.log(this.dataSource)
  }
}

base-card

展示卡片项,可以显示多组卡片信息项

props

props: {
    cardList: { // 多组卡片信息项
      type: Array,
      default: () => []
    },
    layout: { //
      type: Object,
      default: () => ({
        // a-row: 可以设置表单项是否启用flex布局
        layoutRow: { type: 'flex', justify="center", span: 24 } // start;end;space-between;space-around
        content: { span: 24 }
      })
    }
}

配置项

// 等级详情弹窗配置
export const levelDetailDialogConfig = (vue) => {
	return {
		width: '90%',
		title: vue.$t('setProduct.productDetail')
	}
}

base-dialog

  • 弹窗组件,用作添加编辑,而且不止一个表单,也不止一步

使用

<base-dialog
	v-bind="productDialogConfig"
	ref="baseDialogRef"
	@actionNextSubmit="actionNextSubmit"
	@selectUpdate="hasSetLevel"
	@switchVisible="resetFeeActionTable"
>
    <template #step1>
      <computed-table
        class="computed_beforeFee"
        ref="computedBeforeFeeRef"
        queryName="computedBefore"
        :initTable="beforeFeeList"
        :initData="beforeFeeData"
        :isNeedStorage="false"
      >
        <template #leftTitle>
          <div>
            <p>{{ $t('setProduct.beforeLoanFee') }}</p>
            <a-button type="primary" @click="handleBeforeFee('add')">
              <a-icon type="plus" />
            </a-button>
          </div>
        </template>
        <template #handle="scope">
          <a-button type="danger" @click="handleBeforeFee('delete', scope.row)"
            ><a-icon type="delete"
          /></a-button>
        </template>
      </computed-table>
      <!-- 贷前费用和贷后费用的分割线 -->
      <computed-table
        class="computed_table"
        ref="computedAfterFeeRef"
        queryName="computedAfter"
        :initTable="afterFeeList"
        :initData="afterFeeData"
        :isNeedStorage="false"
      >
        <!-- @updateData="feeUpdateData" -->
        <template #leftTitle>
          <div>
            <p>{{ $t('setProduct.afterLoanFee') }}</p>
            <a-button type="primary" @click="handleAfterFee('add')">
              <a-icon type="plus" />
            </a-button>
          </div>
        </template>
        <template #handle="scope">
          <a-button type="danger" @click="handleAfterFee('delete', scope.row)"
            ><a-icon type="delete"
          /></a-button>
        </template>
      </computed-table>
    </template>
</base-dialog>

插槽

  • 第几步的插槽
  • 确认取消插槽

props

props: {
    dialogOptions: { // 弹窗配置
      type: Object,
      default: () => {}
    },
    formList: { // // 弹窗表单配置,第几步的表单
      type: Array,
      require: true
    },
    echoFormList: { // 回显表单数据,为数组
      type: Array,
      default: () => []
    }
}

配置项

export const proActionConfig = (vue) => {
	// 多级嵌套使用函数引入vue的实例
	return {
		dialogOptions: {
			// 弹窗配置
			width: '90%'
		},
		formList: [
			// 弹窗表单配置,第几步的表单
			{
				addTitle: vue.$t('setProduct.addProduct'),
				editTitle: vue.$t('setProduct.editProduct'),
				confirmText: 'setProduct.confirm', // 确认按钮文案
				cancelText: 'setProduct.cancel', // 取消按钮文案
				prevText: 'setProduct.prev', // 上一步按钮文案
				nextText: 'setProduct.next', // 下一步按钮文案
				step: 1, // 这是第几步才会出现的表单
				name: 'step1', // 表单的数据绑定名
				initForm: proActionForm(vue) // 填入base-form的基础配置
			}
		],
		echoFormList: [
			// 设置默认值或者回显数据
			{
				// 第一步表单的默认项
				name: 'step1',
				initForm: {
					repayOrder: ['penaltyInterest', 'interestRate', 'principal'],
					interestRate: 0,
					penaltyInterestRate: 0.02,
					applyCoolDownHours: 24,
					productType: 3
				}
			},
			{
				name: 'step2', // 第二步表单的默认值
				initForm: {
					creditLevel: 'Z'
				}
			}
		]
	}
}

script

<script>
import BaseForm from '../ant-form/base-form.vue'
import { initListData, initData } from '@/utils/ant-fun'
export default {
	components: {
		BaseForm
	},
	data() {
		return {
			action: 'add',
			step: 1,
			visible: false,
			formData: {},
			disabledList: {} // 禁止输入列表,一般在编辑中使用,新增可以在配置文件中配置
		}
	},
	watch: {
		formList(_) {
			// 在外部添加步骤以后,需要监听,并重新赋值formData,保留之前的formData
			const unLiveData = _.filter((item) => {
				// 返回新的表单
				return !this.formData[item.name]
			})
			unLiveData.forEach((item) => {
				// 只对新的表单步骤赋予新的值,之前的不做改变
				this.echoFormList.forEach((_) => {
					// 新的表单初始化
					if (item.name === _.name) {
						this.$set(this.formData, item.name, initData(item.initForm.formMain, _.initForm))
					} else if (!_[item.name]) {
						this.$set(this.formData, item.name, nitData(item.initForm.formMain, {}))
					}
				})
			})
		}
	},
	computed: {
		title() {
			// 根据action的不同改变title
			let title
			if (this.action === 'add') {
				title = this.$t(this.stepItem().addTitle)
			} else if (this.action === 'edit') {
				title = this.$t(this.stepItem().editTitle)
			}
			return title
		},
		stepItem() {
			// 根据步数获取对应步骤的表单配置
			return (stepKey = this.step) => {
				const item = this.formList.find((item) => {
					return item.step === stepKey
				})
				return item
			}
		},
		submitFormData() {
			return (stepKey, name) => {
				// 返回第几步的表单数据 @params: 第几步, 什么属性
				return name ? this.formData[stepKey][name] : this.formData[stepKey]
			}
		}
	},
	created() {
		this.formData = initListData(this.formList, this.echoFormList) // 数据回显,从props中引入
	}
}
</script>
emits
emits: ['actionNextSubmit', 'cascaderUpdate', 'selectUpdate', 'switchVisible']
// actionNextSubmit 确认按钮
// selectUpdate 表单中的选择框发生变化
// cascaderUpdate 级联选择器发生变化
修改哪个步骤的表单数据

有的时候初始化数据 echoFormList 不可行,因为 echoFormList 绝对不可以改变!但是也要动态的改变某一个步骤的数据,就可以使用 setFormData 函数

setFormData ({ stepName, key = '', value }) {
  // 改变步骤中的某一个值,在哪里改变很重要!
  if (key && this.formData[stepName]) {
    this.$set(this.formData[stepName], key, value)
  } else if (this.formData[stepName]) {
    this.$set(this.formData, stepName, value)
  }
}
表单选择器发生变化
selectUpdate (data) {
  this.$emit('selectUpdate', data)
}
级联选择器改变数据
optionUpdate (data) { // 级联选择器无法实时改变base-form的value,只能通过这里实时改变formData
  const form = this.formData
  const { value, key, step } = data
  form[`step${step}`][key] = value
  this.formData = form
  this.$emit('optionUpdate', data)
}
数据初始化
handleAction ({ action = 'add', data = {}, disabledList = {} }) { // action/编辑回显的数据/禁止输入的表单项属性
  this.switchVisible() // 先初始化,不然会覆盖后面的回显数据
  this.action = action
  if (this.action === 'edit') {// 如果是编辑需要回显数据
    this.formData = { ...data }
  }
  this.disabledList = { ...disabledList }
}
cancel 退出弹窗
cancel () { // 有一些数据不在这里面,emit告诉外面退出来,初始化其他组件的数据
  this.switchVisible()
  this.$emit('switchVisible')
}
切换弹窗显隐
switchVisible () {// 并且初始化数据
  this.step = 1
  this.formData = initListData(this.formList, this.echoFormList)
  this.visible = !this.visible
}
步数控制函数
stepControl (type = 'next', step) {
  // 步数控制函数
  if (step && this.step < this.formList.length) {
    this.step = step
  } else {
    type === 'next' && this.step < this.formList.length && (this.step += 1)
    type === 'prev' && this.step > 1 ? (this.step -= 1) : this.cancel()
  }
}
确认传出去数据
handleConfirmClick () { // 可以选择将ref也传出去,也可以选择在这里校验
  const stepItem = this.stepItem()
  const { antFormRef = {} } = this.$refs[`${stepItem.name}Ref`][0]
  antFormRef &&
    antFormRef.validate((valid) => {
      if (valid) {
        const data = {
          formList: { ...this.formData }, // 所有步骤的表单数据
          formData: { ...this.formData[stepItem.name] }, // 当前步骤的表单数据
          step: this.step, // 是第几步的表单
          stepName: stepItem.name // 步骤名称
        }
        this.$emit('actionNextSubmit', {
          ...data,
          action: this.action
        })
      }
    })
}

二次组件

search-from 搜索

搜索表单组件

props

props: {
    queryName: { // 将数据存储vuex的名称,十分重要
      type: String,
      require: true
    },
    initForm: { // 搜索表单的配置信息,包括base-form的formMain
      type: Object,
      require: true
    },
    // 回显表单数据
    echoForm: {
      type: Object,
      default: () => {}
    }
}

script

<script>
import BaseForm from '@/components/AntDesign/ant-form/base-form.vue'
import { initData } from '@/utils/ant-fun'
export default {
	components: {
		BaseForm
	},
	emits: ['reset', 'submit'],
	created() {
		this.formData = initData(this.initForm.formMain, this.echoForm) // 数据回显,从props中引入
	}
}
</script>
外部组件改变 formData
// this.refs.#.setFormData(id, 3)
setFormData (name, value) {
  this.$set(this.formData, name, value)
}
重置 reset
reset (name) { // name: formData
  const resetForm = {}
  for (const item in this[name]) {
    resetForm[item] = ''
  }
  this[name] = resetForm
  this.$emit('reset', this.formData)
},
搜索方法
search () {
  const { antFormRef = {} } = this.$refs.baseFormRef // 获取base的示例,为了校验表单数据是否合法
  antFormRef.validate((valid) => {
    if (valid) {
      // 将表单的搜索条件存入vuex作缓存,如果需要缓存的话
      // this.saveQueryParams({ formData: this.formData, queryName: this.queryName })
      this.$store.commit('common/saveQueryParams', {
        formData: this.formData,
        queryName: this.queryName
      })
      this.$emit('submit', this.formData) // 不需要可以直接返回formData数据
    } else {
      console.log('this.formData: noValid', this.formData)
    }
  })
}

使用

<!-- 搜索表单 -->
<search-form
  ref="searchFromRef"
  queryName="setProduct" // 二次表单只需要这个来存储基础表单的value
  :initForm="proSearchFormConfig" // 都是传入base-form的配置项
  @reset="search"
  @submit="search"
>
  <template #add>
    <a-col>
      <a-button
        type="primary"
        @click="$refs.productActionRef.handleAddProduct()"
      >
        {{ $t('setProduct.addProduct') }}
      </a-button>
    </a-col>
  </template>
</search-form>

配置文件

export const comLayout02 = {
	layout: {
		// 每一个表单项所占得宽度
		content: { xl: 6, lg: 8, md: 6, sm: 24, xs: 24 }
	},
	labelProps: {
		labelCol: { span: 8 }, // 表单项中标题所占的宽度
		wrapperCol: { span: 14 }, // 输入框所占的宽度
		labelAlign: 'left'
	},
	itemStyle: { padding: '5px 0' },
	currentSize: {
		pageIndex: 1,
		pageSize: 10,
		pageSizes: ['5', '10', '20', '30', '40']
	},
	tableShowList: {
		paginationOptions: { 'show-size-changer': true, 'show-quick-jumper': true } // 是否显示footer分页器
	}
}
export const proSearchFormConfig = {
	// 传入base-form的配置项,具体可以参考base-form
	...comLayout02,
	formMain: [
		{
			value: 'productId',
			type: 'input',
			label: 'setProduct.productId',
			ruleVariate: {
				// 输入规则的变量
				// maxLength: 10
			}
		},
		{
			value: 'productType',
			type: 'select',
			label: 'setProduct.productType',
			options: [
				{
					label: 'table.all', // 默认产品
					value: ''
				},
				{
					label: 'setProduct.defaultProduct', // 默认产品
					value: 1
				}
			]
		}
	]
}

content-table 展示表格

显示表格组件,有分页选择功能

props

props: {
    handleData: { // 数据处理,后端返回的数据需要在外面处理完在传进来
      type: Function,
      default: (_) => _
    },
    apiQuery: { // 搜索表格需要的链接和参数,可以结合vuex去做,根据业务需求变通
      type: Object,
      required: true,
      // { url: 'api/...', data: {...}, ...更多属性 }
    },
    queryName: { // 如果需要vuex中的formData缓存,那么就可以写入和search-form一样的queryName
      type: String,
      default: () => ''
    },
    initTable: { // 初始化表格组件,也就是base-table的配置
      type: Object,
      require: true
    },
    isNeedStorage: { // 是否需要使用vuex中的搜索参数初始化表格
      type: Boolean,
      default: false
    }
}

script

<script>
import { createNamespacedHelpers } from 'vuex'
import BaseTable from '@/components/AntDesign/ant-table/base-table.vue'
const { mapGetters } = createNamespacedHelpers('common')
export default {
	components: {
		BaseTable
	},
	data() {
		return {
			loading: false, // 加载动画
			listData: {
				// 存储后端返回的表格数据
				data: [],
				total: 0
			}
		}
	},
	computed: {
		...mapGetters(['getQueryParams']),
		trendsSlots() {
			// 返回组件插槽,过滤掉'操作'插槽
			const useLess = ['handle']
			const slots = this.initTable.columns.filter((item) => {
				return !useLess.includes(item.dataIndex)
			})
			return slots
		}
	},
	methods: {
		// 初始化表格
		async init(params, _ = { pageIndex: 1, pageSize: 10 }) {
			this.loading = true
			const data = {
				...params,
				...this.apiQuery.data,
				pagination: { ..._ }
			}
			const res = await this.$api(this.apiQuery.url, data)
			const list = this.handleData(res.list)
			this.listData = { data: list, total: res.total }
			this.loading = false
		},
		async deleteBtnClick() {},
		// 分页器刷新表格,判断是否使用缓存查询
		updatePage(_) {
			const params = this.isNeedStorage ? this.getQueryParams(this.queryName) : {}
			this.init(params, { pageIndex: _.pageIndex, pageSize: _.pageSize })
		},
		updateSelect(_) {
			console.log(_, '选择序号改变了')
		}
	},
	created() {
		this.isNeedStorage ? this.init(this.getQueryParams(this.queryName), this.initTable.current_size) : this.init({}, this.initTable.current_size)
	}
}
</script>
初始化表格
// 初始化表格
async init (params, _ = { pageIndex: 1, pageSize: 10 }) {
  this.loading = true
  const data = { // 请求参数
    ...params,
    ...this.apiQuery.data,
    pagination: { ..._ }
  }
  const res = await this.$api(this.apiQuery.url, data) // 获取表格数据
  const list = this.handleData(res.list)
  this.listData = { data: list, total: res.total } // 存入data
  this.loading = false
}
分页器和选择框
// @updatePage="updatePage" -----   @updateSelect="updateSelect"
updatePage (_) { // 分页器改变重新获取数据
  const params = this.isNeedStorage
    ? this.getQueryParams(this.queryName)
    : {}
  this.init(params, { pageIndex: _.pageIndex, pageSize: _.pageSize })
}

updateSelect (_) {
  console.log(_, '选择序号改变了')
}

配置文件

import { comLayout02 } from '../base.config'
export const proTableConfig = { // 其实就是base-table的配置文件
  layout: {
    content: { xl: 24 }
  }, // 表格宽度
  tableOptions: {
    style: { width: '100%' }
  },
  rowKey: 'productId', // 列表唯一id
  columns: [
    {
      dataIndex: 'productId',
      title: 'setProduct.productId'
    },
    {
      dataIndex: 'appId',
      title: 'setProduct.appId'
    }

    { dataIndex: 'handle', title: '操作', minWidth: '80' }
  ],
  current_size: comLayout02.currentSize,
  tableShowList: comLayout02.tableShowList
}

computed-table 计算表格

props

props: {
    initData: { // 表格默认数据
      type: Array,
      default: () => []
    },
    queryName: { // 如果需要vuex中的formData缓存,那么就可以写入和search-form一样的queryName
      type: String,
      default: () => ''
    },
    initTable: { // 初始化表格组件,也就是edit-table的配置
      type: Object,
      require: true
    },
    isNeedStorage: { // 是否需要使用vuex中的搜索参数初始化表格
      type: Boolean,
      default: false
    }
}

script

<script>
import { createNamespacedHelpers } from 'vuex'
import EditTable from '@/components/AntDesign/ant-table/edit-table.vue'
const { mapGetters } = createNamespacedHelpers('common')
export default {
	components: {
		EditTable
	},
	data() {
		return {
			listData: {
				data: [],
				total: 0
			}
		}
	},
	computed: {
		...mapGetters(['getQueryParams']),
		trendsSlots() {
			// 返回组件插槽,过滤掉'操作'插槽
			const useLess = ['handle']
			const slots = this.initTable.columns.filter((item) => {
				return !useLess.includes(item.dataIndex)
			})
			return slots
		},
		handleValueChange(value, key) {
			// 当表格里面的表单数据发生变化的时候触发
			// console.log(value, key)
			return 1
		}
	},
	created() {
		// 初始化表格
		this.listData = { ...this.listData, data: this.initData }
	}
}
</script>
计算表格数据发生变化
// @updateData="updateData" 由edit-table组件触发
updateData (dataSource) {
  // 表格里面的数据发生变化时立刻传给父组件
  this.$emit('updateData', dataSource)
}
分页器和选择框
// 计算表格目前还没有遇到需要分页和选择框的需求,还没有完善
updatePage (_) {
  const params = this.getQueryParams(this.queryName)
  // this.init(params, _)
},
updateSelect (_) {
  console.log(_, '选择序号改变了')
}
提交表格数据
submitForm (canNull = []) { // 一行中的谁可以为空不填
  const dataSource = this.$refs.editTableRef.dataSource
  let checked = true // true是没问题的
  let checkedName // 是哪一个属性不合法
  if (dataSource.length === 0) return { checked, result: dataSource } // 表格为空直接返回
  dataSource.forEach((item) => { // 循环判断
    if (canNull.length === 0) {
      // 每一项都不可以为空
      Object.keys(item).forEach((name) => {
        if (
          item[name] === null ||
          item[name] === undefined ||
          item[name] === ''
        ) {
          checked = false
          checkedName = name
        }
      })
    } else {
      const noNull = Object.keys(item).filter((key) => { // 把可以为空的过滤掉
        return !canNull.includes(key)
      })
      noNull.forEach((name) => { // 判断剩下不可以为空的
        if (
          item[name] === null ||
          item[name] === undefined ||
          item[name] === ''
        ) {
          checked = false
          checkedName = name
        }
      })
    }
  })
  return { checked, result: checked ? dataSource : checkedName }
},
增加删除表格项
handleAddDelete (action = 'add', _) { // 传入edit-table action: 'add'/'delete'
  // 增加删除列表项
  this.$refs.editTableRef.handleAddDelete(action, _)
}

配置文件

export let feeIsValidate = true
export const beforeFeeList = {
  layout: ...,
  tableOptions: ...,
  rowKey: ...,
  columns: [
    {
      dataIndex: 'name',
      title: 'setProduct.beforeLoanFee'
    },
    {
      dataIndex: 'rate',
      title: 'setProduct.rate'
    },
    {
      dataIndex: 'fixedCharge',
      title: 'setProduct.fixedCharge'
    },

    { dataIndex: 'handle', title: 'table.operation', minWidth: '80' }
  ],
  tableForm: { // 表格里面的表单类型: input/inputNumber/select
    formMain: {
      name: {
        type: 'input'
      },
      rate: {
        type: 'inputNumber'
      },
      fixedCharge: {
        type: 'inputNumber'
      },
      chargeType: {
          type: 'select',
          options: [
            {
              value: 2,
              label: vue.$t('setProduct.Yes')
            },
            {
              value: 1,
              label: vue.$t('setProduct.No')
            }
          ]
        }
    },
    rules: { // 表单检验规则
      name: [
        {
          validator: (rule, value, callback) => {
            if (value === '') {
              feeIsValidate = false
              return callback(new Error("beforeLoanFeeName can't be null"))
            }
            feeIsValidate = true
            callback()
          },
          required: true,
          trigger: 'change'
        }
      ]
    }
  }
}

detail-dialog

示例

<a-modal v-bind="detailOptions" :visible="visible" centered destroyOnClose @ok="switchVisible" @cancel="switchVisible">
    <base-card v-bind="cardList"></base-card>
    <slot name="default"></slot>
	<template slot="footer">
        <slot name="footer">
            <a-button type="primary" @click="switchVisible">关闭</a-button>
        </slot>
    </template>
</a-modal>
<script>
export default {
  props: {
    detailOptions: { // 卡片的配置项
      type: Object,
      default: () => ({
        width: '80%'
      })
    },
    : { // 在外部过滤完的数据
      type: Object,
      default: () => {}
    }
  },
  components: {
    BaseCard
  },
  data () {
    return {
      visible: false
    }
  },
  methods: {
    switchVisible () {
      this.visible = !this.visible
    }
  }
}
</script>

数据

// cardList是数组
;[
	{
		// 第一个卡片
		type: 'default',
		key: '12',
		cardOption: {
			title: '产品信息'
		},
		itemLayout: {
			span: 4,
			style: {
				margin: '15px 0'
			}
		},
		contentList: [
			{
				title: '产品',
				text: 'credifio-co'
			},
			{
				title: '产品名称',
				text: 'Kes 7 Days'
			}
		]
	},
	{
		// 其他卡片
	}
]

使用方法

配置数据处理函数

filterData

/**
 * @param 表单数组,所有要改动的表单项,添加进来的属性名
 * @param 更改表单中的表单项
 */
export const filterData = (_, keyFun, name = 'inputRule') => {
  _.forEach((item) => {
    for (let obj of keyFun) {
      if (obj[item.value]) {
        item[name] = obj[item.value]
      }
    }
  })
  return _
}
// 使用
export const addLevelForm = (vue) => {
  return {
    ...comLayout01,
    formMain: [
      {
        value: 'appId',
        type: 'select',
        label: 'setProduct.appId'
      }
    ]
  }
}
// 使用filterData也可以使用initFormOptions
initLevelForm () {
  const formMain = filterData(
    addLevelForm(this).formMain,
    [
      {
        appId: [
          ...getVestApp(this.enumerate.appId, this.setting.curSystem.value)
        ],
        // ...
      }
    ],
    'options'
  )
  return { ...addLevelForm(this), formMain }
}

listFilterData

/**
 * @param 表单数组,第几步的表单项,所有要改动的表单项,添加进来的属性名
 * @param 给弹出框中的表单项初始化,更新表单项
 */
export const listFilterData = (_, step, keyFun, name = 'inputRule') => {
  const form = _.find((item) => {
    return item.step === step
  })
  if (form.initForm) {
    const formMain = filterData(form.initForm.formMain, keyFun, name)
    const initForm = { ...form.initForm, formMain }
    const formList = _.map((item) => {
      return item.step === step ? { ...item, initForm } : { ...item }
    })
    return formList
  }
  return _
}
// 使用
export const levelEditForm = (vue) => {
  return {
    formList: [
      {
        addTitle: vue.$t('setProduct.addProduct'),
        editTitle: vue.$t('setProduct.editLevel'),
        confirmText: 'setProduct.confirm',
        cancelText: 'setProduct.cancel',
        prevText: 'setProduct.prev',
        nextText: 'setProduct.next',
        step: 1, // 这是第几步才会出现的表单
        name: 'step1', // 表单的数据绑定
        initForm: levelActionForm(vue)
      }
    ]
  }
}
levelEditForm () {
  const config = levelEditForm(this)
  let formList = dialogFilterData(
    config.formList,
    1, // 第几步的表单要添加
    [
      {
        appId: [
          ...getVestApp(this.enumerate.appId, this.setting.curSystem.value)
        ]
      }
    ],
    'options'
  )
  return { ...config, formList }
}

initData

/**
 * @param 初始化表单数据,如果没有默认值的话将所有值置空
 */
export const initData = (initArray, initObj = {}) => {
	// 做数据回显,初始化表单数据
	const data = {}
	initArray.forEach((item) => {
		if (initObj[item.value] !== undefined) {
			data[item.value] = initObj[item.value]
		} else {
			data[item.value] = ''
		}
	})
	return data
}

initListData

/**
 * @param 初始化多个表单数据
 */
export const initListData = (formList, echoFormList = []) => {
  const data = {}
  formList.forEach((item) => {
    if (item.initForm) { // 判断有无表单配置对象
      echoFormList.forEach((initItem) => {
        if (item.name === initItem.name) {
          data[item.name] = initData(item.initForm.formMain, initItem.initForm)
        } else if (!item[initItem.name] && initItem[item.name]) {
          // formList不存在这个step,echoFormList存在
          data[initItem.name] = {}
        } else if (!initItem[item.name] && item[initItem.name]) {
          // formList存在这个step,echoFormList不存在
          data[item.name] = initData(item.initForm.formMain)
        }
      })
    }
    if (echoFormList.length === 0) {
      // 即使没有初始化数组也不至于报错
      data[item.name] = {}
    }
  })
  return data
}
// 使用
switchVisible () {
  // 切换弹窗显隐,并且初始化数据
  this.step = 1
  this.formData = initListData(this.formList, this.echoFormList)
  this.visible = !this.visible
}

initEchoFormList

// 更新初始化,保留之前的初始化数据,也可以增加修改
export const initEchoFormList = (echoFormList, newEchoFormList) => {
	echoFormList.forEach((item) => {
		newEchoFormList.forEach((key) => {
			if (item.name === key.name) {
				item.initForm = { ...item.initForm, ...key.initForm }
			}
		})
	})
	return echoFormList
}

initFormOptions

/**
 * @param 初始化表单中的选择框
 */
export const initFormOptions = (formMain, optionsList) => {
  const _ = Object.keys(optionsList)
  formMain.forEach((item) => {
    _.forEach((key) => {
      if (item.value === key && item.type === 'select') {
        item.options = optionsList[key]
      }
    })
  })
  return formMain
}
// 使用
export const levelSearchFormConfig = {
  ...comLayout02,
  formMain: [
    {
      value: 'appId',
      type: 'select',
      label: 'setProduct.appId'
    }
  ]
}
levelSearchFormConfig () {
  const appIdOptions = [
    { label: this.$t('table.all'), value: '' },
    ...getVestApp(this.enumerate.appId, this.setting.curSystem.value)
  ]
  // 初始化表单选择框
  const formMain = initFormOptions(levelSearchFormConfig.formMain, {
    appId: appIdOptions
  })
  return { ...levelSearchFormConfig, formMain }
}

搜索表单

<!-- 搜索表单 -->
<search-form ref="searchFromRef" queryName="setProduct" :initForm="proSearchFormConfig" @reset="search" @submit="search">
  <template #add>
    <a-col>
      <a-button
        type="primary"
        @click="$refs.productActionRef.handleAddProduct()"
      >添加产品</a-button>
    </a-col>
  </template>
</search-form>

base-dialog 弹窗

示例

<base-dialog
	v-bind="productDialogConfig"
	ref="baseDialogRef"
	@actionNextSubmit="actionNextSubmit"
	@selectUpdate="hasSetLevel"
	@switchVisible="resetFeeActionTable"
>
    <!--步骤插槽-->
    <template #step1>
      <computed-table
        class="computed_beforeFee"
        ref="computedBeforeFeeRef"
        queryName="computedBefore"
        :initTable="beforeFeeList"
        :initData="beforeFeeData"
        :isNeedStorage="false"
      >
        <template #leftTitle>
          <div>
            <p>{{ $t('setProduct.beforeLoanFee') }}</p>
            <a-button type="primary" @click="handleBeforeFee('add')">
              <a-icon type="plus" />
            </a-button>
          </div>
        </template>
        <template #handle="scope">
          <a-button type="danger" @click="handleBeforeFee('delete', scope.row)"
            ><a-icon type="delete"
          /></a-button>
        </template>
      </computed-table>
      <!-- 贷前费用和贷后费用的分割线 -->
      <computed-table
        class="computed_table"
        ref="computedAfterFeeRef"
        queryName="computedAfter"
        :initTable="afterFeeList"
        :initData="afterFeeData"
        :isNeedStorage="false"
      >
        <template #leftTitle>
          <div>
            <p>{{ $t('setProduct.afterLoanFee') }}</p>
            <a-button type="primary" @click="handleAfterFee('add')">
              <a-icon type="plus" />
            </a-button>
          </div>
        </template>
        <template #handle="scope">
          <a-button type="danger" @click="handleAfterFee('delete', scope.row)"
            ><a-icon type="delete"
          /></a-button>
        </template>
      </computed-table>
    </template>
</base-dialog>

编辑回显数据

适用于第一次点击编辑按钮的时候,但是如果要完成类似于点击默认产品出现第二步,而第二步的产品回显要查询得到数据,那么这个方法就不适用,可以直接使用 setFormData 方法改变表单数据

// <a-button @click="$refs.productActionRef.handleAddProduct()">
// {{ $t('setProduct.addProduct') }}
// </a-button>
async handleEditProduct (_) {
  try {
    const res = await this.$api(
      `/${this.setting.curSystem.prefixApi}${getProductNew}?productId=${_.productId}`,
      {},
      'get'
    )
    // 如果不是默认产品就可以这样
    this.$refs.baseDialogRef.handleAction({
      action: 'edit',
      data: { step1: res }, // !回显要加上是第几步的表单数据
      disabledList: { step1: ['productName', 'limitDays'] } // 指定第几步的禁用
    })
  } catch (error) {
    console.log(error)
  }
},

编辑禁用输入框

在添加时,是不需要禁用某些输入框的,但是编辑时需要的,所以在编辑时,除了要传数据,还要传 disabledList

// 如果不是默认产品就可以这样
this.$refs.baseDialogRef.handleAction({
	action: 'edit',
	data: { step1: res }, // !回显要加上是第几步的表单数据
	disabledList: { step1: ['productName', 'limitDays'] } // 指定第几步的禁用
})

配置文件禁用输入框

比如说一开始就不可以输入的框,或者是类似于第二步的添加等级,都是死的,从头到尾,无论是添加还是编辑都是禁用的,那么就可以使用

formMain: [
	{
		value: 'appId',
		type: 'select',
		label: 'setProduct.appId',
		disabled: true
	},
	{
		value: 'creditLevel',
		type: 'input',
		label: 'setProduct.creditLevel',
		disabled: true
	}
]

动态回显修改表单数据

this.$refs.baseDialogRef.setFormData({
	stepName: 'step2',
	value: data // !回显要加上是第几步的表单数据
})

配置处理,添加属性

initLevelForm () { // 第二步的表单
  const formMain = filterData(
    addLevelForm(this).formMain,
    [
      {
        appId: [
          ...getVestApp(this.enumerate.appId, this.setting.curSystem.value)
        ]
      }
    ],
    'options'
  )
  return { ...addLevelForm(this), formMain }
}

中途添加步骤

// <base-dialog @selectUpdate="hasSetLevel">
hasSetLevel (data) { // 选择框产品类型更换决定是否有第二步
  const { value = 3, step } = data
  if (step === 1) {
    this.productTypeActive = value
  }
}
// <base-dialog v-bind="productDialogConfig">
import { proActionConfig } from './config/productConfig/pro-action.config'
computed: {
    proActionConfig() {
        const config = proActionConfig(this)
        let formList = dialogFilterData( // 第一步配置过滤
            config.formList,
            1,
            [
              {
                appId: [
                  ...getVestApp(this.enumerate.appId, this.setting.curSystem.value)
                ]
              }
            ],
            'options'
        )
        if (this.productTypeActive === 1) {
            formList.push({ // 添加步骤
              addTitle: '第2步',
              editTitle: this.$t('编辑'),
              confirmText: 'confirm',
              cancelText: 'cancel',
              prevText: 'prev',
              nextText: 'next',
              step: 2, // 这是第几步才会出现的表单
              name: 'step2', // 表单的数据绑定
              initForm: this.initLevelForm
            })
        } else {
            formList.length === 2 && formList.pop()
        }
        return { ...config, formList }
    }
}

修改初始化 echoFormList

利用 initEchoFormList 函数

productDialogConfig () {
    const config = proActionConfig(this)
    const echoFormList = initEchoFormList(config.echoFormList, [
        {
            name: 'step2',
            initForm: {
              appId: this.appId
            }
        }
    ])
    return { ...config, formList }
}

显示弹窗并初始化

handleAddProduct () {
  this.$refs.baseDialogRef.handleAction({ action: 'add' })
}

确认 action

// <base-dialog @actionNextSubmit="actionNextSubmit">
actionNextSubmit (value) {
  // 弹窗确认数据
  const { formData, step, formList, stepName, action } = value
  let product
  let data = { ...formData }

  if (step === 1) {
    product = this.productFilter(data)
    if (product) {
      if (data.productType === 1) { // 默认产品有第二步,先不发送请求
        this.$refs.baseDialogRef.stepControl('next', 2)
      } else {
        action === 'add' && this.addProduct(product)
        action === 'edit' && this.editProduct(product)
      }
    }
  } else if (step === 2) {
    product = this.productFilter(formList['step1'])
    if (product) {
      action === 'add' && this.addProduct(product)
      action === 'edit' && this.editProduct(product)
    }
  }
}

computed-table

<computed-table
	class="computed_table"
	ref="computedAfterFeeRef"
	queryName="computedAfter"
	:initTable="afterFeeList"
	:initData="afterFeeData"
	:isNeedStorage="false"
>
    <!-- @updateData="feeUpdateData" -->
    <template #leftTitle>
      <div>
        <p>{{ $t('setProduct.afterLoanFee') }}</p>
        <a-button type="primary" @click="handleAfterFee('add')">
          <a-icon type="plus" />
        </a-button>
      </div>
    </template>
    <template #handle="scope">
      <a-button type="danger" @click="handleAfterFee('delete', scope.row)"
        ><a-icon type="delete"
      /></a-button>
    </template>
  </computed-table>

添加删除表单项

handleBeforeFee (action = 'add', row) {
  const uniqueId = _uniqueId()
  if (action === 'add') {
    this.$refs.computedBeforeFeeRef.handleAddDelete('add', {
      uniqueId,
      name: '', // 费用名称
      fixedCharge: 0, // 固定费用金额
      rate: 0 // 砍头利率
    })
  } else {
    this.$refs.computedBeforeFeeRef.handleAddDelete('delete', row.uniqueId)
  }
}

重置表格数据

// <base-dialog  @cancelAction="resetFeeActionTable">
// 当弹窗消失时重置表格数据
resetFeeActionTable () {
  this.beforeFeeData = []
  this.afterFeeData = []
}

编辑表格

  • @click="$refs.productActionRef.handleEditProduct(scope.row)"

  • async handleEditProduct (_) {
      try {
        const res = await this.$api(...) // 获取回显数据,其中包括了表格和表单数据
        let bfFee
        if (res.preLoanFeeSettings.length !== 0) {
          bfFee = res.preLoanFeeSettings.map((item) => { // 添加唯一标识,方便删除和添加
            return { ...item, uniqueId: _uniqueId() }
          })
        }
        this.beforeFeeData = bfFee || [] // 赋值给data,因为传过去的数据也是data中的数据
        let { logList ...params } = res // 删除回显数据中不需要的属性
        this.$refs.baseDialogRef.handleAction({
          action: 'edit',
          data: { step1: params }, // !回显要加上是第几步的表单数据
          disabledList: { step1: ['productName', 'limitDays'] } // 指定第几步的禁用项
        })
      } catch (error) {
        console.log(error)
      }
    }
  • handleAction ({ action = 'add', data = {}, disabledList = {} }) {
      this.switchVisible() // 先初始化,不然会覆盖后面的回显数据
      this.action = action
      if (this.action === 'edit') {
        // 如果是编辑需要回显数据
        this.formData = { ...data }
      }
      this.disabledList = { ...disabledList }
    }

About

基于AntDesige二次封装的组件


Languages

Language:JavaScript 94.4%Language:Vue 5.3%Language:CSS 0.2%Language:HTML 0.1%