Commit 7f799a68a88e95206eeded82336b1be0ebbacef1

Authored by 徐烜
1 parent a2d14a12

Update

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&lt;SchedulePlan, Long&gt; 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
... ... @@ -10,7 +10,7 @@ import java.util.List;
10 10 public class ValidateResults_output {
11 11 private List<ValidInfo> infos = new ArrayList<>();
12 12  
13   - static class ValidInfo {
  13 + public static class ValidInfo {
14 14 /** 日期 */
15 15 private Date sd;
16 16 /** 描述 */
... ...
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>-->
... ...
src/main/resources/static/pages/scheduleApp/module/core/scheduleRuleManage/list.html
... ... @@ -66,6 +66,7 @@
66 66 <td>
67 67 <div>
68 68 <a href="#">
  69 + <i class="fa fa-user"></i>
69 70 <span ng-bind="info.updateBy.userName"></span>
70 71 </a>
71 72 </div>
... ...