专家库选取功能

以下两张图是专家库覆盖算法

选取专家类型的HTML结构

<el-cascader placeholder="请选择专家类型" :options="specialtyCategoryOption" :props="{multiple:true,emitPath:false }" collapse-tags clearable v-model="form.expertType" @change="getExpertListByType"/>

第一步 筛选出满足特长的专家 

/* 变量介绍

选中的特长类型
type=[1,2,7,8,9,10,] 

当前专家库里满足目前选中的特长类型  true则代表有,false则代表是没有,默认为false
typeObj={ 
    1:false,
    2:false,   
    7:false,
    8:false,
    9:false,
    10:false,
}

经过筛选后,满足选中特长类型的专家将保存在改变量中
selectExpertsList =[ 
    {    
        name:'张三',//专家姓名
        specialtyCategory:'1,2,5,6',//该专家所拥有的特长
        meetStrengths:[1,2],//满足当前选中的特长 
        meetStrengthsStr:'1,2',//满足当前选中的特长 
        agreementStatus:true //该专家没有拒绝过该项目
    },.......
]
*/

//选特长时触发  
    getExpertListByType(type){
      this.expertType = type
      if(type.length == 0) return  //未选中特长时 跳出函数

      let typeObj = {}
      type.forEach(v=>{
         typeObj[v]=false //初始化,所有值都未命中状态
      })

      //挑出满足条件的专家 且 找出所有专家都没有满足的特长
      let selectExpertsList = this.allExperts.filter(val=>{
        let useType = val.specialtyCategory.split(',');
        let isSatisfy = false 
        val.meetStrengths = []
        val.meetStrengthsStr = ''
        if(val.agreementStatus === false ) return false // 如果该专家拒绝过 直接跳过
        useType.forEach(v=>{
          if((typeObj.hasOwnProperty(v))){
            isSatisfy =true //该专家满足所有特长中一个
            typeObj[v] = true //命中则置为true
            if(val.meetStrengthsStr==''){
              val.meetStrengthsStr = v
            }else{
              val.meetStrengthsStr = val.meetStrengthsStr+','+v
            }
            val.meetStrengths.push(v)
          }
        })
        return isSatisfy
      })
      this.selectExpertsList = selectExpertsList
    },

将符合选中特长的专家,按命中的特长作分类存在变量combination中

/*  经过整合后combination的结构会是这样的
combination:{
    '1,2':[
            {    
                name:'张三',//专家姓名
                specialtyCategory:'1,2,5,6',//该专家所拥有的特长
                meetStrengths:[1,2],//满足当前选中的特长 
                meetStrengthsStr:'1,2',//满足当前选中的特长 
                agreementStatus:true //该专家没有拒绝过该项目
             },
             {    
                name:'李四',//专家姓名
                specialtyCategory:'1,2,4,6',//该专家所拥有的特长
                meetStrengths:[1,2],//满足当前选中的特长 
                meetStrengthsStr:'1,2',//满足当前选中的特长 
                agreementStatus:true //该专家没有拒绝过该项目
             },
          ],
    '7,8,9':[
            {    
                name:'小明',//专家姓名
                specialtyCategory:'5,6,8,9',//该专家所拥有的特长
                meetStrengths:[8,9],//满足当前选中的特长 
                meetStrengthsStr:'8,9',//满足当前选中的特长 
                agreementStatus:true //该专家没有拒绝过该项目
             },
          ],
    '8,9,10':[
            {    
                name:'小明',//专家姓名
                specialtyCategory:'3,4,6,8,9,10',//该专家所拥有的特长
                meetStrengths:[8,9,10],//满足当前选中的特长 
                meetStrengthsStr:'8,9,10',//满足当前选中的特长 
                agreementStatus:true //该专家没有拒绝过该项目
             },
          ],.......
}
*/
//随机抽取专家(有几个专家,抽几个专家) 整合数据
processingData(){
    if(this.tix()) return 
    if(this.reviewForm.passed==="1") return this.$message({ type: "error", message: "评审已经通过(抽选结束)!" });
    this.getExpertListByType(this.expertType) //重新获取满足条件的专家
    let combination = this.specialityGrouping()//专家按命中的特长类型分组
    this.arrange(combination,this.expertNumber,false)
},
//将专家按命中的特长类型分组
specialityGrouping(){
  let combination = {} 
  this.selectExpertsList.forEach(v=>{//将专家按命中的特长类型分组
    if(!combination.hasOwnProperty(v.meetStrengthsStr)){
      combination[v.meetStrengthsStr] = []
    }
    combination[v.meetStrengthsStr].push(v)
  })
  return combination
},

抽取专家方法 : arrange()、combination这是按专家按命中的特长类型分组、num专家数量、isByElection是否是补选

