Commit 7f799a68a88e95206eeded82336b1be0ebbacef1
1 parent
a2d14a12
Update
Showing
10 changed files
with
267 additions
and
9 deletions
src/main/java/com/bsth/service/schedule/impl/SchedulePlanServiceImpl.java
| ... | ... | @@ -21,6 +21,9 @@ import com.bsth.service.schedule.rules.shiftloop.ScheduleRule_input; |
| 21 | 21 | import com.bsth.service.schedule.rules.ttinfo.*; |
| 22 | 22 | import com.bsth.service.schedule.rules.ttinfo2.CalcuParam; |
| 23 | 23 | import com.bsth.service.schedule.rules.ttinfo2.Result; |
| 24 | +import com.bsth.service.schedule.rules.validate.ValidateParam; | |
| 25 | +import com.bsth.service.schedule.rules.validate.ValidateResults_output; | |
| 26 | +import org.apache.commons.lang3.StringUtils; | |
| 24 | 27 | import org.joda.time.DateTime; |
| 25 | 28 | import org.kie.api.KieBase; |
| 26 | 29 | import org.kie.api.runtime.KieSession; |
| ... | ... | @@ -321,6 +324,59 @@ public class SchedulePlanServiceImpl extends BServiceImpl<SchedulePlan, Long> im |
| 321 | 324 | |
| 322 | 325 | } |
| 323 | 326 | |
| 327 | + /** | |
| 328 | + * 验证排班结果。 | |
| 329 | + * @param planResult | |
| 330 | + * @param schedulePlan | |
| 331 | + */ | |
| 332 | + public void validPlanResult(PlanResult planResult, SchedulePlan schedulePlan) { | |
| 333 | + // 1-1、构造drools规则输入数据,输出数据 | |
| 334 | + ValidateParam validateParam = new ValidateParam( | |
| 335 | + new DateTime(schedulePlan.getScheduleFromTime()), | |
| 336 | + new DateTime(schedulePlan.getScheduleToTime()) | |
| 337 | + ); | |
| 338 | + // 规则输出数据 | |
| 339 | + ValidateResults_output result = new ValidateResults_output(); | |
| 340 | + | |
| 341 | + // 1-2、构造drools session->载入数据->启动规则->计算->销毁session | |
| 342 | + // 创建session,内部配置的是stateful | |
| 343 | + KieSession session = kieBase.newKieSession(); | |
| 344 | + | |
| 345 | + // 设置gloable对象,在drl中通过别名使用 | |
| 346 | + session.setGlobal("validResult", result); | |
| 347 | + session.setGlobal("log", logger); // 设置日志 | |
| 348 | + | |
| 349 | + // 载入数据 | |
| 350 | + session.insert(validateParam); | |
| 351 | + for (SchedulePlanInfo schedulePlanInfo: planResult.getSchedulePlanInfos()) { | |
| 352 | + session.insert(schedulePlanInfo); | |
| 353 | + } | |
| 354 | + | |
| 355 | + // 执行rule | |
| 356 | + session.fireAllRules(); | |
| 357 | + | |
| 358 | + // 执行完毕销毁,有日志的也要关闭 | |
| 359 | + session.dispose(); | |
| 360 | + | |
| 361 | +// for (ValidateResults_output.ValidInfo validInfo: result.getInfos()) { | |
| 362 | +// logger.info(validInfo.getDesc()); | |
| 363 | +// } | |
| 364 | + | |
| 365 | + // 取10条错误 | |
| 366 | + int size = result.getInfos().size() > 10 ? 10: result.getInfos().size(); | |
| 367 | + List<String> desclist = new ArrayList<>(); | |
| 368 | + for (int i = 0; i < size; i++) { | |
| 369 | + desclist.add(result.getInfos().get(i).getDesc()); | |
| 370 | + } | |
| 371 | + if (desclist.size() > 0) { | |
| 372 | + schedulePlan.setPlanResult(StringUtils.join(desclist, "</br>")); | |
| 373 | + } else { | |
| 374 | + schedulePlan.setPlanResult("ok"); | |
| 375 | + } | |
| 376 | + | |
| 377 | + // TODO:设定错误信息 | |
| 378 | + } | |
| 379 | + | |
| 324 | 380 | @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED) |
| 325 | 381 | public SchedulePlan save(SchedulePlan schedulePlan) { |
| 326 | 382 | // pre、如果排班的数据之前已经有了,删除之前的数据 |
| ... | ... | @@ -341,6 +397,9 @@ public class SchedulePlanServiceImpl extends BServiceImpl<SchedulePlan, Long> im |
| 341 | 397 | // 3、确定套跑规则 |
| 342 | 398 | rerunPlanResult(planResult, schedulePlan); |
| 343 | 399 | |
| 400 | + // TODO:3-1、验证排班结果 | |
| 401 | + validPlanResult(planResult, schedulePlan); | |
| 402 | + | |
| 344 | 403 | // 4、保存数据(jdbcTemplate 批量插入) |
| 345 | 404 | Date start4 = new Date(); |
| 346 | 405 | scheduleRuleService.generateSchedulePlan(schedulePlan, planResult.getSchedulePlanInfos()); | ... | ... |
src/main/java/com/bsth/service/schedule/rules/MyDroolsConfiguration.java
| ... | ... | @@ -74,6 +74,9 @@ public class MyDroolsConfiguration { |
| 74 | 74 | kfs.write("src/main/resources/rerun.drl", kieServices.getResources() |
| 75 | 75 | .newInputStreamResource(this.getClass().getResourceAsStream( |
| 76 | 76 | "/rules/rerun.drl"), "UTF-8")); |
| 77 | + kfs.write("src/main/resources/validplan.drl", kieServices.getResources() | |
| 78 | + .newInputStreamResource(this.getClass().getResourceAsStream( | |
| 79 | + "/rules/validplan.drl"), "UTF-8")); | |
| 77 | 80 | // TODO:还有其他drl.... |
| 78 | 81 | |
| 79 | 82 | // 4、创建KieBuilder,使用KieFileSystem构建 | ... | ... |
src/main/java/com/bsth/service/schedule/rules/validate/ValidRepeatBcFunction.java
0 → 100644
| 1 | +package com.bsth.service.schedule.rules.validate; | |
| 2 | + | |
| 3 | +import com.bsth.entity.schedule.SchedulePlanInfo; | |
| 4 | +import org.kie.api.runtime.rule.AccumulateFunction; | |
| 5 | + | |
| 6 | +import java.io.*; | |
| 7 | +import java.text.SimpleDateFormat; | |
| 8 | +import java.util.ArrayList; | |
| 9 | +import java.util.HashMap; | |
| 10 | +import java.util.List; | |
| 11 | +import java.util.Map; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * 计算班次重复错误。 | |
| 15 | + * 同一个路牌下,相同发车时间的班次数。 | |
| 16 | + * 注意:使用这个函数时,要一天计算一次,多天计算无意义。 | |
| 17 | + */ | |
| 18 | +public class ValidRepeatBcFunction implements AccumulateFunction { | |
| 19 | + @Override | |
| 20 | + public void writeExternal(ObjectOutput out) throws IOException { | |
| 21 | + } | |
| 22 | + | |
| 23 | + @Override | |
| 24 | + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { | |
| 25 | + | |
| 26 | + } | |
| 27 | + | |
| 28 | + protected static class RepeatBcInfo implements Externalizable { | |
| 29 | + /** 错误描述 */ | |
| 30 | + public List<ValidateResults_output.ValidInfo> validInfoList = new ArrayList<>(); | |
| 31 | + /** 内部计数Map,key:{路牌Id}_{发车时间},value:个数 */ | |
| 32 | + public Map<String, Integer> lpBcFcsjCount = new HashMap<>(); | |
| 33 | + | |
| 34 | + public RepeatBcInfo() { | |
| 35 | + } | |
| 36 | + | |
| 37 | + @Override | |
| 38 | + public void writeExternal(ObjectOutput out) throws IOException { | |
| 39 | + out.writeObject(validInfoList); | |
| 40 | + } | |
| 41 | + | |
| 42 | + @Override | |
| 43 | + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { | |
| 44 | + validInfoList = (List<ValidateResults_output.ValidInfo>) in.readObject(); | |
| 45 | + } | |
| 46 | + } | |
| 47 | + | |
| 48 | + @Override | |
| 49 | + public Serializable createContext() { | |
| 50 | + return new RepeatBcInfo(); | |
| 51 | + } | |
| 52 | + | |
| 53 | + @Override | |
| 54 | + public void init(Serializable serializable) throws Exception { | |
| 55 | + // TODO: | |
| 56 | + } | |
| 57 | + | |
| 58 | + @Override | |
| 59 | + public void accumulate(Serializable context, Object o) { | |
| 60 | + RepeatBcInfo repeatBcInfo = (RepeatBcInfo) context; | |
| 61 | + SchedulePlanInfo schedulePlanInfo = (SchedulePlanInfo) o; | |
| 62 | + | |
| 63 | + String key = schedulePlanInfo.getLp() + "_" + schedulePlanInfo.getFcsj(); | |
| 64 | + SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日"); | |
| 65 | + String infoformat = "日期(%s),路牌(%s),班次(%s),重复(%d)次"; | |
| 66 | + if (repeatBcInfo.lpBcFcsjCount.get(key) == null) { | |
| 67 | + repeatBcInfo.lpBcFcsjCount.put(key, 1); | |
| 68 | + } else { | |
| 69 | + int count = repeatBcInfo.lpBcFcsjCount.get(key) + 1; | |
| 70 | + ValidateResults_output.ValidInfo validInfo = new ValidateResults_output.ValidInfo(); | |
| 71 | + validInfo.setSd(schedulePlanInfo.getScheduleDate()); | |
| 72 | + validInfo.setDesc(String.format( | |
| 73 | + infoformat, | |
| 74 | + sf.format(schedulePlanInfo.getScheduleDate()), | |
| 75 | + schedulePlanInfo.getLpName(), | |
| 76 | + schedulePlanInfo.getFcsj(), | |
| 77 | + count)); | |
| 78 | + repeatBcInfo.validInfoList.add(validInfo); | |
| 79 | + repeatBcInfo.lpBcFcsjCount.put(key, count); | |
| 80 | + } | |
| 81 | + } | |
| 82 | + | |
| 83 | + @Override | |
| 84 | + public boolean supportsReverse() { | |
| 85 | + return false; | |
| 86 | + } | |
| 87 | + | |
| 88 | + @Override | |
| 89 | + public void reverse(Serializable serializable, Object o) throws Exception { | |
| 90 | + | |
| 91 | + } | |
| 92 | + | |
| 93 | + @Override | |
| 94 | + public Class<?> getResultType() { | |
| 95 | + return List.class; | |
| 96 | + } | |
| 97 | + | |
| 98 | + @Override | |
| 99 | + public Object getResult(Serializable context) throws Exception { | |
| 100 | + RepeatBcInfo repeatBcInfo = (RepeatBcInfo) context; | |
| 101 | + return repeatBcInfo.validInfoList; | |
| 102 | + } | |
| 103 | +} | ... | ... |
src/main/java/com/bsth/service/schedule/rules/validate/ValidateParam.java
| ... | ... | @@ -16,7 +16,9 @@ public class ValidateParam { |
| 16 | 16 | /** 间隔天数 */ |
| 17 | 17 | private Integer days; |
| 18 | 18 | |
| 19 | - public ValidateParam() { | |
| 19 | + public ValidateParam(DateTime f, DateTime t) { | |
| 20 | + this.fromDate = f; | |
| 21 | + this.toDate = t; | |
| 20 | 22 | Period period = new Period(fromDate, toDate, PeriodType.days()); |
| 21 | 23 | days = period.getDays() + 1; |
| 22 | 24 | } | ... | ... |
src/main/java/com/bsth/service/schedule/rules/validate/ValidateResults_output.java
src/main/resources/application-dev.properties
| ... | ... | @@ -10,7 +10,7 @@ spring.jpa.show-sql= true |
| 10 | 10 | spring.datasource.driver-class-name= com.mysql.jdbc.Driver |
| 11 | 11 | spring.datasource.url= jdbc:mysql://127.0.0.1/control?useUnicode=true&characterEncoding=utf-8&useSSL=false |
| 12 | 12 | spring.datasource.username= root |
| 13 | -spring.datasource.password= root | |
| 13 | +spring.datasource.password= | |
| 14 | 14 | |
| 15 | 15 | #DATASOURCE |
| 16 | 16 | spring.datasource.max-active=100 | ... | ... |
src/main/resources/rules/functions.drl
| ... | ... | @@ -4,4 +4,5 @@ import accumulate com.bsth.service.schedule.rules.ttinfo2.ErrorBcCountFunction e |
| 4 | 4 | import accumulate com.bsth.service.schedule.rules.shiftloop.GidsCountFunction gidscount; |
| 5 | 5 | import accumulate com.bsth.service.schedule.rules.shiftloop.GidFbTimeFunction gidfbtime; |
| 6 | 6 | import accumulate com.bsth.service.schedule.rules.ttinfo.LpInfoResultsFunction lpinforesult; |
| 7 | -import accumulate com.bsth.service.schedule.rules.ttinfo.MinRuleQyrqFunction minruleqyrq | |
| 8 | 7 | \ No newline at end of file |
| 8 | +import accumulate com.bsth.service.schedule.rules.ttinfo.MinRuleQyrqFunction minruleqyrq; | |
| 9 | +import accumulate com.bsth.service.schedule.rules.validate.ValidRepeatBcFunction vrb; | |
| 9 | 10 | \ No newline at end of file | ... | ... |
src/main/resources/rules/validplan.drl
| 1 | -// TODO: | |
| 2 | 1 | \ No newline at end of file |
| 2 | +package com.bsth.service.schedule.rules.validate; | |
| 3 | + | |
| 4 | +import com.bsth.entity.schedule.SchedulePlanInfo; | |
| 5 | + | |
| 6 | +import org.joda.time.*; | |
| 7 | +import java.util.*; | |
| 8 | + | |
| 9 | +import org.slf4j.Logger; | |
| 10 | + | |
| 11 | +// 全局日志类(一般使用调用此规则的service类) | |
| 12 | +global Logger log; | |
| 13 | + | |
| 14 | +// 输出 | |
| 15 | +global ValidateResults_output validResult; | |
| 16 | + | |
| 17 | +//------------------------- 第一阶段、构造循环体 ----------------------------// | |
| 18 | + | |
| 19 | +declare Loop_param | |
| 20 | + start_date: DateTime // 开始日期(这个要不停的更新迭代) | |
| 21 | + end_date: DateTime // 结束日期 | |
| 22 | + sdays: Integer // 总共循环的天数 | |
| 23 | +end | |
| 24 | + | |
| 25 | +rule "Calcu_Loop_param" | |
| 26 | + salience 1000 | |
| 27 | + when | |
| 28 | + ValidateParam( | |
| 29 | + $fd: fromDate, | |
| 30 | + $ed: toDate, | |
| 31 | + $days: days | |
| 32 | + ) | |
| 33 | + then | |
| 34 | + Loop_param p = new Loop_param(); | |
| 35 | + p.setStart_date($fd); | |
| 36 | + p.setEnd_date($ed); | |
| 37 | + p.setSdays($days); | |
| 38 | + | |
| 39 | + insert(p); | |
| 40 | +end | |
| 41 | + | |
| 42 | +//------------------------- 第二阶段、验证计算 ----------------------------// | |
| 43 | + | |
| 44 | + | |
| 45 | +rule "Valid_repeat_bc" // 验证是否存在重复班次 | |
| 46 | + salience 600 | |
| 47 | + when | |
| 48 | + $lp: Loop_param($sd: start_date, $ed: end_date) | |
| 49 | + eval($sd.isBefore($ed) || $sd.isEqual($ed)) | |
| 50 | + $spiList: ArrayList() from collect (SchedulePlanInfo(scheduleDate.getTime() == $sd.millis)) | |
| 51 | + $infos: ArrayList() from accumulate ($spi: SchedulePlanInfo() from $spiList, vrb($spi)) | |
| 52 | + then | |
| 53 | + // TODO: | |
| 54 | +// log.info("日期={},班次重复错误数={}", $sd, $infos.size()); | |
| 55 | + | |
| 56 | + validResult.getInfos().addAll($infos); | |
| 57 | + | |
| 58 | + // 迭代 | |
| 59 | + $lp.setStart_date($sd.plusDays(1)); | |
| 60 | + update($lp); | |
| 61 | + | |
| 62 | +end | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | ... | ... |
src/main/resources/static/pages/scheduleApp/module/core/schedulePlanManage/list.html
| ... | ... | @@ -9,7 +9,8 @@ |
| 9 | 9 | <th style="width: 100%;">关联时刻表</th> |
| 10 | 10 | <th style="width: 150px;">排班开始日期</th> |
| 11 | 11 | <th style="width: 150px;">排班结束日期</th> |
| 12 | - <th style="width: 250px;">排班人/操作时间</th> | |
| 12 | + <th style="width: 150px;">排班人/操作时间</th> | |
| 13 | + <th style="width: 100px;">状态</th> | |
| 13 | 14 | <th style="width: 180px;">操作</th> |
| 14 | 15 | </tr> |
| 15 | 16 | <tr role="row" class="filter"> |
| ... | ... | @@ -60,6 +61,7 @@ |
| 60 | 61 | </div> |
| 61 | 62 | </td> |
| 62 | 63 | <td></td> |
| 64 | + <td></td> | |
| 63 | 65 | <td> |
| 64 | 66 | <button class="btn btn-sm green btn-outline filter-submit margin-bottom" |
| 65 | 67 | ng-click="ctrl.doPage()"> |
| ... | ... | @@ -94,9 +96,28 @@ |
| 94 | 96 | <span ng-bind="info.scheduleToTime | date: 'yyyy-MM-dd '"></span> |
| 95 | 97 | </td> |
| 96 | 98 | <td> |
| 97 | - <span ng-bind="info.updateBy.userName"></span> | |
| 98 | - / | |
| 99 | - <span ng-bind="info.updateDate | date: 'yyyy-MM-dd HH:mm:ss'"></span> | |
| 99 | + <div> | |
| 100 | + <a href="#"> | |
| 101 | + <i class="fa fa-user"></i> | |
| 102 | + <span ng-bind="info.updateBy.userName"></span> | |
| 103 | + </a> | |
| 104 | + </div> | |
| 105 | + <div> | |
| 106 | + <a href="#"> | |
| 107 | + <span ng-bind="info.updateDate | date: 'yyyy-MM-dd HH:mm:ss'"></span> | |
| 108 | + </a> | |
| 109 | + </div> | |
| 110 | + | |
| 111 | + </td> | |
| 112 | + <td> | |
| 113 | + <a href="#" class="btn btn-success btn-sm" ng-if="info.planResult == 'ok'"> | |
| 114 | + <span>成功</span> | |
| 115 | + </a> | |
| 116 | + <a sweetalert | |
| 117 | + sweet-options="{title: '排班错误信息',text: '线路:' + info.xl.name + '</br>开始时间:' + ctrl.toDateStr(info.scheduleFromTime) + '</br>结束时间:' + ctrl.toDateStr(info.scheduleToTime) + '</br>' + info.planResult, html: true,type: 'warning',showCancelButton: true,confirmButtonColor: '#DD6B55',confirmButtonText: '是',cancelButtonText: '取消'}" | |
| 118 | + sweet-on-confirm="" | |
| 119 | + class="btn btn-danger btn-sm" | |
| 120 | + ng-if="info.planResult != 'ok'">点击查错</a> | |
| 100 | 121 | </td> |
| 101 | 122 | <td> |
| 102 | 123 | <!--<a href="details.html?lineId={{obj.id}}" class="btn default blue-stripe btn-sm"> 详细 </a>--> | ... | ... |