Browse Source

选科2级页面接口重做
选科1级页面术语更新

hare8999@163.com 3 years ago
parent
commit
9448bcbe23

+ 81 - 66
doc/Mind/ElectiveGeneration.cs

@@ -89,8 +89,15 @@ namespace mxdemo.Mind
 
     public class RoundForFlow : mxdemo.Mind.IStudentClassDispatchService.Round // Round到时候合并在一起
     {
-        bool AllMatched; // 所有学生匹配完毕,可以开始推进排名均衡或者分班
+        bool allMatched; // 所有学生录取完毕,可以开始推进排名均衡或者分班
         EnumElectiveGeneration currentGeneration; // 内部字段
+
+        // + new fields
+        int disenrollCount; // 未录取学生数量 - 用于图表展示,或者内部判定allMatched
+        // bool enablePushNextDMGeneration; // 是否可以强制推进下一代决策进程 = 当前为报名进程,且学生均已报名
+        bool allowDMAlgorithm; // 当前为决策进程,支持运行匹配算法(BackTrackingDM,FinalAdjustDM)
+        bool doneDMAlgorithm; // 当前为决策进程,且已经运行了匹配算法
+        bool allowForce; // 当前进程代是否允许强制调剂录取(原来BackTrackingDM,FinalAdjustDM,RankBalance),现在调整为(FinalAdjustDM,RankBalance)
     }
 
     // 1 初选决策时,需要进行设置
@@ -118,7 +125,7 @@ namespace mxdemo.Mind
         // 可能还有其它字段
     }
 
