Vue + Element UI 实现单选框 目录一. 需求描述需求分析1.1 需求描述1.2 需求分析二. 代码实现2.1 原代码分析2.2 新增代码编写三. 效果展示3.1 需求目标一验证3.2 需求目标二验证3.3 需求目标三验证3.4 需求目标四验证3.5 需求目标五验证3.6 需求目标六验证一. 需求描述需求分析1.1 需求描述如下图所示是一个销售管理后台的修改页面我类似地将各个字段的含义做了简单的标注Producer 大家可以理解为销售人员(中介)假设一件商品是由甲、乙、丙......等非单独一个人推销卖出的产品那么这些人中就有一个一定付出的努力最大所以得到的报酬也应该最多。因此现在要新增一个主附Producer单选框标记出来谁是主Producer方便后台计算员工薪酬奖金。要求一如果只有一个人员则默认为主Producer要求二付出成果占比低的人同样可以成为主ProducerShare Commission与Share Production均可以为0但是在提交的时候需要弹出中断流程的提示框进行提示经确认后才可提交审核要求三同一个团队下各个Producer人员的Share Commission与Share Production值相加应等于100要求四默认情况下只有同一个团队下人员之间可以更换主Producer非同一个团队不能随意更换主Producer要求五选择对应的主Producer时对应的销售人员团队编码和员工编码不能为空要求六拆分的Producer不能相同例如不能第一行是员工A第二行拆分时还是添加的员工A员工不可重复1.2 需求分析1因为不同的团队可能出现相同的员工姓名编码例如A团队001的张三B团队001的张三员工编号可能重复不一定唯一所以我们不能将员工编号直接作为单选框的值但是如果使用团队码值员工码值就可以确定一个唯一的销售人员了不能只我们将字段名称就定义为mainProducer2:label标签采用的是中文文国际版所以字段名称单独定义在其它文件作为Vue组件导入到此因此我们在定义的时候也遵循这种设计理念将添加的主Producer也在对应的文件中进行添加3因为是单选框通过点击来进行选择主Producer所以我们可以给单选框绑定一个 change 函数每当我的单选发生改变时就去执行 change 函数这样一来我们就可以将需求要求的校验写在 change 函数中二. 代码实现2.1 原代码分析如下代码是原本页面上已经存在的代码可以看出一个表格所以我们直接在原有的表格中添加即可。表格中采用了 ElementUI 表格组件:datasplitForm.splitData绑定表格数据源来自splitForm对象的splitData数组 数据来源通常为后端返回slot-scopescope:是 Vue.js 和 ElementUI 中用于表格列模板的一种特殊语法它提供了对当前行数据的访问能力scope 对象内容scope.row当前行的数据对象scope.$index当前行的索引从0开始scope.column当前列的信息scope.store表格的存储状态el-table :datasplitForm.splitData :header-cell-style{text-align:center} :cell-style{text-align:center} stylewidth: 100%; !-- 渠道类型 -- el-table-column :label$t(feeSplit.feeSplit.qudaoleixing) width180px template slot-scopescope el-form-item label-width-120px el-form-item :propsplitData. scope.$index .businessNature :rulespageRules.businessNature code-select v-modelscope.row.businessNature code-typeChannelTypeLv1 :disabled!lookShowBtu || scope.row.dataFlag 1 || scope.row.firstFlag clearable changeclearChild(scope.row, businessNature) / /el-form-item /el-form-item /template /el-table-column !-- producer -- el-table-column :label$t(feeSplit.feeSplit.Procucer) width140px template slot-scopescope el-form-item label-width-120px el-form-item :propsplitData. scope.$index .producerCode :rulespageRules.producerCode code-search v-modelscope.row.producerCode show-code :show-namefalse code-typeProducerInPolicy :other-conditions{ ChannelTypeLv1:scope.row.businessNature, ChannelTypeLv2:scope.row.businessNatureSub, comCode: scope.row.policyComCode, riskCode:scope.row.riskCode,dsProducer:scope.row.dsProducer } :disabled!lookShowBtu || scope.row.dataFlag 1 || scope.row.firstFlag changerefFillProducer(scope.$index, ...arguments), clearChild(scope.row, producerCode) / /el-form-item /el-form-item /template /el-table-column !-- producer name -- el-table-column :label$t(feeSplit.feeSplit.ProcucerName) width180px template slot-scopescope el-input v-modelscope.row.producerName :titlescope.row.producerName disabled / /template /el-table-column !-- 渠道细分 -- el-table-column :label$t(feeSplit.feeSplit.qudaoxifen) width180px template slot-scopescope el-form-item label-width-120px el-form-item :propsplitData. scope.$index .businessNatureSub :rulespageRules.businessNatureSub code-select v-modelscope.row.businessNatureSub code-typeChannelTypeLv2 :parent-codescope.row.businessNature :disabled!lookShowBtu || scope.row.dataFlag 1 || scope.row.firstFlag clearable changeclearChild(scope.row, businessNatureSub) / /el-form-item /el-form-item /template /el-table-column !-- 经办人代码 -- el-table-column :label$t(feeSplit.feeSplit.yewuyuandaima) width120px template slot-scopescope el-form-item label-width-120px el-form-item :propsplitData. scope.$index .producerSubCode :rulespageRules.producerSubCode code-search v-modelscope.row.producerSubCode show-code :show-namefalse code-typeHandlerInPolicyModel :include-codesscope.row.handleCodeList :other-conditions{ ChannelTypeLv1:scope.row.businessNature, ChannelTypeLv2:scope.row.businessNatureSub, Producer:scope.row.producerCode } :disabled!lookShowBtu || scope.row.dataFlag 1 || scope.row.firstFlag || scope.row.subFlag changerefFillHandler(scope.$index, ...arguments), clearChild(scope.row, producerSubCode) / /el-form-item /el-form-item /template /el-table-column !-- 经办人名称 -- el-table-column :label$t(feeSplit.feeSplit.yewuyuanmingcheng) width180px template slot-scopescope el-input v-modelscope.row.producerSubName disabled / /template /el-table-column !-- 销售团队 -- el-table-column :label$t(feeSplit.feeSplit.xiaoshoutuandui) width150px template slot-scopescope code-search v-modelscope.row.teamCode code-typeTeamCodeHis disabled / /template /el-table-column !-- 业绩归属机构 -- el-table-column :label$t(feeSplit.feeSplit.yejiguishujigou) width120px template slot-scopescope code-trans v-modelscope.row.comCode code-typeCompany / !-- code-search v-modelscope.row.comCode code-typeCompany disabled /-- /template /el-table-column !-- share commission -- el-table-column :label$t(feeSplit.feeSplit.ShareCommission) width150px template slot-scopescope el-input-number v-modelscope.row.shareCommission :disabled!lookShowBtu :precision2 :controlsfalse stylewidth: 100px changenumberChange(scope.row.shareCommission,scope.$index,0) / /template /el-table-column !-- share production -- el-table-column :label$t(feeSplit.feeSplit.ShareProduction) width150px template slot-scopescope el-input-number v-modelscope.row.shareProduction :disabled!lookShowBtu :precision2 :controlsfalse stylewidth: 100px changenumberChange(scope.row.shareProduction,scope.$index,1) / /template /el-table-column /el-table2.2 新增代码编写:lable 标签导入的文件如下所示展示部分我们新添加的单选框名称也在这个文件中添加即可export default { mainProducerFlag: 主Producer, // 新增主Producer标识作为表格列名 qudaoleixing: 渠道类型, Procucer: Producer, ProcucerName: Producer Name, ShareCommission: Share Commission, ShareProduction: Share Production ...... }新添加单选框主体代码我们就直接加在表格table代码块最上面即可然后我们在 Vue 的 data 数据中添加 v-mode 绑定的 selectMainProducerCode 属性!-- 主producer标识单选框 -- el-table-column :label$t(feeSplit.feeSplit.mainProducerFlag) width130px aligncenter template slot-scopescope el-radio v-modelselectMainProducerCode :labelgetMainProducerKey(scope.row.producerCode, scope.row.producerSubCode) changeupdateMainAgent(scope.row.producerCode, scope.row.producerSubCode,scope.row.businessNature) /el-radio /template /el-table-column data() { return { selectMainProducerCode: null, // 费用拆分单选主Producer对应的十位码值(producerCode handlerCode) prevSelectMainProducerCode: null, // 上一次单选选择的主Producer对应的十位码值(producerCode handlerCode) selectMainBusinessNature: null, // 主Producer的渠道类型 prevSelectMainBusinessNature: null, // 上一次单选选择的主Producer对应的渠道类型 } }, methods: { // 在 methods 中添加单选标签值计算函数动态的根据每一行的团队编码员工编码得出一个唯一标识 // 用于与 data 中的 selectMainProducerCode匹配相同则被选中不通则不被选中 getMainProducerKey(producerCode,producerSubCode) { return producerCode producerSubCode }, // 编写绑定的 change 函数函数传递三个参数 // 参数一选中行的团队编码用于计算十位唯一值 // 参数二选中行的员工编码用于计算十位唯一值 // 参数三选中行的渠道类型用于判断新选的Producer是否与原Producer渠道相同实现需求的要求四 // 结合上面的getMainProducerKey方法得出的十位唯一值就可以判断当前行对应的员工是否被选中 updateMainAgent(producerCode,handlerCode,businessNature){ // 1. 判空.若为空则提示请选择 Producer, // 此步判断实现需求的要求五对应的销售人员团队编码和员工编码不能为空 if (!producerCode || producerCode || !handlerCode || handlerCode ) { this.$message({ type: warning, message: this.$t(请先选择Producer和经办人代码) }) // 2. 弹出提示框后回滚到上一个选择的 Producer, 然后 return 返回 this.$nextTick(() { this.selectMainProducerCode this.prevSelectMainProducerCode }); return; } // 3. 判断新选择的主Producer渠道类型需与原主Producer渠道类型是否一致 // 此步判断实现需求的要求四非同一个团队不能随意更换主Producer if (this.prevSelectMainBusinessNature ! null this.prevSelectMainBusinessNature ! businessNature){ this.$message({ type: warning, message: this.$t(新选择的主Producer渠道类型需与原主Producer渠道类型一致) }) // 4. 弹出提示框后回滚到上一个选择的 Producer 和 渠道类型值 this.$nextTick(() { this.selectMainBusinessNature this.prevSelectMainBusinessNature this.selectMainProducerCode this.prevSelectMainProducerCode }); return; } // 5. 若选择的 Producer 非空,将此次选择的 Producer 保存用于后续回滚操作使用, 上一次选中的Producer的Id值 this.prevSelectMainProducerCode producerCode handlerCode this.selectMainProducerCode producerCode handlerCode }, // 弹出费用拆分弹窗 feeSplit() { const splitForm { splitData: [{ businessNature: this.selection[0].businessNature, businessNatureSub: this.selection[0].businessNatureSub, producerCode: this.selection[0].producerCode, producerName: this.selection[0].producerName, producerSubCode: this.selection[0].handlerCode, producerSubName: this.selection[0].handlerName, teamCode: this.selection[0].teamCode, teamName: this.selection[0].teamName, comCode: this.selection[0].branchCode, // producer的归属机构 即保单的业绩归属机构对应 shareCommission: 100, shareProduction: 100, permitNo: , permitName: , mobile: , interAddress: , // comCode: this.selection[0].comCode, riskCode: this.selection[0].riskCode, // 产品 firstFlag: true, // 第一行数据 subFlag: false, // 经办人是否可修改 handelCodeList: [] }] } // 下面四行代码用于初始化值实现需求的要求一“如果只有一个人员则默认为主Producer”。 // 未进行拆分说明只有一个人默认选择第一条记录作为主Producer this.selectMainProducerCode this.selection[0].producerCode this.selection[0].handlerCode // 未进行拆分说明只有一个人默认选择第一条记录作为主Producer 记录值用于回滚操作 this.prevSelectMainProducerCode this.selection[0].producerCode this.selection[0].handlerCode // 记录当前的渠道类型值用于判断新选择的Producer渠道类型是否与当前渠道类型值相同 this.selectMainBusinessNature this.selection[0].businessNature // 记录当前的渠道类型值用于回滚操作 this.prevSelectMainBusinessNature this.selection[0].businessNature }, // 保函数 submitButton(passCommpaymentCheck) { this.$refs[splitForm].validate(async valid { // 这里我只编写了新增的逻辑其它原有的表单逻辑已省略...... // Share Commission总和必须为100%供后续作为标识做判断 let comNum 0 // Share Production总和必须为100%供后续作为标识做判断 let proNum 0 // 拆分数据producer相同标识 let proFlag false // 主Producer的shareCommission,shareProduction均为0标识 let mainProducerShareCommissionAndShareProductionIsZeroFlag false // 循环遍历修改后的集合数据计算shareCommissionshareProduction各自的总和 this.splitForm.splitData.forEach(element { if (element.producerCode element.producerSubCode this.selectMainProducerCode){ if (element.shareCommission 0 element.shareProduction 0){ mainProducerShareCommissionAndShareProductionIsZeroFlag true } element.agentFlag 1 }else { element.agentFlag 0 } comNum math.add(comNum, (element.shareCommission undefined || element.shareCommission ) ? 0 : element.shareCommission) proNum math.add(proNum, (element.shareProduction undefined || element.shareProduction ) ? 0 : element.shareProduction) if ((element.shareCommission undefined || element.shareCommission ) (element.shareProduction undefined || element.shareProduction )) { numFlag true return } // 比较所有拆分对象是否有重复 numsIn 0 this.splitForm.splitData.forEach(elementIn { if (nums ! numsIn elementIn.producerCode element.producerCode elementIn.producerSubCode element.producerSubCode) { proFlag true return } numsIn }) nums }) // 若主Producer的shareCommission,shareProduction均为0则弹出提示框 // 这一步判断实现了需求的要求二 if (mainProducerShareCommissionAndShareProductionIsZeroFlag){ try { await this.$confirm( this.$t(请注意主Producer的share Commission和share Production都为0请确认是否提交), this.$t(请确认), { confirmButtonText: this.$t(common.ok), cancelButtonText: this.$t(common.close), type: warning } ); } catch (error) { // 用户点击了取消或关闭弹窗 return; } } // 这一步判断实现了需求的要求六员工不可重复拆分 // 判断拆分数据的producer是否相同相同弹出提示框 if (proFlag) { this.$message({ type: warning, message: this.$t(拆分数据的producer不能相同!) }) return } // 这一步判断实现了需求的要求三Share Commission值相加应等于100 // shareCommission总和必须为100%不为100则弹出提示框 if ((comNum ! 100)) { this.$message({ type: warning, message: this.$t(Share Commission总和必须为100%!) }) return } // 这一步判断实现了需求的要求三Share Production值相加应等于100 // shareProduction总和必须为100%不为100则弹出提示框 if ((proNum ! 100)) { this.$message({ type: warning, message: this.$t(Share Production总和必须为100%!) }) return } }) }, }三. 效果展示3.1 需求目标一验证选中一条数据进入到拆分页面可以发现如果只有一条数据那么会默认选中成为主Producer需求要求一验证成功3.2 需求目标二验证如下图所示我新增一条数据并设置为主Producer将他的Share Commission和Share Production全设置为0点击提交如下弹窗要求我们进一步确认方可提交需求要求二验证成功3.3 需求目标三验证如下我新增两条数据对其Share Commission和Share Production进行设置但相加不为100点击提交触发了 submit 提交校验弹出提示框需求要求三验证成功3.4 需求目标四验证我尝试更换团队编码点击选择另一个团队的销售人员作为主Producer如下图所示在点击的时候因为触发了 change 函数校验团队编码(渠道类型)必须相同否则无法选择需求要求四验证成功。3.5 需求目标五验证如下图所示我新增一条数据但是不选择 Producer点击单选框触发了 change 函数判空校验弹出一条提示信息提示要先选择Producer和经办人代码需求要求五验证成功。3.6 需求目标六验证我新增一条相同的Producer因为默认选择第一条作为主Producer所以新增的第二条也被选中但是没关系我们尝试提交尝试提交触发了 submit 提交函数校验如下图所示。也弹出中断提示框要求拆分的数据Producer不能相同需求要求六验证成功。