// combination这是按专家按命中的特长类型分组 num专家数量
arrange(combination,num,isByElection){
  let key = Object.keys(combination)
  let amount = num
  let allAmount = num
  let keyLen = key.length
  if(keyLen < amount ){ //当专家种类少于专家数量时
    // diff = amount - keyLen // 多出来的 后续抽取
    amount  = keyLen
  }
  // var allArr = [...new Set(key.flatMap(item => item.split(',')))]
  // console.log(allArr)
  let maxCombinations = this.combinations(key,amount) //得到最大限度满足特长的几
组合
  const index = this.getRandomInt(0,maxCombinations.length-1) //随机生成一个整数
  let randomCombination = maxCombinations[index] //从maxCombinations中随机获取其中一个组合
  let expertList = [] //存放专家的变量
  randomCombination.forEach(v=>{//从抽取的组合下,随机抽取专家
    let arr = combination[v]//获取该特长的所有专家
    const index = this.getRandomInt(0,arr.length-1)
    arr[index].teamLeader = 0
    expertList.push(arr[index])
  })
  let currentExpertNum = expertList.length
  let diffExpertNum =allAmount - currentExpertNum // 算出还差几个专家数量,差的这
几个就直接抽取,因为expertList变量里存的专家已经最大限度去覆盖了所选的特长。
  if(isByElection){//是否是补选
    this.selectedExpertsList = this.selectedExpertsList.concat(expertList)
  }else{
    this.selectedExpertsList = [...expertList]
  }
  for(let i = 0;i<diffExpertNum;i++){
    this.expertDeduplication()//先过滤专家库里的专家
    this.randomSelectEvent()//然后再随机抽取专家
  }
},
combinations(input, length) {//排列组合 找出满足特长最多的组合
  let maxLen = 0;
  let maxCombination = [];
  function recurse(prefix, remaining, k) {
    if (k === 0) {
      var newArr = prefix.flatMap(item => item.split(','));
      var uniqueArr = [...new Set(newArr)];
      if(uniqueArr.length > maxLen){
        maxLen = uniqueArr.length
        maxCombination = []
        maxCombination.push(prefix)
      }else if (uniqueArr.length == maxLen){
        maxCombination.push(prefix)
      }
      // result.push(prefix);
      return;
    }
    for (var i = 0; i < remaining.length; i++) {
      recurse(prefix.concat(remaining[i]), remaining.slice(i + 1), k - 1);
    }
  }
  for(let i=1;i<=length;i++){
    recurse([], input, i);
  }
  // recurse([], input, length);
  return maxCombination;
},

 expertDeduplication:去重函数,主要从专家库里过滤掉已选的专家

expertDeduplication(){ //专家库去重操作 已选的专家:selectedExpertsList 专家库:selectExpertsList
  let selectExpertsList = this.selectExpertsList
  //过滤专家库里已选的专家
  this.selectedExpertsList.forEach(item => {
    selectExpertsList = selectExpertsList.filter(i=> {
      /*
      item.name != i.name 过滤已选的专家  不使用id是因为后端接口返回的已选专家的id与专家库里的id不是同一个东西
      item.agreementStatus !== false 过滤拒绝的专家
       */
      return item.name != i.name //|| item.agreementStatus !== false  
    })
  })
  this.selectExpertsList = selectExpertsList//过滤掉已选专家后专家库里的专家

 randomSelectEvent : 消息提醒函数

setActiveExperts:随机抽取一个专家

randomSelectEvent(){
  if (!this.form.projectName) return this.$message({ type: "error", message: "请选择项目" });
  if(this.selectedExpertsList.length>=this.expertNumber) return this.$message({ type: "error", message: "不得超过规定的专家数量!" });
  if(!this.selectExpertsList.length) return this.$message({ type: "error", message: "没有可以抽取的专家数据!" });
  this.setActiveExperts()
},
setActiveExperts(){
  const index = this.getRandomInt(0,this.selectExpertsList.length-1)//生成随机数
  if(this.isExistExperts(this.selectExpertsList[index])) return this.randomSelectEvent() //如果存在则重新抽取
  this.activeExperts = this.selectExpertsList[index];
  let num =0
  // if(this.selectedNumber == 0) num = 1  //当选出第一个专家时,默认他为组长
  // else num = 0
  this.$set(this.activeExperts,'teamLeader',num)
  this.selectExpertsList.splice(index,1)
  this.selectName = this.activeExperts.name;
  this.selectedExpertsList.push(this.activeExperts)
//判断已选取列表是否已存在
isExistExperts(data){
  const res = this.selectedExpertsList.find(item=>item.id === data.id)
  return !!res
},
// 获取随机数
getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
},

                  在保持原有的专家不变情况下增加专家数量。

<el-button type="primary" style="width: 150px;margin-left: 0px;margin-top: 50px;" @click="byElection" :disabled="this.reviewForm.passed==='1'">补选随机抽取并添加</el-button>

byElection:补选函数

//补选随机抽取专家(缺几个专家,抽几个专家)
byElection(){
  if(this.tix()) return 
  if(this.reviewForm.passed==="1") return this.$message({ type: "error", message: "评审已经通过(抽选结束)!" });
  //补选需要过滤已选的专家和拒绝的专家
  this.expertDeduplication()
  let combination = this.specialityGrouping()
  let diffNum = this.expertNumber - this.selectedExpertsList.length
  if(diffNum == 0 ) return
  this.arrange(combination,diffNum,true)
},

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值