-    /*  
+    /*
      总则:ElectiveGenerationFlowData记录的是每一代数据的最终结果,如果想要更精细的记录,可以结合ElectiveGenerationFlowLog
     1 Generation.Init 可有可无,不需要生成初始数据?
 
@@ -127,7 +134,7 @@ namespace mxdemo.Mind
         ADD operation=Approved
 
         取消时:
-        UPDATE operation=Cancel 
+        UPDATE operation=Cancel
 
         排名挤出时-被挤出人:
         UPDATE operation=Disabled, remark = '排名挤出'
@@ -153,7 +160,7 @@ namespace mxdemo.Mind
         refId = ElectiveEsign.id // 生成一条待签记录
         // 这样的话签名与选科的代数据就可分割开了,具体说是否一定要学生签名才能推进下一代?
         // 我看未必,因为学校不可能因为个别钉子户就暂停教务
-        
+
         未录取,但自选专业满足
         ADD operation=Optional, groupId=推荐组合
         remark = 未录取原因
@@ -214,7 +221,7 @@ namespace mxdemo.Mind
 
             // 反向查询代码 将统计逻辑的条件关键字放入此代码,回传后台能反向解析并恢复明细
             // 想法:让统计全部基于ElectiveGenerationFlowData,形成一种或多种QueryDto{roundId:'',generation:'',groupId:''...}等, 序列化实际查询条件
-            string queryCode;
+            // string queryCode; // 4.18 此字段往上提升了1级放在了ElectiveSummaryCategory上,详情请看注释
             bool disabled; // 不支持查询
         }
 
@@ -225,6 +232,11 @@ namespace mxdemo.Mind
         {
             string category; // 身份标识,类似字段名/列名,可能被前端用来定制渲染模板
             string displayName; // 显示名称
+            string detailName; // 4.19 详情页对应的groupId的业务意义:如报名组合、录取组合、推荐组合、初录报名组合、...
+            string queryCode; // 4.18 如果直接查询,就定义此queryCode,前端会收拢此代所有的queryCode,在2级页面形成查询条件选项卡;
+                              // 4.18 后台需要一个配置,比如PrimaryDM代之后,整列没有数据直接隐藏,
+                              // 4.18 不向前端输出,以减少2级页面的条件项,因为随着选科进行,残留的学生越来越少,减少条件项可以帮助校长更快定位学生
+                              // 4.18 从原来ElectiveSummaryValue内部的queryCode升级而来,反查明细时由方法其它参数提供groupId, roundId, generation
 
             ElectiveSummaryValue[] values;
         }
@@ -279,41 +291,44 @@ namespace mxdemo.Mind
          *  {'actualCount','实际人数'},   -- 填报第X志愿的人数
          *  {'unfinishedCount','未完成人数'},  -- 未填报第X志愿的人数(根据ElectiveGenerationFlowData实际Approved&Rank情况统计即可,因为如果报名还在进行中,本身就是动态变化的东西)
          *  按第一志愿、第二志愿、...的顺序输出数据
-         *  
-         *  二、ElectiveGenerationDMSummary.accumulates 
+         *
+         *  二、ElectiveGenerationDMSummary.accumulates
          *  仅决策代需要统计此数据,决策代[PrimaryDM BackTrackingDM FinalAdjustDM RankBalance]
          *  // hht.22/4/12 同上,这个属性也不要了 {'expectedCount', '设置人数'} -- 选科设置人数
-         *  {'approvedCount', '正常录取人数'} -- 到此阶段为止,正常录取人数
+         *  {'approvedCount', '录取人数'} -- 到此阶段为止,正常录取人数
          *  {'forcedCount', '调剂录取人数'} -- 到此阶段为止,调剂录取人数
-         *  {'esignedCount', '已签人数'} -- 到此阶段为止,触发的有效签名统计
-         *  {'esigningCount', '待签人数'} -- 到此阶段为止,阶段触发有效的应签未签统计
-         *  
+         *  {'esignedCount', '已签人数'} -- 到此阶段为止,触发的有效签名统计 这个先
+         *  {'esigningCount', '待签人数'} -- 到此阶段为止,阶段触发有效的应签未签统计 [4.18 因为签字提前和强制调剂更改,所以只有FinalAdjustDM RankBalance这两代会产生待签数据了]
+         *
          *  三、ElectiveGenerationSummary.categories 只统计某代的数据
          *  A PrimaryDM
          *  {'indicateCount','指标'} -- 正负表示超过设置的人数,负数表示低于设置的人数
          *  {'approvedCount, '录取人数'} -- 正常录取人数
          *  {'adjustCount','调剂人数'} -- 未录取人数,理论上应该<=指标的绝对值
-         *  {'matchedCount','可调剂人数'} -- 未录取可被调剂的人(志愿不满足但自选专业满足)
-         *  {'nonmatchedCount','不可调剂人数'} -- 未录取不可被调剂的人(志愿与自选专业均不满足)
-         *  
+         *  {'matchedCount','专业符合'} -- 未录取可被调剂的人(志愿不满足但自选专业满足) // 4.19 为保存自选专业与报告一致,每次进入初选决策之后关闭自选专业功能,校长开启选科(或者选科结束???)时打开
+         *  {'nonmatchedCount','专业不符'} -- 未录取不可被调剂的人(志愿与自选专业均不满足)
+         *
          *  B BackTracking FinalAdjust
-         *  {'matchedApproved','可调剂同意人数'} -- 统计有效补录报名,且报名与推荐相同
-         *  {'matchedNotOptional','可调剂改填人数'} -- 统计有效补录报名,且报名与推荐不同
-         *  {'matchedRejected','可调剂已拒绝人数'} -- 统计拒绝报名的人数
-         *  {'matchedNonaction','可调剂未完成人数'} -- 统计未参的人数(因为有可能被排名挤出)
-         *  {'matchedRankout','可调剂被挤出'} -- 统计参与但已经失效的报名人数(因为有可能被排名挤出)
-         *  {'nonmatchedApproved','不可调剂已填人数'}
-         *  {'nonmatchedNotOptional','不可调剂改填人数'}
-         *  {'nonmatchedRejected','不可调剂已拒绝人数'}
-         *  {'nonmatchedNonaction','不可调剂未完成人数'}
-         *  {'nonmatchedRankout','不可调剂已填人数'}
-         *  
+         *  {'matchedApproved','专业符合同意'} -- 统计有效补录报名,且报名与推荐相同
+         *  {'matchedNotOptional','专业符合改填'} -- 统计有效补录报名,且报名与推荐不同
+         *  {'matchedRejected','专业符合拒绝'} -- 统计拒绝报名的人数
+         *  {'matchedNonaction','专业符合未填'} -- 统计未参的人数(因为有可能被排名挤出)
+         *  {'nonmatchedApproved','专业不符同意'}
+         *  {'nonmatchedNotOptional','专业不符改填'}
+         *  {'nonmatchedRejected','专业不符拒绝'}
+         *  {'nonmatchedNonaction','专业不符未填'}
+         *
          *  C BackTrackingDM FinalAdjustDM RankBalance
-         *  {'approvedCount','补录录取人数'} -- 正常录取 [BackTrackingDM FinalAdjustDM]
-         *  {'forcedCount','调剂录取人数'} -- 强制调剂录取 [BackTrackingDM FinalAdjustDM RankBalance]
-         *  {'matchedCount','可调剂人数'} -- 正常录取 [BackTrackingDM]
-         *  {'nonmatchedCount','不可调剂人数'} -- 正常录取 [BackTrackingDM] 
-         *  
+         *  {'matchedApproved','专业符合填报录取'} -- 正常录取 [BackTrackingDM FinalAdjustDM]
+         *  {'matchedApprovedByConfig','专业符合拒填录取'} -- 正常录取 [BackTrackingDM FinalAdjustDM]
+         *  {'matchedApprovedByNoaction','专业符合未填录取'} -- 正常录取 [BackTrackingDM FinalAdjustDM]
+         *  {'matchedRejectByRankout','专业符合填报未录'} -- 正常录取 [BackTrackingDM FinalAdjustDM] // 4.19需要区分填报后被匹配算法踢出的人
+         *  「专业不符」* 4
+         *  {'forcedCount','调剂录取'} -- 强制调剂录取 [FinalAdjustDM RankBalance]
+         *  {'indicateCount','指标'} -- 正负表示超过设置的人数,负数表示低于设置的人数
+         *  {'matchedCount','专业符合'} -- 正常录取 [BackTrackingDM]
+         *  {'nonmatchedCount','专业不符'} -- 正常录取 [BackTrackingDM]
+         *
         */
         #endregion
 
