Vue + Element UI 实现单选框

发布于:2025-07-18 ⋅ 阅读:(19) ⋅ 点赞:(0)

目录

一. 需求描述+需求分析

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-search
            v-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-search
            v-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-number
        v-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-number
        v-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.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
          // 循环遍历修改后的集合数据,计算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 = 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不能相同,需求要求六验证成功。

 


网站公告

今日签到

点亮在社区的每一天
去签到