ElectiveGeneration.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. using System;
  2. using System.Collections.Generic;
  3. using static mxdemo.Mind.IStudentClassDispatchService;
  4. namespace mxdemo.Mind
  5. {
  6. // 选科数据与决策会有很多重合的地方
  7. public enum EnumElectiveGeneration
  8. {
  9. Init = 0, // 初始化态,选科正式开启前的状态,开启之后往下一代推进
  10. Primary = 1, // 初选(正常报名)阶段,初选时间结束时往下一代推进 (先暂定进入PrimaryDM之前选科设置还可以修改,之后禁止,防止扰乱数据)
  11. PrimaryDM, // (PrimaryDecisionMaking)初选录取阶段,应用决策之后,开启补录报名(时间段)并往下一代推进
  12. BackTracking, // 补录报名时间结束后往下一代推进
  13. BackTrackingDM, // 调剂OR提醒,如果为直接调剂,则跳过FinalAdjust,如果为提醒(设时间段)并往下一代推进
  14. FinalAdjust, // 调剂报名期间
  15. FinalAdjustDM, // 调剂决策,这个阶段会最终定版
  16. RankBalance, // 可选步骤,行为类似强制调剂
  17. // Dispatch, // 分班?分班是否要进入此结构?貌似结构不太统一!应该还是要分出去做
  18. Terminate // 最终代,选科流程数据全部封存
  19. }
  20. public enum EnumElectiveOperation
  21. {
  22. None = 0,
  23. Canceled,
  24. Disabled,
  25. Optional,
  26. Rejected,
  27. Approved,
  28. Forced
  29. }
  30. // 待思考问题:
  31. /*
  32. 1 哪个结点开始不允许修改选科设置
  33. 2 未操作志愿、未选完志愿、未响应决策的学生是否需要区分显示
  34. 3 补录决策时,是否存在部分调剂、部分提醒的情况?
  35. 4 调剂行为定义:直接修改学生最终录取组合,触发发签名
  36. */
  37. #region models
  38. /// <summary>
  39. /// Generation init时生成的缓存数据,方便后续计算
  40. /// 生成开放组合的数据即可
  41. /// 每次修改选科设置(在允许范围内修改)需要刷新
  42. /// </summary>
  43. public class ElectiveStudentScore
  44. {
  45. long id;
  46. long roundId;
  47. long studentId;
  48. long groupId;
  49. decimal scoreTotal; // 9科成绩,看是否有必要存
  50. decimal scoreGroup; // 6科成绩
  51. int rankTotal; // 9科全校排名,看是否有必要存
  52. int rankGroup; // 6科全校排名
  53. }
  54. /// <summary>
  55. /// 每一代都为体现学生的选科数据变化,任何操作都可以被记录下来,只是最终哪条生效的问题
  56. /// 当然也可以根据实际情况减少部分记录,类下面的注解将讨论这些问题
  57. /// </summary>
  58. public class ElectiveGenerationFlowData
  59. {
  60. long id;
  61. long roundId;
  62. long studentId;
  63. long groupId;
  64. EnumElectiveGeneration generation;
  65. EnumElectiveOperation operation;
  66. long operateBy;
  67. DateTime operateTime;
  68. int rank; // Primary中可能存在多志愿,用来控制此阶段的志愿优先级,如第1志愿=0,第2志愿=1,第三志愿=2
  69. string remark;
  70. // 以下2个字段用来挂载生命周期关键引用对象,具体每个环节挂什么,需要再斟酌。
  71. string refType;
  72. long refId;
  73. }
  74. public class ElectiveGenerationFlowLog : ElectiveGenerationFlowData
  75. {
  76. // + 区分ElectiveGenerationFlowData的字段
  77. }
  78. public class RoundForFlow : mxdemo.Mind.IStudentClassDispatchService.Round // Round到时候合并在一起
  79. {
  80. bool allEnrolled; // 所有学生录取完毕,可以开始推进排名均衡或者分班
  81. EnumElectiveGeneration currentGeneration; // 内部字段
  82. // + new fields
  83. // int disenrollCount; // 未录取学生数量 - 用于图表展示,或者内部判定allEnrolled // 5.22 将此字段改到summary才能体现不同代的未录人数
  84. bool enablePushNextDMGeneration; // 是否可以强制推进下一代决策进程 = 当前为报名进程,且学生均已报名
  85. bool allowDMAlgorithm; // 当前为决策进程,支持运行匹配算法(BackTrackingDM,FinalAdjustDM)
  86. bool doneDMAlgorithm; // 当前为决策进程,且已经运行了匹配算法
  87. // 5.13 现在只有forceAdjust阶段开放
  88. bool allowForce; // 当前阶段是否开放了强制调剂功能
  89. bool enablePushForceAdjust; // 当前是否展示强制阶段入口:2次补录结果匹配算法之后一定展示此入口;如果提前录取完毕,加个匹配项控制是否展示此入口(最好配置到round,作为后门),默认不展示
  90. }
  91. // 1 初选决策时,需要进行设置
  92. // 2 补录决策时,需要进行设置,此时要根据具体数据来定
  93. // 如果所有学生都已经匹配完毕(Approved,Forced都属性已匹配),则可以推进排名均衡或者分班
  94. // 如果还有未匹配的,则推进到FinalAdjust
  95. public class FlowPushSetting
  96. {
  97. long id;
  98. long roundId;
  99. DateTime begin;
  100. DateTime end;
  101. bool onlyRecommand; // 仅允许学生选择推荐组合, 否则允许学生填报有空缺的组合
  102. bool onlyAgree; // 调剂阶段,只允许学生选择同意, 否则允许学生拒绝
  103. bool useRecommandWhileDisagree; // 如果拒绝,按推荐报名处理
  104. bool useRecommandWhileNonaction; // 如果不报名,按推荐报名处理
  105. }
  106. public class ElectiveEsign
  107. {
  108. long id;
  109. long roundId;
  110. long flowDataId; // 对应哪条匹配数据(录取或者调剂)【匹配算法结果表也可如此挂载flowDataId,这样可以追溯匹配原因】
  111. string esignPath; // 签字保存图片
  112. bool actived; // 有效标记,可以考虑:如果学生需要签名且未签名时,如果再遇到新的调剂时,旧的签名还要继续么?我觉得应该是不需要的
  113. // 可能还有其它字段
  114. }
  115. /*
  116. 总则:ElectiveGenerationFlowData记录的是每一代数据的最终结果,如果想要更精细的记录,可以结合ElectiveGenerationFlowLog
  117. 1 Generation.Init 可有可无,不需要生成初始数据?
  118. 2 Generation.Primary
  119. 报名时:
  120. ADD operation=Approved
  121. 取消时:
  122. UPDATE operation=Cancel
  123. 排名挤出时-被挤出人:
  124. UPDATE operation=Disabled, remark = '排名挤出'
  125. refType = 'ElectiveGenerationFlowData'
  126. refId = ElectiveGenerationFlowData.id // 报名解发挤出那条记录的ElectiveGenerationFlowData.id
  127. 取消时恢复补挤出的人(只有当被影响的人还有剩余报名次数的时候才自动恢复,因为期间他可能自己又补填了一个志愿):
  128. QueryBy refId
  129. UPDATE operation=Approved WHEN COUNT(operation=Approved)<setting.PreferenceCount
  130. remark = ''
  131. refType = ''
  132. refId = 0 // 取消对应记录的ID
  133. Primary中学生的有效报名数据:operation=Approved
  134. 3 Generation.PrimaryDM
  135. 目标:启用算法,给每个学生生成一条决策数据,表示初选录取情况(算法见ElectiveEngine草稿)
  136. 录取:
  137. ADD operation=Approved
  138. remark = 录取说明?
  139. refType = 'ElectiveEsign'
  140. refId = ElectiveEsign.id // 生成一条待签记录
  141. // 这样的话签名与选科的代数据就可分割开了,具体说是否一定要学生签名才能推进下一代?
  142. // 我看未必,因为学校不可能因为个别钉子户就暂停教务
  143. 未录取,但自选专业满足
  144. ADD operation=Optional, groupId=推荐组合
  145. remark = 未录取原因
  146. 未录取,也无自选专业满足
  147. ADD operation=Rejected, groupId=推荐组合
  148. remark = 未录取原因
  149. PrimaryDM中 operation=[Optional,Rejected]的学生,即是一代补录流程的目标学生
  150. 4 Generation.BackTracking
  151. 操作逻辑重用Generation.Primary
  152. 5 Generation.BackTrackingDM
  153. 操作逻辑重用Generation.PrimaryDM,
  154. 计算差别:仅1个志愿,但还是可以引用自选专业,因为学生在此期间可能更改了自选专业
  155. 操作差别:校长在推动下一代流程时,有可能会开始手动调剂
  156. UPDATE operation=Forced // Forced操作等同于Approved录取状态,即告诉学生被调剂了,签字同意即可(即也挂ref钩子)
  157. 6 Generation.FinalAdjust
  158. 可选步骤,有可能跳过,如未跳过,则是调剂报名
  159. 同意:前端会强制签名,所以这条在保存时可以直接挂钩ElectiveEsign
  160. ADD operation=Approved, refType='ElectiveEsign', refId=ElectiveEsign.id
  161. 拒绝:
  162. ADD operation=Rejected, remark=不同意原因
  163. 附:没有记录则是未参与的
  164. 7 Generation.FinalAdjustDM
  165. 针对未参与的或operation=Rejected, 校长会在此环节强制调剂,以达到最终定版的目的
  166. ADD operation=Forced, refType='ElectiveEsign', refId=0 // 待签名
  167. 8 Generation.RankBalance
  168. 可选步骤,也是产生类似Generation.FinalAdjustDM数据逻辑,只是学校出发的角度不一样
  169. ADD operation=Forced, refType='ElectiveEsign', refId=0 // 待签名
  170. 9 Generation.Dispatch 待定应该要分出去单独做
  171. 10 Generation.Terminate
  172. 不产生数据,但需要记录此状态,表示选科数据封存(记录在round实例中)
  173. */
  174. #endregion
  175. public interface IElectiveService
  176. {
  177. /// <summary>
  178. /// 校长-选科状态
  179. /// </summary>
  180. RoundForFlow getElectiveStatus({year, roundId});
  181. #region getElectiveSummary
  182. /// <summary>
  183. /// 选科过程中的统计数据值,除了要展示之外还需要做查询支持
  184. /// </summary>
  185. public class ElectiveSummaryValue
  186. {
  187. // 展示字段
  188. int groupId; // 组合ID,没有组合为0比如未参与报名人数(实际只有两种统计数据,针对某个组合的统计和不针对组合的统计)
  189. int value; // 数值
  190. string color; // 常用值:'R,G,B,P,Y'(不分大小写,也可以hexString),R:红,G:绿,B:蓝,P:主题绿,Y:橙
  191. bool bold; // 加粗,重点展示
  192. bool star; // 带*,重点展示
  193. // 反向查询代码 将统计逻辑的条件关键字放入此代码,回传后台能反向解析并恢复明细
  194. // 想法:让统计全部基于ElectiveGenerationFlowData,形成一种或多种QueryDto{roundId:'',generation:'',groupId:''...}等, 序列化实际查询条件
  195. // string queryCode; // 4.18 此字段往上提升了1级放在了ElectiveSummaryCategory上,详情请看注释
  196. bool disabled; // 不支持查询
  197. }
  198. /// <summary>
  199. /// 查询的某一列
  200. /// </summary>
  201. public class ElectiveSummaryCategory
  202. {
  203. string category; // 身份标识,类似字段名/列名,可能被前端用来定制渲染模板
  204. string displayName; // 显示名称
  205. string detailName; // 4.19 详情页对应的groupId的业务意义:如报名组合、录取组合、推荐组合、初录报名组合、...
  206. string queryCode; // 4.18 如果直接查询,就定义此queryCode,前端会收拢此代所有的queryCode,在2级页面形成查询条件选项卡;
  207. // 4.18 后台需要一个配置,比如PrimaryDM代之后,整列没有数据直接隐藏,
  208. // 4.18 不向前端输出,以减少2级页面的条件项,因为随着选科进行,残留的学生越来越少,减少条件项可以帮助校长更快定位学生
  209. // 4.18 从原来ElectiveSummaryValue内部的queryCode升级而来,反查明细时由方法其它参数提供groupId, roundId, generation
  210. ElectiveSummaryValue[] values;
  211. }
  212. public interface IElectiveGenerationSummary
  213. {
  214. int roundId { get; set; } // 选科轮次
  215. EnumElectiveGeneration generation { get; set; } // 进程代
  216. }
  217. /// <summary>
  218. /// 进程代的统计结果从primary开始出数据
  219. /// </summary>
  220. public class ElectivePrimarySummary : IElectiveGenerationSummary
  221. {
  222. ElectiveSummaryCategory[][] categories; // 是多维数组,以应对多志愿的情况
  223. public int roundId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  224. public EnumElectiveGeneration generation { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  225. }
  226. /// <summary>
  227. /// 非Primary非DM的某一代的统计结果
  228. /// </summary>
  229. public class ElectiveGenerationSummary: IElectiveGenerationSummary
  230. {
  231. /// <summary>
  232. /// 对某一代的统计项目,比如在初选决策、补录报名的统计等,下面接口会细述
  233. /// </summary>
  234. ElectiveSummaryCategory[] categories;
  235. int IElectiveGenerationSummary.roundId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  236. EnumElectiveGeneration IElectiveGenerationSummary.generation { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  237. }
  238. public class ElectiveGenerationDMSummary: ElectiveGenerationSummary
  239. {
  240. /// <summary>
  241. /// 迭加到某决策代的统计项目,比如当前选科的总录取人数、待签人数、已签人数等,下面接口会细述
  242. /// </summary>
  243. ElectiveSummaryCategory[] accumulates;
  244. int disenrollCount; // 5.22 hht 将未录人数放在此处
  245. }
  246. /// <summary>
  247. /// 获取选科进程的统计数据,一直汇总到当前进程代
  248. /// </summary>
  249. /// <returns></returns>
  250. IElectiveGenerationSummary[] getElectiveSummary();
  251. // 下面开始按代来描述ElectiveGenerationSummary需要返回的具体内容
  252. /* 一、ElectivePrimarySummary,所需ElectiveSummaryCategory->{category:'',displayName:''}定义如下:
  253. * // hht.22/4/10 这个属性不要了 {'expectedCount','设置人数'}, -- 选科设置的人数, 为方便输出与图表展示,可能后续会有重复输出
  254. * {'actualCount','实际人数'}, -- 填报第X志愿的人数
  255. * {'unfinishedCount','未完成人数'}, -- 未填报第X志愿的人数(根据ElectiveGenerationFlowData实际Approved&Rank情况统计即可,因为如果报名还在进行中,本身就是动态变化的东西)
  256. * 按第一志愿、第二志愿、...的顺序输出数据
  257. *
  258. * 二、ElectiveGenerationDMSummary.accumulates
  259. * 仅决策代需要统计此数据,决策代[PrimaryDM BackTrackingDM FinalAdjustDM RankBalance]
  260. * // hht.22/4/12 同上,这个属性也不要了 {'expectedCount', '设置人数'} -- 选科设置人数
  261. * {'approvedCount', '录取人数'} -- 到此阶段为止,正常录取人数
  262. * {'forcedCount', '调剂录取人数'} -- 到此阶段为止,调剂录取人数
  263. * {'esignedCount', '已签人数'} -- 到此阶段为止,触发的有效签名统计 这个先
  264. * {'esigningCount', '待签人数'} -- 到此阶段为止,阶段触发有效的应签未签统计 [4.18 因为签字提前和强制调剂更改,所以只有FinalAdjustDM RankBalance这两代会产生待签数据了]
  265. 注意:上述一与二的数据不能随意变动,会影响后续图表展示
  266. * 三、ElectiveGenerationSummary.categories 只统计某代的数据
  267. * A PrimaryDM
  268. * {'indicateCount','指标'} -- 正负表示超过设置的人数,负数表示低于设置的人数
  269. * {'approvedCount, '录取人数'} -- 正常录取人数
  270. * {'adjustCount','调剂人数'} -- 未录取人数,理论上应该<=指标的绝对值
  271. * {'matchedCount','专业符合'} -- 未录取可被调剂的人(志愿不满足但自选专业满足) // 4.19 为保存自选专业与报告一致,每次进入初选决策之后关闭自选专业功能,校长开启选科(或者选科结束???)时打开
  272. * {'nonmatchedCount','专业不符'} -- 未录取不可被调剂的人(志愿与自选专业均不满足)
  273. *
  274. * B BackTracking FinalAdjust
  275. * {'matchedApproved','专业符合同意'} -- 统计有效补录报名,且报名与推荐相同
  276. * {'matchedNotOptional','专业符合改填'} -- 统计有效补录报名,且报名与推荐不同
  277. * {'matchedRejected','专业符合拒绝'} -- 统计拒绝报名的人数
  278. * {'matchedNonaction','专业符合未填'} -- 统计未参的人数(因为有可能被排名挤出)
  279. * {'nonmatchedApproved','专业不符同意'}
  280. * {'nonmatchedNotOptional','专业不符改填'}
  281. * {'nonmatchedRejected','专业不符拒绝'}
  282. * {'nonmatchedNonaction','专业不符未填'}
  283. *
  284. * C BackTrackingDM FinalAdjustDM RankBalance
  285. * {'matchedApproved','专业符合填报录取'} -- 正常录取 [BackTrackingDM FinalAdjustDM]
  286. * {'matchedApprovedByConfig','专业符合拒填录取'} -- 正常录取 [BackTrackingDM FinalAdjustDM]
  287. * {'matchedApprovedByNoaction','专业符合未填录取'} -- 正常录取 [BackTrackingDM FinalAdjustDM]
  288. * {'matchedRejectByRankout','专业符合填报未录'} -- 正常录取 [BackTrackingDM FinalAdjustDM] // 4.19需要区分填报后被匹配算法踢出的人
  289. * 「专业不符」* 4
  290. * {'forcedCount','调剂录取'} -- 强制调剂录取 [FinalAdjustDM RankBalance]
  291. * {'indicateCount','指标'} -- 正负表示超过设置的人数,负数表示低于设置的人数
  292. * {'matchedCount','专业符合'} -- 正常录取 [BackTrackingDM]
  293. * {'nonmatchedCount','专业不符'} -- 正常录取 [BackTrackingDM]
  294. *
  295. */
  296. #endregion
  297. #region getElectiveSummaryDetail 汇总明细清单
  298. /// <summary>
  299. /// 明细肯定是通过 某个组合某个学生 来呈现的
  300. /// </summary>
  301. public interface IElectiveGenerationDetail
  302. {
  303. long id { get; set; }
  304. EnumElectiveGeneration generation { get; set; }
  305. string category { get; set; } // ElectiveSummaryCategory.category
  306. int roundId { get; set; }
  307. int studentId { get; set; }
  308. string studentName { get; set; }
  309. int classId { get; set; }
  310. string className { get; set; }
  311. int groupId { get; set; }
  312. string groupName { get; set; }
  313. string datetime { get; set; }
  314. string userName { get; set; }
  315. }
  316. public class ElectiveGenerationRankDescriptor
  317. {
  318. string key; // 类似字段名,相同的业务定义相同的名称,在代数据迭代到一个格子里显示时,同字段将被覆盖掉
  319. int value; // 实际值
  320. string description; // 描述文字
  321. }
  322. public class ElectiveGenerationFlowHistory // : IElectiveGenerationDetail 可以考虑接收IElectiveGenerationDetail接口约束,也可以不,因为history只会展示关键信息
  323. {
  324. EnumElectiveGeneration generation; // <=ElectiveGenerationDetail.generation
  325. int groupId; // ElectiveGenerationFlowData.groupId
  326. string description; // 一志愿 二志愿 三志愿 初选报名 初选录取 未录取(能显示匹配算法具体原因更好) 推荐 补录报名 ...
  327. ElectiveGenerationRankDescriptor[] rankDescriptors; // 与匹配算法相关的数据提供,之所以定义成这样,是这些项极有可能还会进一步调整
  328. /* rankDescriptors 估计需要边做边整理了:
  329. * Primary [{ 'expected', 250, '设置人数'},{'inTimeRankInGrade', 267, '实时排名'}] 所有报名的人都会产生
  330. * PrimaryDM [{'indicate', 25, '补录指标'},{'bestGroupSum', '最优分组人数'}, {'rankInIndicate', 19, '成绩最优排名'}] 未录取需要参与补录的人会产生新的统计维度
  331. * 注:最优分组人数与成绩最优排名是指:有补录指标的组合,在剩余待补录的人员中的最好成绩所在组合的总人数与自己的排名情况
  332. * ... 后面的generation以此类推
  333. * */
  334. }
  335. /// <summary>
  336. /// 此类相当于ElectiveGenerationFlowData的DTO,将字段转义为UI需要的内容
  337. /// 明细的学生组合信息, 主要包含报名信息;
  338. /// 还有一部分自选专业的信息,需要借助其它接口
  339. /// </summary>
  340. public class ElectiveGenerationDetail : IElectiveGenerationDetail
  341. {
  342. ElectiveGenerationFlowHistory[] histories; // 4.19 当前student截止到当前代的全部generation flow data数据,但需要转换为业务格式
  343. // 5.5 hht 允许此条数据触发强制调剂。具体进行到哪代可以调剂、哪些数据可以调剂???
  344. // 5.5 hht 暂定:所有学生录取完毕的决策代或者二次补录决策代允许调剂,可调剂对象为已录取(包含正常录与调剂录)和二级补录决策中未录取的。
  345. public bool enableForce;
  346. // 5.5 hht 如果允许强制调剂,禁止调剂到哪个组合?一般禁止调剂到被录取组合,因为原地不动不叫调剂。没有禁止的给0或者null
  347. public int disableForceGroupId;
  348. // 5.12 hht 增加颜色控制,常用值:'R,G,B,P,Y'(不分大小写,也可以hexString),R:红,G:绿,B:蓝,P:主题绿,Y:橙
  349. // 颜色逻辑:currentGeneration>1
  350. // ?录取
  351. // ?当前查询组合录取?'G':'Y'
  352. // :'R'
  353. // :''
  354. public string color;
  355. // 5.27 hht +迭代至参数中acitve阶段的录取状态(非最终态,用来展示某阶段未录取学生AI分析表)
  356. public bool approved;
  357. public bool forceAdjusted;
  358. // 6.11 hht +录取组合&报名组合(迭代至参数中acitve阶段的录取状态, getClassGenerationDetails专用)
  359. public int enrollGeneration; // 真实录取时的generation
  360. public string enrollGroupName; // 录取组合
  361. public string rankInEnrolledGroup; // 录取排名:已录取情况下,组合所有录取同学中的排名, 录取排名/组合全校全部录取人数
  362. public string[] applyGroupNames; // active只会传入决策代,取active前一代的报名组合
  363. public string rankInAppliedGroup; // 报名排名:报名时的排名(多志愿取一志愿) 报名排名/applyGroupNames中1志愿报名全校总人数
  364. public long id { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  365. public string category { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  366. public EnumElectiveGeneration generation { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  367. public int roundId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  368. public int studentId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  369. public string studentName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  370. public int classId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  371. public string className { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  372. public int groupId { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  373. public string groupName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  374. public string datetime { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
  375. }
  376. public class ElectiveGroupGenerationStatistic
  377. {
  378. public int groupId;
  379. ElectiveGenerationRankDescriptor[] descriptors;
  380. }
  381. public class ElectiveGenerationDetailWrapper
  382. {
  383. ElectiveGroupGenerationStatistic[] groupDescriptors; // 迭代至当前代的组合统计信息,主要统计指标(缺少人数)与实报(实际报名人数)
  384. ElectiveGenerationDetail[] details; // 学生明细
  385. }
  386. /// <summary>
  387. /// 初选报名搭配使用,展示其它可报组合情况
  388. /// </summary>
  389. public class ElectiveGenerationOptionalMajor
  390. {
  391. ElectiveOptionalMajor[] marjors; // 自选专业列表
  392. int bestMatchedGroupId; // 最佳匹配
  393. }
  394. /// <summary>
  395. /// Map: {key: studentid, value: ElectiveGenerationOptionalMajor}
  396. /// </summary>
  397. /// <param name="studentIds"></param>
  398. /// <returns>批量取学生自选专业匹配情况</returns>
  399. Dictionary<int, ElectiveGenerationOptionalMajor> getGenerationOptionalMajorsBatch(int roundId, int[] studentIds);
  400. /// <summary>
  401. /// 通过summary中输出的queryCode反查明细
  402. /// </summary>
  403. /// <param name="roundId"></param>
  404. /// <param name="generation">当前进程代</param>
  405. /// <param name="groupId">针对组合的查询会传,否则传0或者''(具体看返回的时候给的什么值,比如未报名的)</param> 按行
  406. /// <param name="queryCode"></param> 按列
  407. /// <param name="active">前端激活的步骤</param>
  408. /// <returns></returns>
  409. ElectiveGenerationDetailWrapper getElectiveGenerationDetails(int pageNum, int pageSize, int roundId, int generation, int groupId, string queryCode, int active);
  410. #endregion
  411. #region decision-making
  412. /// <summary>
  413. /// 匹配算法,算法名称代表的具体逻辑请看注解(不要顾名思义)
  414. /// </summary>
  415. public enum EnumElectiveDMAlgorithm
  416. {
  417. /// <summary>
  418. /// 按成绩:
  419. /// ElectiveEngine中,相当于[未录学生]/[组合*ALL]/[志愿*ALL]一并运行,排序时排名优先;
  420. /// 以上逻辑循环迭代,每次只补空缺组合,直至未录学生=0。
  421. /// 第1次迭代之后运算的学生均属于可调剂名单,不会有不可调剂名单
  422. /// </summary>
  423. RankFirst,
  424. /// <summary>
  425. /// 按专业:
  426. /// ElectiveEngine中,相当于[未录学生]/[组合*ALL]/[志愿1][志愿2,志愿3][自选专业伪志愿]/三波运行,排序时排名优先;
  427. /// 以上逻辑循环迭代,每次只补空缺组合,直至伪志愿运算结束。
  428. /// [志愿1][志愿2,志愿3]迭代的录取学生为正常录取;自选专业伪志愿为可调剂名单;运行结束后的未录学生为不可调剂名单。
  429. /// </summary>
  430. MajorFirst, //
  431. }
  432. /// <summary>
  433. /// 执行选科匹配算法。为减少错误,对DM代数据全删全加可能好点。
  434. /// </summary>
  435. /// <param name="algorithm"></param>
  436. void applyElectiveDMAlgorithm(EnumElectiveDMAlgorithm algorithm);
  437. #endregion
  438. #region forced
  439. /// <summary>
  440. /// 决策阶段,强制调剂录取
  441. /// </summary>
  442. /// <param name="studentId"></param>
  443. /// <param name="groupId"></param>
  444. void enrollByForce(long studentId, int groupId);
  445. /// <summary>
  446. /// 取消强制调剂操作
  447. /// </summary>
  448. /// <param name="id">ElectiveGenerationFlowData.id</param>
  449. void cancelEnrollByForce(long id);
  450. #endregion
  451. #region generation推进
  452. /// <summary>
  453. /// 决策完毕时,推进下一代进行
  454. /// </summary>
  455. /// <param name="setting">推进配置</param>
  456. void pushGenerationSetting(FlowPushSetting setting);
  457. /// <summary>
  458. /// 5.13 hht 二次补录结果(或者提前录取完毕时)跳转到强制调剂
  459. /// </summary>
  460. void jumpGenerationForceAdjust();
  461. /// <summary>
  462. /// 如果在所有学生全部录取的情况,可以在任意决策结点跳转至排名均衡
  463. /// </summary>
  464. void jumpGenerationRankBalance();
  465. /// <summary>
  466. /// 如果在所有学生全部录取的情况,可以在任意决策结点跳转至终止态,封存数据
  467. /// </summary>
  468. void terminateGeneration();
  469. /// <summary>
  470. /// 在任意报名阶段,如果校长发现数据已经完全OK,则可以强制推进进程,提前进入决策
  471. /// </summary>
  472. void flushIntoGenerationDM();
  473. #endregion
  474. #region 排名均衡(略)先完成前面的
  475. #endregion
  476. #region
  477. /// <summary>
  478. /// 重用getElectiveGenerationDetails, query=active=current
  479. /// <param name="keywords">姓名/学号/账号</param>
  480. /// </summary>
  481. ElectiveGenerationDetail[] searchElectiveGenerationDetails(int pageNum, int pageSize, int roundId, string keywords);
  482. public class ClassGenerationDetailWrapper {
  483. ElectiveGenerationDetail[] details;
  484. int studentCount; // 本班总人数
  485. int enrolledCount; // 迭代至activeGeneration的本班录取人数
  486. }
  487. /// <summary>
  488. /// 重用getElectiveGenerationDetails, query=active=generation
  489. /// 班主任查询接口,查询当前班级的选科数据
  490. /// +isNew true表示查询当前老师待生效的新班级学生,false表示查当前班主任所在班级的学生
  491. /// 先通过oldClassId或者newClassId锁定查询范围,再查迭代至某个generation的录取与未录取状态
  492. /// 6.13 isNew参数暂不用
  493. /// </summary>
  494. ClassGenerationDetailWrapper getClassGenerationDetails(int roundId, int generation, string queryCode, bool isNew);
  495. #endregion
  496. }
  497. }