@@ -325,7 +340,7 @@ namespace mxdemo.Mind
         public interface IElectiveGengerationDetail
         {
             long id { get; set; }
-            EnumElectiveGeneration generation { get; set; } 
+            EnumElectiveGeneration generation { get; set; }
             string category { get; set; } // ElectiveSummaryCategory.category
             int roundId { get; set; }
             int studentId { get; set; }
@@ -334,6 +349,29 @@ namespace mxdemo.Mind
             string className { get; set; }
             int groupId { get; set; }
             string groupName { get; set; }
+            string datetime { get; set; }
+        }
+
+        public class ElectiveGenerationRankDescriptor
+        {
+            string key; // 类似字段名,相同的业务定义相同的名称,在代数据迭代到一个格子里显示时,同字段将被覆盖掉
+            int value; // 实际值
+            string description;  // 描述文字
+        }
+
+        public class ElectiveGenerationFlowHistory // : IElectiveGengerationDetail 可以考虑接收IElectiveGengerationDetail接口约束,也可以不,因为history只会展示关键信息
+        {
+            EnumElectiveGeneration generation; // <=ElectiveGenerationDetail.generation
+            int groupId; // ElectiveGenerationFlowData.groupId
+            string description; // 一志愿 二志愿 三志愿 初选报名 初选录取 未录取(能显示匹配算法具体原因更好) 推荐 补录报名 ...
+            ElectiveGenerationRankDescriptor[] rankDescriptors; // 与匹配算法相关的数据提供,之所以定义成这样,是这些项极有可能还会进一步调整
+            /* rankDescriptors 估计需要边做边整理了:
+             * Primary [{ 'expected', 250, '设置人数'},{'actual', 287, '报名人数'},{'inTimeRankInGrade', 267, '实时排名'}] 所有报名的人都会产生
+             * PrimaryDM [{'indicate', 25, '补录指标'},{'bestGroupSum', '最优分组人数'}, {'rankInIndicate', 19, '成绩最优排名'}] 未录取需要参与补录的人会产生新的统计维度
+             * 注:最优分组人数与成绩最优排名是指:有补录指标的组合,在剩余待补录的人员中的最好成绩所在组合的总人数与自己的排名情况
+             * ... 后面的generation以此类推
+             * */
+
         }
 
         /// <summary>
