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!
要求二:付出成果占比低的人同样可以成为主Producer,"Share Commission"与"Share Production" 均可以为0,但是在提交的时候需要弹出中断流程的提示框进行提示,经确认后才可提交审核!
要求三:同一个团队下,各个Producer人员的"Share Commission"与"Share Production"值相加应等于100!
要求四:默认情况下,只有同一个团队下人员之间可以更换主Producer,非同一个团队不能随意更换主Producer!
要求五:选择对应的主Producer时,对应的销售人员团队编码和员工编码不能为空!
要求六:拆分的Producer不能相同,例如不能第一行是员工A,第二行拆分时还是添加的员工A,员工不可重复!
1.2 需求分析
(1)因为不同的团队可能出现相同的员工姓名编码例如"A团队001的张三","B团队001的张三",员工编号可能重复不一定唯一,所以我们不能将员工编号直接作为单选框的值,但是如果使用"团队码值+员工码值",就可以确定一个唯一的销售人员了,不能只我们将字段名称就定义为"mainProducer";
(2)":label"标签采用的是中文文国际版,所以字段名称单独定义在其它文件作为Vue组件导入到此,因此我们在定义的时候也遵循这种设计理念,将添加的"主Producer"也在对应的文件中进行添加;
(3)因为是单选框,通过点击来进行选择主Producer,所以我们可以给单选框绑定一个 "@change" 函数,每当我的单选发生改变时,就去执行 change 函数,这样一来,我们就可以将需求要求的校验写在 change 函数中;
二. 代码实现
2.1 原代码分析
如下代码,是原本页面上已经存在的代码,可以看出一个表格,所以我们直接在原有的表格中添加即可。
表格中采用了 ElementUI 表格组件,
-
:data="splitForm.splitData"
:绑定表格数据源,来自splitForm
对象的splitData
数组 ,数据来源通常为后端返回; -
slot-scope="scope":
是 Vue.js 和 ElementUI 中用于表格列模板的一种特殊语法,它提供了对当前行数据的访问能力, -
scope 对象内容:
-
scope.row
:当前行的数据对象 -
scope.$index
:当前行的索引(从0开始) -
scope.column
:当前列的信息 -
scope.store
:表格的存储状态
-
<el-table :data="splitForm.splitData" :header-cell-style="{'text-align':'center'}" :cell-style="{'text-align':'center'}" style="width: 100%;"><!-- 渠道类型 --><el-table-column :label="$t('feeSplit.feeSplit.qudaoleixing')" width="180px"><template slot-scope="scope"><el-form-item label-width="-120px"><el-form-item :prop="'splitData.' + scope.$index + '.businessNature'" :rules="pageRules.businessNature"><code-select v-model="scope.row.businessNature" code-type="ChannelTypeLv1" :disabled="!lookShowBtu || scope.row.dataFlag === '1' || scope.row.firstFlag" clearable @change="clearChild(scope.row, 'businessNature')" /></el-form-item></el-form-item></template></el-table-column><!-- producer --><el-table-column :label="$t('feeSplit.feeSplit.Procucer')" width="140px"><template slot-scope="scope"><el-form-item label-width="-120px"><el-form-item :prop="'splitData.' + scope.$index + '.producerCode'" :rules="pageRules.producerCode"><code-searchv-model="scope.row.producerCode"show-code:show-name="false"code-type="ProducerInPolicy":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"@change="refFillProducer(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')" width="180px"><template slot-scope="scope"><el-input v-model="scope.row.producerName" :title="scope.row.producerName" disabled /></template></el-table-column><!-- 渠道细分 --><el-table-column :label="$t('feeSplit.feeSplit.qudaoxifen')" width="180px"><template slot-scope="scope"><el-form-item label-width="-120px"><el-form-item :prop="'splitData.' + scope.$index + '.businessNatureSub'" :rules="pageRules.businessNatureSub"><code-select v-model="scope.row.businessNatureSub" code-type="ChannelTypeLv2" :parent-code="scope.row.businessNature" :disabled="!lookShowBtu || scope.row.dataFlag === '1' || scope.row.firstFlag" clearable @change="clearChild(scope.row, 'businessNatureSub')" /></el-form-item></el-form-item></template></el-table-column><!-- 经办人代码 --><el-table-column :label="$t('feeSplit.feeSplit.yewuyuandaima')" width="120px"><template slot-scope="scope"><el-form-item label-width="-120px"><el-form-item :prop="'splitData.' + scope.$index + '.producerSubCode'" :rules="pageRules.producerSubCode"><code-searchv-model="scope.row.producerSubCode"show-code:show-name="false"code-type="HandlerInPolicyModel":include-codes="scope.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"@change="refFillHandler(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')" width="180px"><template slot-scope="scope"><el-input v-model="scope.row.producerSubName" disabled /></template></el-table-column><!-- 销售团队 --><el-table-column :label="$t('feeSplit.feeSplit.xiaoshoutuandui')" width="150px"><template slot-scope="scope"><code-search v-model="scope.row.teamCode" code-type="TeamCodeHis" disabled /></template></el-table-column><!-- 业绩归属机构 --><el-table-column :label="$t('feeSplit.feeSplit.yejiguishujigou')" width="120px"><template slot-scope="scope"><code-trans v-model="scope.row.comCode" code-type="Company" />
<!-- <code-search v-model="scope.row.comCode" code-type="Company" disabled />--></template></el-table-column><!-- share commission --><el-table-column :label="$t('feeSplit.feeSplit.ShareCommission')" width="150px"><template slot-scope="scope"><el-input-numberv-model="scope.row.shareCommission":disabled="!lookShowBtu":precision="2":controls="false"style="width: 100px"@change="numberChange(scope.row.shareCommission,scope.$index,0)"/></template></el-table-column><!-- share production --><el-table-column :label="$t('feeSplit.feeSplit.ShareProduction')" width="150px"><template slot-scope="scope"><el-input-numberv-model="scope.row.shareProduction":disabled="!lookShowBtu":precision="2":controls="false"style="width: 100px"@change="numberChange(scope.row.shareProduction,scope.$index,1)"/></template></el-table-column>
</el-table>
2.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')" width="130px" align="center"><template slot-scope="scope"><el-radio v-model="selectMainProducerCode":label="getMainProducerKey(scope.row.producerCode, scope.row.producerSubCode)"@change="updateMainAgent(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.prevSelectMainBusinessNaturethis.selectMainProducerCode = this.prevSelectMainProducerCode});return;}// 5. 若选择的 Producer 非空,将此次选择的 Producer 保存用于后续回滚操作使用, 上一次选中的Producer的Id值this.prevSelectMainProducerCode = producerCode + handlerCodethis.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// 循环遍历修改后的集合数据,计算shareCommission,shareProduction各自的总和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 = truereturn}// 比较所有拆分对象是否有重复numsIn = 0this.splitForm.splitData.forEach(elementIn => {if (nums !== numsIn && elementIn.producerCode === element.producerCode && elementIn.producerSubCode === element.producerSubCode) {proFlag = truereturn}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不能相同,需求要求六验证成功。