@@ -341,13 +379,9 @@ namespace mxdemo.Mind
         /// 明细的学生组合信息, 主要包含报名信息;
         /// 还有一部分自选专业的信息,需要借助其它接口
         /// </summary>
-        public class ElectiveGenerationDetail: IElectiveGengerationDetail
+        public class ElectiveGenerationDetail : IElectiveGengerationDetail
         {
-            int rankInTime { get; set; } // 组合即时排名
-            int rankInGroup { get; set; } // 组合全校排名
-            int rankInGrade { get; set; } // 总分全校排名
-            int rankPreference { get; set; } // 志愿RANK 第几志愿
-            string OperateTime { get; set; } // 报名时间
+            ElectiveGenerationFlowHistory[] histories; // 4.19 当前student截止到当前代的全部generation flow data数据,但需要转换为业务格式
 
             public long id { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
             public string category { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
@@ -359,38 +393,16 @@ namespace mxdemo.Mind
             public string className { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
             public int groupId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
             public string groupName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
-        }
-
-        /// <summary>
-        /// 录取明细(包含approved正常录取;forced强制调剂录取),当前组合为录取项
-        /// </summary>
-        public class ElectiveGenerationEnrollDetail: ElectiveGenerationDetail
-        {
-            ElectiveGenerationDetail[] otherEnlist; // 非录取报名清单
-            Dictionary<long, string> failedReasons; // 如果有未录取原因,填充在此MAP{key: detailId, value: failed reason}中
-            bool forced; // 是否属于强制调剂
-            bool esigned; // 是否已经签名
-        }
-
-        /// <summary>
-        /// 未录取明细,当前组合是推荐项
-        /// </summary>
-        public class ElectiveGenerationDisenrollDetail: ElectiveGenerationDetail
-        {
-            ElectiveGenerationDetail[] enlist; // 之前的报名清单(肯定都没有录取)
-            Dictionary<long, string> failedReasons; // 如果有未录取原因,填充在此MAP中
-            bool agreed; // 同意此组合
-            bool disagreed; // 不同意此组合
-            bool disagreeReason; // 不同意的原因
-            ElectiveGenerationDetail other; // 即没有同意,也没有不同意,选了其它组合
-            bool esigned; // 是否已经签名
+            public string datetime { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
         }
 
         /// <summary>
         /// 初选报名搭配使用,展示其它可报组合情况
         /// </summary>
-        public class ElectiveGenerationOptionalMajor : ElectiveOptionalMajor
+        public class ElectiveGenerationOptionalMajor
         {
+            ElectiveOptionalMajor[] marjors; // 自选专业列表
+
             int bestMatchedGroupId; // 最佳匹配
         }
 
@@ -404,9 +416,12 @@ namespace mxdemo.Mind
         /// <summary>
         /// 通过summary中输出的queryCode反查明细
         /// </summary>
+        /// <param name="roundId"></param>
+        /// <param name="generation">当前进程代</param>
+        /// <param name="groupId">针对组合的查询会传,否则传0或者''(具体看返回的时候给的什么值,比如未报名的)</param>
         /// <param name="queryCode"></param>
         /// <returns></returns>
-        List<IElectiveGengerationDetail> getElectiveGengerationDetails(string queryCode);
+        List<IElectiveGengerationDetail> getElectiveGengerationDetails(int roundId, int generation, int groupId, string queryCode);
 
         #endregion
 
@@ -431,7 +446,7 @@ namespace mxdemo.Mind
             /// 以上逻辑循环迭代,每次只补空缺组合,直至伪志愿运算结束。
             /// [志愿1][志愿2,志愿3]迭代的录取学生为正常录取;自选专业伪志愿为可调剂名单;运行结束后的未录学生为不可调剂名单。
             /// </summary>
-            MajorFirst, // 
+            MajorFirst, //
         }
 
         /// <summary>
@@ -455,7 +470,7 @@ namespace mxdemo.Mind
         /// 取消强制调剂操作
         /// </summary>
         /// <param name="id">ElectiveGenerationFlowData.id</param>
-        void cancelEnrollByForce(long id);       
+        void cancelEnrollByForce(long id);
 
         #endregion
 

+ 15 - 37
mock/modules/elective-generation.js

@@ -1,7 +1,7 @@
 const Mock = require('mockjs')
 const Random = Mock['Random']
 
-const mockGeneration = 8 // primary
+const mockGeneration = 4 // primary
 const mockGroups = [1, 2, 3, 4, 5, 6]
 const mockPreferenceCount = 3 // 1 or 3 // 1志愿/3志愿
 
@@ -27,11 +27,15 @@ module.exports = [
             limitPerson: false,
             rankOut: false
           })),
-          allMatched: false,
+          allMatched: Random.boolean(1, 10, 8),
           currentGeneration: mockGeneration,
 
           // +
-          disenrollCount: Random.integer(20, 100)
+          disenrollCount: Random.integer(20, 100), // 未录人数
+          enablePushNextDMGeneration: Random.boolean(1, 10, 8),
+          allowDMAlgorithm: true,
+          doneDMAlgorithm: Random.boolean(1, 10, 8),
+          allowForce: Random.boolean(1, 10, 8)
         }
       }
     }
@@ -119,32 +123,6 @@ module.exports = [
                     queryCode: 'abc',
                     disabled: false
                   }))
-                },
-                {
-                  category: 'esignedCount',
-                  displayName: '已签人数',
-                  values: mockGroups.map(groupId => ({
-                    groupId: groupId,
-                    value: Random.integer(120, 400),
-                    color: '',
-                    bold: false,
-                    star: false,
-                    queryCode: 'abc',
-                    disabled: false
-                  }))
-                },
-                {
-                  category: 'esigningCount',
-                  displayName: '待签人数',
-                  values: mockGroups.map(groupId => ({
-                    groupId: groupId,
-                    value: Random.integer(120, 400),
-                    color: 'R',
-                    bold: false,
-                    star: false,
-                    queryCode: 'abc',
-                    disabled: false
-                  }))
                 }
               ]
             }
@@ -193,7 +171,7 @@ module.exports = [
                   },
                   {
                     category: 'matchedCount',
-                    displayName: '可调剂人数',
+                    displayName: '专业符合',
                     values: mockGroups.map(groupId => ({
                       groupId: groupId,
                       value: Random.integer(120, 400),
@@ -206,7 +184,7 @@ module.exports = [
                   },
                   {
                     category: 'nonmatchedCount',
-                    displayName: '不可调剂人数',
+                    displayName: '专业不符',
                     values: mockGroups.map(groupId => ({
                       groupId: groupId,
                       value: Random.integer(120, 400),
@@ -224,7 +202,7 @@ module.exports = [
                 factory: () => [
                   {
                     category: 'matchedApproved',
-                    displayName: '可调剂同意',
+                    displayName: '专业符合同意',
                     values: mockGroups.map(groupId => ({
                       groupId: groupId,
                       value: Random.integer(120, 400),
@@ -237,7 +215,7 @@ module.exports = [
                   },
                   {
                     category: 'matchedNotOptional',
-                    displayName: '可调剂改选',
+                    displayName: '专业符合改选',
                     values: mockGroups.map(groupId => ({
                       groupId: groupId,
                       value: Random.integer(120, 400),
@@ -250,7 +228,7 @@ module.exports = [
                   },
                   {
                     category: 'matchedRejected',
-                    displayName: '可调剂拒绝',
+                    displayName: '专业符合拒绝',
                     values: mockGroups.map(groupId => ({
                       groupId: groupId,
                       value: Random.integer(120, 400),
@@ -263,7 +241,7 @@ module.exports = [
                   },
                   {
                     category: 'matchedNonaction',
-                    displayName: '可调剂未填',
+                    displayName: '专业符合未填',
                     values: mockGroups.map(groupId => ({
                       groupId: groupId,
                       value: Random.integer(120, 400),
@@ -276,7 +254,7 @@ module.exports = [
                   },
                   {
                     category: 'matchedRankout',
-                    displayName: '可调剂被挤出',
+                    displayName: '专业符合被挤出',
                     values: mockGroups.map(groupId => ({
                       groupId: groupId,
                       value: Random.integer(120, 400),
@@ -289,7 +267,7 @@ module.exports = [
                   },
                   {
                     category: 'nonmatchedApproved',
-                    displayName: '不可调剂已填',
+                    displayName: '专业符合已填',
                     values: mockGroups.map(groupId => ({
                       groupId: groupId,
                       value: Random.integer(120, 400),

+ 18 - 6
src/common/mx-config.js

@@ -90,7 +90,7 @@ export default {
       value: 1,
       decisionMaking: false,
       stepsVisible: true,
-      title: '初选报名',
+      title: '初录数据',
       description: '',
       icon: ''
     },
@@ -99,7 +99,7 @@ export default {
       value: 2,
       decisionMaking: true,
       stepsVisible: true,
-      title: '初选报名决策',
+      title: '通知补录',
       description: '',
       icon: ''
     },
@@ -108,7 +108,7 @@ export default {
       value: 3,
       decisionMaking: false,
       stepsVisible: true,
-      title: '补录报名',
+      title: '补录数据',
       description: '',
       icon: ''
     },
@@ -117,7 +117,7 @@ export default {
       value: 4,
       decisionMaking: true,
       stepsVisible: true,
-      title: '补录报名决策',
+      title: '通知二次补录',
       description: '',
       icon: ''
     },
@@ -126,7 +126,7 @@ export default {
       value: 5,
       decisionMaking: false,
       stepsVisible: true,
-      title: '补录调剂报名',
+      title: '二次补录数据',
       description: '',
       icon: ''
     },
@@ -135,7 +135,7 @@ export default {
       value: 6,
       decisionMaking: true,
       stepsVisible: true,
-      title: '补录调剂报名决策',
+      title: '调剂决策',
       description: '',
       icon: ''
     },
@@ -157,5 +157,17 @@ export default {
       description: '',
       icon: ''
     }
+  },
+  electiveDMAlgorithm: {
+    rankFirst: {
+      key: 'rankFirst',
+      value: 0,
+      title: '按成绩'
+    },
+    majorFirst: {
+      key: 'majorFirst',
+      value: 1,
+      title: '按专业'
+    }
   }
 }

+ 1 - 1
src/views/elective/generation/components/elective-generation-charts.vue

@@ -10,7 +10,7 @@
     </div>
     <template v-if="chartOptions.pies&&chartOptions.pies.length">
       <el-divider></el-divider>
-      <div class="fx-row fx-bet-cen">
+      <div class="fx-row fx-bet-cen pl30">
         <div v-for="(pie,idx) in chartOptions.pies" :key="idx" class="fx-1 fx-row fx-cen-cen">
           <mx-chart ref="pies" :options="pie" :height="'400px'"></mx-chart>
         </div>

+ 65 - 0
src/views/elective/generation/components/elective-generation-commands.vue

@@ -0,0 +1,65 @@
+<template>
+  <div class="fx-row fx-bet-cen">
+    <div class="fx-1">
+      <el-button v-if="showDMAlgorithm" type="primary">智能匹配</el-button>
+      <el-button v-if="showDMAlgorithmResults" type="primary">查看匹配明细</el-button>
+      <el-button v-if="showForceAdjust" type="primary">调剂/提醒</el-button>
+    </div>
+    <div>
+      <el-button v-if="showFastPush" type="primary">提前进入{{ nextStepName }}</el-button>
+      <el-button v-if="showSend" type="primary">发送</el-button>
+      <el-button v-if="showRankBalance" type="primary">排名均衡</el-button>
+      <el-button v-if="showClassDispatch" type="primary">选科分班</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'elective-generation-commands',
+  inject: ['refreshData'],
+  props: ['chartBinding', 'disabled'],
+  computed: {
+    generation() {
+      return this.chartBinding.generation || {}
+    },
+    status() {
+      return this.generation?.status || {}
+    },
+    // buttons control
+    showDMAlgorithm() {
+      return this.status.allowDMAlgorithm
+    },
+    showDMAlgorithmResults() {
+      return this.status.doneDMAlgorithm && !this.status.allowForce
+    },
+    showForceAdjust() {
+      return this.status.doneDMAlgorithm && this.status.allowForce
+    },
+    showFastPush() {
+      return this.status.enablePushNextDMGeneration
+    },
+    nextStepName() {
+      const options = this.generation.options
+      const next = this.generation.current + 1
+      return Object.values(options).find(opt => opt.value == next).title
+    },
+    showSend() {
+      return this.status.doneDMAlgorithm && !this.status.allMatched
+    },
+    showRankBalance() {
+      const options = this.generation.options
+      return this.status.allMatched && this.generation.current < options.rankBalance.value
+    },
+    showClassDispatch() {
+      const options = this.generation.options
+      return this.status.allMatched && this.generation.current <= options.rankBalance.value
+    }
+  },
+  methods: {}
+}
+</script>
+
+<style scoped>
+
+</style>

+ 10 - 4
src/views/elective/generation/components/elective-generation-master.vue

@@ -7,7 +7,9 @@
           <slot name="header-prefix"></slot>
         </div>
         <div class="fx-1">
-          <slot :name="activeKey+'-header'" v-bind="chartBinding"></slot>
+          <slot :name="activeKey+'-header'" v-bind="chartBinding">
+            <elective-generation-commands v-if="!stepDisabled" :chart-binding="chartBinding"/>
+          </slot>
         </div>
         <div>
           <slot name="header-suffix"></slot>
@@ -18,7 +20,7 @@
       </slot>
       <slot name="footer-prefix"></slot>
       <slot :name="activeKey+'-footer'" v-bind="chartBinding">
-        <elective-generation-bar-chart :chart-binding="chartBinding" class="mt40"></elective-generation-bar-chart>
+        <elective-generation-charts :chart-binding="chartBinding" class="mt40"></elective-generation-charts>
       </slot>
       <slot name="footer-suffix"></slot>
     </template>
@@ -28,11 +30,12 @@
 <script>
 
 import ElectiveGenerationTable from '@/views/elective/generation/components/elective-generation-table'
-import ElectiveGenerationBarChart from '@/views/elective/generation/components/elective-generation-charts'
+import ElectiveGenerationCharts from '@/views/elective/generation/components/elective-generation-charts'
+import ElectiveGenerationCommands from '@/views/elective/generation/components/elective-generation-commands'
 
 export default {
   name: 'elective-generation-master',
-  components: { ElectiveGenerationBarChart, ElectiveGenerationTable },
+  components: { ElectiveGenerationCommands, ElectiveGenerationCharts, ElectiveGenerationTable },
   props: {
     generation: {
       type: Object
@@ -47,6 +50,9 @@ export default {
     activeKey() {
       return this.generation.activeOpt?.key || ''
     },
+    stepDisabled() {
+      return this.generation.active !== this.generation.current
+    },
     isUnPassedStep() {
       if (!this.generation.activeOpt) return false
       this.emptyTitle = this.generation.currentOpt == this.generation.options.init

+ 1 - 1
src/views/elective/generation/components/elective-generation-table.vue

@@ -1,7 +1,7 @@
 <template>
   <mx-table ref="table" :prop-defines="resolvedTable.columns" :rows="resolvedTable.rows" border>
     <template #elective-cell="{value, label}">
-      <el-popover trigger="hover" placement="right" :disabled="value&&value.disabled"
+      <el-popover trigger="hover" :disabled="value&&value.disabled"
                   popper-class="zero-padding-popover">
         <div class="fx-column">
           <el-button plain type="text" @click="goDetails(value, label)">查看名单</el-button>

+ 6 - 1
src/views/elective/generation/index.vue

@@ -10,7 +10,7 @@
       </template>
       <elective-generation-master :generation="generation">
         <template #header-prefix>
-          <el-button circle icon="el-icon-refresh" @click="handleQuery"></el-button>
+          <el-button circle icon="el-icon-refresh" @click="handleQuery" class="mr30"></el-button>
         </template>
       </elective-generation-master>
     </el-card>
@@ -88,6 +88,11 @@ export default {
       }
     }
   },
+  provide() {
+    return {
+      refreshData: this.handleQuery
+    }
+  },
   methods: {
     handleInvalid() {
       this.activeStep = ''