提交 a65f5ced authored 作者: Matrix's avatar Matrix

[核查模块] 核查周期保存

上级 515efe4d
...@@ -22,7 +22,7 @@ public enum CheckType { ...@@ -22,7 +22,7 @@ public enum CheckType {
*/ */
MANUAL_CHECK(2, "手动核查"); MANUAL_CHECK(2, "手动核查");
private Integer id; private final Integer id;
private String name; private final String name;
} }
package com.tykj.dev.device.confirmcheck.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* TaskPeriod.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2020/10/26 at 4:47 下午
*/
@Getter
@AllArgsConstructor
public enum TaskPeriod {
/**
* 月度
*/
monthly("0 0 0 1 * ? *"),
/**
* 季度
*/
quarterly("0 0 0 1 3/3 ? *"),
/**
* 年度
*/
yearly("0 0 0 1 3/3 ? *");
private final String cron;
}
package com.tykj.dev.device.confirmcheck.common;
import javax.persistence.AttributeConverter;
import java.util.stream.Stream;
/**
* TaskPeriodConvert.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2020/10/26 at 4:54 下午
*/
public class TaskPeriodConvert implements AttributeConverter<TaskPeriod, String> {
/**
* Converts the value stored in the entity attribute into the
* data representation to be stored in the database.
*
* @param attribute the entity attribute value to be converted
* @return the converted data to be stored in the database
* column
*/
@Override
public String convertToDatabaseColumn(TaskPeriod attribute) {
if (attribute == null) {
return null;
}
return attribute.getCron();
}
/**
* Converts the data stored in the database column into the
* value to be stored in the entity attribute.
* Note that it is the responsibility of the converter writer to
* specify the correct <code>dbData</code> type for the corresponding
* column for use by the JDBC driver: i.e., persistence providers are
* not expected to do such type conversion.
*
* @param dbData the data from the database column to be
* converted
* @return the converted value to be stored in the entity
* attribute
*/
@Override
public TaskPeriod convertToEntityAttribute(String dbData) {
if (dbData == null) {
return null;
}
return Stream.of(TaskPeriod.values())
.filter(t -> t.getCron().equals(dbData))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}
}
package com.tykj.dev.device.confirmcheck.controller; package com.tykj.dev.device.confirmcheck.controller;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.tykj.dev.config.GlobalMap; import com.tykj.dev.config.GlobalMap;
import com.tykj.dev.config.swagger.AutoDocument; import com.tykj.dev.config.swagger.AutoDocument;
import com.tykj.dev.device.confirmcheck.common.CheckType; import com.tykj.dev.device.confirmcheck.common.CheckType;
import com.tykj.dev.device.confirmcheck.common.TaskPeriod;
import com.tykj.dev.device.confirmcheck.entity.cache.AreaCache; import com.tykj.dev.device.confirmcheck.entity.cache.AreaCache;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckBill; import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckBill;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckDetail; import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckDetail;
...@@ -12,7 +12,7 @@ import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckStat; ...@@ -12,7 +12,7 @@ import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckStat;
import com.tykj.dev.device.confirmcheck.entity.vo.*; import com.tykj.dev.device.confirmcheck.entity.vo.*;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckBillDao; import com.tykj.dev.device.confirmcheck.repository.DeviceCheckBillDao;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckDetailDao; import com.tykj.dev.device.confirmcheck.repository.DeviceCheckDetailDao;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckStatRepo; import com.tykj.dev.device.confirmcheck.repository.DeviceCheckStatDao;
import com.tykj.dev.device.confirmcheck.service.ConfirmCheckService; import com.tykj.dev.device.confirmcheck.service.ConfirmCheckService;
import com.tykj.dev.device.confirmcheck.utils.ObjTransUtil; import com.tykj.dev.device.confirmcheck.utils.ObjTransUtil;
import com.tykj.dev.device.library.repository.DeviceLibraryDao; import com.tykj.dev.device.library.repository.DeviceLibraryDao;
...@@ -33,7 +33,6 @@ import com.tykj.dev.device.user.util.AuthenticationUtils; ...@@ -33,7 +33,6 @@ import com.tykj.dev.device.user.util.AuthenticationUtils;
import com.tykj.dev.misc.base.ResultObj; import com.tykj.dev.misc.base.ResultObj;
import com.tykj.dev.misc.base.StatusEnum; import com.tykj.dev.misc.base.StatusEnum;
import com.tykj.dev.misc.utils.JacksonUtil; import com.tykj.dev.misc.utils.JacksonUtil;
import com.tykj.dev.misc.utils.MapperUtils;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -43,10 +42,9 @@ import org.springframework.http.ResponseEntity; ...@@ -43,10 +42,9 @@ import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.time.LocalDate; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import static com.tykj.dev.misc.base.BusinessEnum.CONFIRM_CHECK_DETAIL; import static com.tykj.dev.misc.base.BusinessEnum.CONFIRM_CHECK_DETAIL;
import static com.tykj.dev.misc.base.BusinessEnum.CONFIRM_CHECK_STAT; import static com.tykj.dev.misc.base.BusinessEnum.CONFIRM_CHECK_STAT;
...@@ -66,7 +64,7 @@ import static java.util.stream.Collectors.*; ...@@ -66,7 +64,7 @@ import static java.util.stream.Collectors.*;
public class DeviceCheckController { public class DeviceCheckController {
@Autowired @Autowired
private DeviceCheckStatRepo statRepo; private DeviceCheckStatDao statRepo;
@Autowired @Autowired
private DeviceCheckBillDao billRepo; private DeviceCheckBillDao billRepo;
@Autowired @Autowired
...@@ -128,184 +126,40 @@ public class DeviceCheckController { ...@@ -128,184 +126,40 @@ public class DeviceCheckController {
return ResponseEntity.ok(new ResultObj<>(detailVoList)); return ResponseEntity.ok(new ResultObj<>(detailVoList));
} }
@ApiOperation(value = "发起自动核查", notes = "发起自动核查") /**
@PostMapping("/auto") * @param periodId 1-月度 2-季度 3-年度
public ResultObj<Map<String, List<Integer>>> startAutoCheck() { * @return
// 构建返回数据对象 */
Map<String, List<Integer>> resultIds = new HashMap<>(8); @ApiOperation(value = "更新自动核查周期", notes = "更新自动核查周期")
resultIds.put("statId", new ArrayList<>()); @PutMapping("/task/{period}")
resultIds.put("detailId", new ArrayList<>()); public ResponseEntity updateTaskPeriod(@PathVariable Integer periodId) {
resultIds.put("taskId", new ArrayList<>()); if (periodId < 1 || periodId > 3) {
return ResponseEntity.status(400).body(new ResultObj<>("提供了错误的周期参数!应该是 1/2/3 , 您提供的是" + periodId));
Map<String, Integer> areaStatIdMap = new HashMap<>(16); }
TaskPeriod period = TaskPeriod.values()[periodId - 1];
// 发起省级的统计 - 获得所有的市级单位
List<Units> cityUnits = unitsRepo.findAllByLevel(2); // 更新最新的周期
Units provUnit = unitsRepo.findById(1).get(); ccService.updateTaskPeriod(period);
String baseTitle = "自动-" + LocalDate.now().getYear() + "年" + (LocalDate.now().getMonthValue() + 1) + "月"; // 结束当前任务,开启下轮任务
// 构建省的统计账单 ccService.stopAutoCheckCron();
boolean startSuccess = ccService.startAutoCheckCron();
DeviceCheckStat provStatDo = new DeviceCheckStat(
CheckType.AUTO_CHECK, if (startSuccess) {
baseTitle + provUnit.getName() + "核查统计单", String nextTime = ccService.getNextTaskDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
"核查统计单", return ResponseEntity.ok(new ResultObj<>(String.format("更新自动核查周期成功,下一次任务的执行时间为%s %n", nextTime)));
"系统发起的统计|" + provUnit.getName() + "|" + provUnit.getAreaId()); } else {
return ResponseEntity.status(400).body("自动核查更新周期失败了!");
DeviceCheckStat provStat = statRepo.save(provStatDo);
resultIds.get("statId").add(provStat.getId());
List<DeviceLibrary> deviceList = deviceRepo.findAll();
Map<String, List<DeviceLibrary>> devInLib = deviceList.stream()
.filter(device -> device.getOwnUnit().equals(device.getLocationUnit()))
.collect(groupingBy(DeviceLibrary::getOwnUnit));
Map<String, List<DeviceLibrary>> devNotInLib = deviceList.stream()
.filter(device -> !device.getOwnUnit().equals(device.getLocationUnit()))
.collect(groupingBy(DeviceLibrary::getOwnUnit));
// 构建省统Task
TaskBto provStatTask = new Task(CHECK_STAT_0.id, "省自动核查", 0, ".0.", CONFIRM_CHECK_STAT.id, provStat.getId(), provUnit.getUnitId())
.parse2Bto();
provStatTask.setInvolveUserIdList(Lists.newArrayList(-1));
provStatTask = taskService.start(provStatTask);
resultIds.get("taskId").add(provStatTask.getId());
List<CheckDeviceStatVo> statVoList = new ArrayList<>();
List<DeviceCheckStat> cityStatList = new ArrayList<>();
List<String> countyAreaNames = new ArrayList<>();
// 构建所有市的统计账单(先不考虑JSON-INFO)
for (Units cityUnit : cityUnits) {
List<Integer> areaIds = areaRepo.findAllByFatherId(cityUnit.getAreaId()).stream().map(Area::getId).collect(toList());
List<Units> countyUnits = unitsRepo.findByAreaIdIn(areaIds);
// 构建市统账单
DeviceCheckStat cityStatDo = new DeviceCheckStat(
CheckType.AUTO_CHECK,
baseTitle + cityUnit.getName() + "核查统计单",
"核查统计单",
"系统发起的统计|" + cityUnit.getName() + "|" + cityUnit.getAreaId()
);
DeviceCheckStat cityStat = statRepo.save(cityStatDo);
cityStatList.add(cityStat);
String cityName = areaCache.findById(cityUnit.getAreaId()).getName();
areaStatIdMap.put(cityName, cityStat.getId());
resultIds.get("statId").add(cityStat.getId());
// 构建市统task 获得id
TaskBto cityStatTask = new Task(CHECK_STAT_0.id, cityUnit.getName() + "自动核查统计", provStatTask.getId(), addNode(provStatTask.getNodeIdDetail(), provStatDo.getId()), CONFIRM_CHECK_STAT.id, cityStat.getId(), cityUnit.getUnitId())
.parse2Bto();
cityStatTask.setInvolveUserIdList(Lists.newArrayList(-1));
cityStatTask = taskService.start(cityStatTask);
resultIds.get("taskId").add(cityStatTask.getId());
// 构建市自查账单
DeviceCheckDetail cityDetailDo = DeviceCheckDetail.EmptyWithChecker(
"系统发起的自查|" + cityUnit.getName() + "|" + cityUnit.getAreaId(),
baseTitle,
0, 0, 0, 0,
cityUnit.getName(),
devInLib.getOrDefault(cityUnit.getName(), new ArrayList<>()),
devNotInLib.getOrDefault(cityUnit.getName(), new ArrayList<>()));
DeviceCheckDetail cityDetail = detailRepo.save(cityDetailDo);
resultIds.get("detailId").add(cityDetail.getId());
List<CheckDeviceStatVo> cityStatVoList = deviceList.stream()
.filter(d -> d.getOwnUnit().equals(cityUnit.getName()))
.map(d -> transUtil.device2InitStatVo(d, cityName, cityStat.getId(), cityDetail.getId()))
.collect(toList());
statVoList.addAll(cityStatVoList);
// 构建市自查TASK
TaskBto cityDetailTask = new TaskBto(CHECK_DETAIL_0.id, cityUnit.getName() + "自动核查自查", cityStatTask.getId(), addNode(cityStatTask.getNodeIdDetail(), cityStatTask.getId()), CONFIRM_CHECK_DETAIL.id, cityDetail.getId(), cityUnit.getUnitId(), 0);
cityDetailTask = taskService.start(cityDetailTask);
resultIds.get("taskId").add(cityDetailTask.getId());
// 构建县任务
for (Units countyUnit : countyUnits) {
String countyName = areaCache.findById(countyUnit.getAreaId()).getName();
countyAreaNames.add(countyName);
//构建县自查账单
DeviceCheckDetail countyDetailDo = DeviceCheckDetail.EmptyWithChecker(
"系统发起的自查|" + countyUnit.getName() + "|" + countyUnit.getAreaId(),
baseTitle,
0, 0, 0, 0,
countyUnit.getName(),
devInLib.getOrDefault(countyUnit.getName(), new ArrayList<>()),
devNotInLib.getOrDefault(countyUnit.getName(), new ArrayList<>()));
DeviceCheckDetail countyDetail = detailRepo.save(countyDetailDo);
resultIds.get("detailId").add(countyDetail.getId());
List<CheckDeviceStatVo> countyStatVoList = deviceList.stream()
.filter(d -> d.getOwnUnit().equals(countyUnit.getName()))
.map(d -> transUtil.device2InitStatVo(d, countyName, cityStat.getId(), countyDetail.getId()))
.collect(toList());
statVoList.addAll(countyStatVoList);
//构建县自查TASK
TaskBto countyDetailTask = new TaskBto(CHECK_DETAIL_0.id, countyUnit.getName() + "自动核查自查", cityStatTask.getId(), addNode(cityStatTask.getNodeIdDetail(), cityStatTask.getId()), CONFIRM_CHECK_DETAIL.id, countyDetail.getId(), countyUnit.getUnitId(), 0);
countyDetailTask = taskService.start(countyDetailTask);
resultIds.get("taskId").add(countyDetailTask.getId());
}
}
// 处理JSON INFO 数据
// 对于省统计来说,需要把区的数据累加到市级中去
List<CheckDeviceStatVo> statVoListCopy1 = MapperUtils.deepClone(statVoList, CheckDeviceStatVo::new);
List<CheckDeviceStatVo> statVoListCopy2 = MapperUtils.deepClone(statVoList, CheckDeviceStatVo::new);
//按照区数据与市数据进行分组 - true->区级装备统计信息 false->市级装备统计是信息
Map<Boolean, List<CheckDeviceStatVo>> regionMap = statVoListCopy1.stream()
.collect(partitioningBy(stat -> countyAreaNames.contains(stat.getAreaStatList().get(0).getAreaName())));
// 区数据
List<CheckDeviceStatVo> countyVo = regionMap.get(true);
// 市级数据
Map<String, CheckDeviceStatVo> map = regionMap.get(false).stream()
.collect(toMap(CheckDeviceStatVo::getDeviceModel, Function.identity()));
//查找区域数据内的父级地区(即市),将数据count数据add进去(通过两次get),将areaList数据也加进去
for (CheckDeviceStatVo v : countyVo) {
String couName = v.getAreaStatList().get(0).getAreaName();
String cityName = areaCache.findFatherByName(couName).getName();
//把相同型号的区级的数据merge到市级即可,没有的话改个名加进去
Integer cityStatId = areaStatIdMap.get(cityName);
map.computeIfPresent(v.getDeviceModel(), (k, value) -> value.reduce(v, cityName, cityStatId));
map.computeIfAbsent(v.getDeviceModel(), k -> {
v.getAreaStatList().forEach(area -> area.setAreaName(cityName));
return v;
});
}
//将市级Map里的数据全部取出来展平一层并累加
List<CheckDeviceStatVo> filterVoList = new ArrayList<>(map.values());
provStat.setStatInfo(JacksonUtil.toJSon(filterVoList));
statRepo.save(provStat);
// 对于市统计来说,只需要自己本市以及其下地区的数据
for (DeviceCheckStat csd : cityStatList) {
List<String> cityNames = new ArrayList<>();
if (csd.getRemark().split("\\|").length <= 1) {
continue;
} }
Integer cityId = Integer.valueOf(csd.getRemark().split("\\|")[2]);
String cityName = areaCache.findById(cityId).getName();
List<String> childNames = areaRepo.findByFatherId(cityId).stream().map(Area::getName).collect(toList());
cityNames.add(cityName);
cityNames.addAll(childNames);
//去除其他地区的数据
List<CheckDeviceStatVo> cityStatVo = new ArrayList<>();
statVoListCopy2.stream()
.filter(stat -> cityNames.contains(stat.getAreaStatList().get(0).getAreaName()))
.collect(Collectors.groupingBy(CheckDeviceStatVo::getDeviceModel, reducing(CheckDeviceStatVo::reduce)))
.forEach((k, v) -> cityStatVo.add(v.get()));
csd.setStatInfo(JacksonUtil.toJSon(cityStatVo));
} }
statRepo.saveAll(cityStatList); @ApiOperation(value = "发起自动核查", notes = "发起自动核查")
@PostMapping("/auto")
public ResultObj<Map<String, List<Integer>>> startAutoCheck() {
Map<String, List<Integer>> resultIds = ccService.autoCheck();
return new ResultObj<>(resultIds, "自动核查任务发起成功"); return new ResultObj<>(resultIds, "自动核查任务发起成功");
} }
/** /**
* 手动发起核查 * 手动发起核查
* <li>1. 添加发起核查bill记录</> * <li>1. 添加发起核查bill记录</>
......
package com.tykj.dev.device.confirmcheck.entity.domain;
import com.tykj.dev.device.confirmcheck.common.TaskPeriod;
import com.tykj.dev.misc.base.BaseEntityNoDelete;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import java.time.LocalDateTime;
/**
* DeviceCheckPeriod.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2020/10/26 at 5:03 下午
*/
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class DeviceCheckPeriod extends BaseEntityNoDelete {
private TaskPeriod cronExpression;
}
package com.tykj.dev.device.confirmcheck.repository;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckDetail;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckPeriod;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* DeviceCheckPeriodDao.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2020/10/26 at 5:10 下午
*/
public interface DeviceCheckPeriodDao extends JpaRepository<DeviceCheckPeriod, Integer>, JpaSpecificationExecutor<DeviceCheckPeriod> {
/**
* @return 最新的一条周期数据
*/
DeviceCheckPeriod findTopByOrderByIdDesc();
}
...@@ -9,5 +9,5 @@ import org.springframework.data.jpa.repository.JpaRepository; ...@@ -9,5 +9,5 @@ import org.springframework.data.jpa.repository.JpaRepository;
* @author Matrix <xhyrzldf@gmail.com> * @author Matrix <xhyrzldf@gmail.com>
* @since 2020/8/16 at 5:26 下午 * @since 2020/8/16 at 5:26 下午
*/ */
public interface DeviceCheckStatRepo extends JpaRepository<DeviceCheckStat, Integer> { public interface DeviceCheckStatDao extends JpaRepository<DeviceCheckStat, Integer> {
} }
package com.tykj.dev.device.confirmcheck.service; package com.tykj.dev.device.confirmcheck.service;
import com.tykj.dev.device.confirmcheck.common.TaskPeriod;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckPeriod;
import com.tykj.dev.device.confirmcheck.entity.vo.CheckStatTableVo; import com.tykj.dev.device.confirmcheck.entity.vo.CheckStatTableVo;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
/** /**
* CheckStatService. * CheckStatService.
* *
...@@ -20,4 +26,47 @@ public interface ConfirmCheckService { ...@@ -20,4 +26,47 @@ public interface ConfirmCheckService {
* @return {@link CheckStatTableVo} 's List * @return {@link CheckStatTableVo} 's List
*/ */
Page<CheckStatTableVo> findAllStatTable(String keyword, int page, int size); Page<CheckStatTableVo> findAllStatTable(String keyword, int page, int size);
/**
* 开启自动核查
* @return 自动核查所开启的统计以及详情的账单id和任务id集合
*/
Map<String, List<Integer>> autoCheck();
/**
* 更新自动核查的任务周期
*
* @param taskPeriod 要更新成为的周期
* @return 周期表的最新id
*/
Integer updateTaskPeriod(TaskPeriod taskPeriod);
/**
* 获得当前自动核查的任务周期
*
* @return 当前的 {@link TaskPeriod}
*/
DeviceCheckPeriod getCurrentTaskPeriod();
/**
* 获得下一次计划任务的执行时间
* @return 下次计划任务的执行时间
*/
LocalDate getNextTaskDate();
/**
* 开启自动核查计划任务
*
* @return 任务是否开启成功
*/
boolean startAutoCheckCron();
/**
* 关闭自动核查计划任务
*
* @return 任务是否关闭成功
*/
boolean stopAutoCheckCron();
} }
package com.tykj.dev.device.confirmcheck.service.impl; package com.tykj.dev.device.confirmcheck.service.impl;
import com.tykj.dev.device.confirmcheck.service.ConfirmCheckService; import com.google.common.collect.Lists;
import com.tykj.dev.device.confirmcheck.common.CheckType;
import com.tykj.dev.device.confirmcheck.common.TaskPeriod;
import com.tykj.dev.device.confirmcheck.entity.cache.AreaCache;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckDetail;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckPeriod;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckStat;
import com.tykj.dev.device.confirmcheck.entity.vo.CheckDeviceStatVo;
import com.tykj.dev.device.confirmcheck.entity.vo.CheckStatTableVo; import com.tykj.dev.device.confirmcheck.entity.vo.CheckStatTableVo;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckStatRepo; import com.tykj.dev.device.confirmcheck.repository.DeviceCheckDetailDao;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckPeriodDao;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckStatDao;
import com.tykj.dev.device.confirmcheck.service.ConfirmCheckService;
import com.tykj.dev.device.confirmcheck.utils.ObjTransUtil; import com.tykj.dev.device.confirmcheck.utils.ObjTransUtil;
import com.tykj.dev.device.library.repository.DeviceLibraryDao;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.task.service.TaskService;
import com.tykj.dev.device.task.subject.bto.TaskBto;
import com.tykj.dev.device.task.subject.domin.Task;
import com.tykj.dev.device.user.subject.dao.AreaDao;
import com.tykj.dev.device.user.subject.dao.UnitsDao;
import com.tykj.dev.device.user.subject.entity.Area;
import com.tykj.dev.device.user.subject.entity.Units;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.JacksonUtil;
import com.tykj.dev.misc.utils.MapperUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.tykj.dev.misc.base.BusinessEnum.CONFIRM_CHECK_DETAIL;
import static com.tykj.dev.misc.base.BusinessEnum.CONFIRM_CHECK_STAT;
import static com.tykj.dev.misc.base.StatusEnum.CHECK_DETAIL_0;
import static com.tykj.dev.misc.base.StatusEnum.CHECK_STAT_0;
import static java.util.stream.Collectors.*;
/** /**
* ConfirmCheckServiceImpl. * ConfirmCheckServiceImpl.
* *
* @author Matrix <xhyrzldf@gmail.com> * @author Matrix <xhyrzldf@gmail.com>
* @since 2020/10/13 at 4:07 下午 * @since 2020/10/13 at 4:07 下午
*/ */
@Slf4j
@Service @Service
public class ConfirmCheckServiceImpl implements ConfirmCheckService { public class ConfirmCheckServiceImpl implements ConfirmCheckService, CommandLineRunner {
@Autowired @Autowired
private DeviceCheckStatRepo statRepo; private DeviceCheckStatDao statDao;
@Autowired
private DeviceCheckPeriodDao periodDao;
@Autowired @Autowired
private ObjTransUtil objTransUtil; private ObjTransUtil objTransUtil;
@Autowired
private AreaDao areaRepo;
@Autowired
private UnitsDao unitsRepo;
@Autowired
private DeviceLibraryDao deviceRepo;
@Autowired
private DeviceCheckDetailDao detailRepo;
@Autowired
private ObjTransUtil transUtil;
@Autowired
private TaskService taskService;
@Autowired
private AreaCache areaCache;
private ScheduledFuture<?> future;
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
//实例化一个线程池任务调度类,可以使用自定义的ThreadPoolTaskScheduler
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
return new ThreadPoolTaskScheduler();
}
@Override
@NotNull
public Map<String, List<Integer>> autoCheck() {
// 构建返回数据对象
Map<String, List<Integer>> resultIds = new HashMap<>(8);
resultIds.put("statId", new ArrayList<>());
resultIds.put("detailId", new ArrayList<>());
resultIds.put("taskId", new ArrayList<>());
Map<String, Integer> areaStatIdMap = new HashMap<>(16);
// 发起省级的统计 - 获得所有的市级单位
List<Units> cityUnits = unitsRepo.findAllByLevel(2);
Units provUnit = unitsRepo.findById(1).get();
String baseTitle = "自动-" + LocalDate.now().getYear() + "年" + (LocalDate.now().getMonthValue() + 1) + "月";
// 构建省的统计账单
DeviceCheckStat provStatDo = new DeviceCheckStat(
CheckType.AUTO_CHECK,
baseTitle + provUnit.getName() + "核查统计单",
"核查统计单",
"系统发起的统计|" + provUnit.getName() + "|" + provUnit.getAreaId());
DeviceCheckStat provStat = statDao.save(provStatDo);
resultIds.get("statId").add(provStat.getId());
List<DeviceLibrary> deviceList = deviceRepo.findAll();
Map<String, List<DeviceLibrary>> devInLib = deviceList.stream()
.filter(device -> device.getOwnUnit().equals(device.getLocationUnit()))
.collect(groupingBy(DeviceLibrary::getOwnUnit));
Map<String, List<DeviceLibrary>> devNotInLib = deviceList.stream()
.filter(device -> !device.getOwnUnit().equals(device.getLocationUnit()))
.collect(groupingBy(DeviceLibrary::getOwnUnit));
// 构建省统Task
TaskBto provStatTask = new Task(CHECK_STAT_0.id, "省自动核查", 0, ".0.", CONFIRM_CHECK_STAT.id, provStat.getId(), provUnit.getUnitId())
.parse2Bto();
provStatTask.setInvolveUserIdList(Lists.newArrayList(-1));
provStatTask = taskService.start(provStatTask);
resultIds.get("taskId").add(provStatTask.getId());
List<CheckDeviceStatVo> statVoList = new ArrayList<>();
List<DeviceCheckStat> cityStatList = new ArrayList<>();
List<String> countyAreaNames = new ArrayList<>();
// 构建所有市的统计账单(先不考虑JSON-INFO)
for (Units cityUnit : cityUnits) {
List<Integer> areaIds = areaRepo.findAllByFatherId(cityUnit.getAreaId()).stream().map(Area::getId).collect(toList());
List<Units> countyUnits = unitsRepo.findByAreaIdIn(areaIds);
// 构建市统账单
DeviceCheckStat cityStatDo = new DeviceCheckStat(
CheckType.AUTO_CHECK,
baseTitle + cityUnit.getName() + "核查统计单",
"核查统计单",
"系统发起的统计|" + cityUnit.getName() + "|" + cityUnit.getAreaId()
);
DeviceCheckStat cityStat = statDao.save(cityStatDo);
cityStatList.add(cityStat);
String cityName = areaCache.findById(cityUnit.getAreaId()).getName();
areaStatIdMap.put(cityName, cityStat.getId());
resultIds.get("statId").add(cityStat.getId());
// 构建市统task 获得id
TaskBto cityStatTask = new Task(CHECK_STAT_0.id, cityUnit.getName() + "自动核查统计", provStatTask.getId(), addNode(provStatTask.getNodeIdDetail(), provStatDo.getId()), CONFIRM_CHECK_STAT.id, cityStat.getId(), cityUnit.getUnitId())
.parse2Bto();
cityStatTask.setInvolveUserIdList(Lists.newArrayList(-1));
cityStatTask = taskService.start(cityStatTask);
resultIds.get("taskId").add(cityStatTask.getId());
// 构建市自查账单
DeviceCheckDetail cityDetailDo = DeviceCheckDetail.EmptyWithChecker(
"系统发起的自查|" + cityUnit.getName() + "|" + cityUnit.getAreaId(),
baseTitle,
0, 0, 0, 0,
cityUnit.getName(),
devInLib.getOrDefault(cityUnit.getName(), new ArrayList<>()),
devNotInLib.getOrDefault(cityUnit.getName(), new ArrayList<>()));
DeviceCheckDetail cityDetail = detailRepo.save(cityDetailDo);
resultIds.get("detailId").add(cityDetail.getId());
List<CheckDeviceStatVo> cityStatVoList = deviceList.stream()
.filter(d -> d.getOwnUnit().equals(cityUnit.getName()))
.map(d -> transUtil.device2InitStatVo(d, cityName, cityStat.getId(), cityDetail.getId()))
.collect(toList());
statVoList.addAll(cityStatVoList);
// 构建市自查TASK
TaskBto cityDetailTask = new TaskBto(CHECK_DETAIL_0.id, cityUnit.getName() + "自动核查自查", cityStatTask.getId(), addNode(cityStatTask.getNodeIdDetail(), cityStatTask.getId()), CONFIRM_CHECK_DETAIL.id, cityDetail.getId(), cityUnit.getUnitId(), 0);
cityDetailTask = taskService.start(cityDetailTask);
resultIds.get("taskId").add(cityDetailTask.getId());
// 构建县任务
for (Units countyUnit : countyUnits) {
String countyName = areaCache.findById(countyUnit.getAreaId()).getName();
countyAreaNames.add(countyName);
//构建县自查账单
DeviceCheckDetail countyDetailDo = DeviceCheckDetail.EmptyWithChecker(
"系统发起的自查|" + countyUnit.getName() + "|" + countyUnit.getAreaId(),
baseTitle,
0, 0, 0, 0,
countyUnit.getName(),
devInLib.getOrDefault(countyUnit.getName(), new ArrayList<>()),
devNotInLib.getOrDefault(countyUnit.getName(), new ArrayList<>()));
DeviceCheckDetail countyDetail = detailRepo.save(countyDetailDo);
resultIds.get("detailId").add(countyDetail.getId());
List<CheckDeviceStatVo> countyStatVoList = deviceList.stream()
.filter(d -> d.getOwnUnit().equals(countyUnit.getName()))
.map(d -> transUtil.device2InitStatVo(d, countyName, cityStat.getId(), countyDetail.getId()))
.collect(toList());
statVoList.addAll(countyStatVoList);
//构建县自查TASK
TaskBto countyDetailTask = new TaskBto(CHECK_DETAIL_0.id, countyUnit.getName() + "自动核查自查", cityStatTask.getId(), addNode(cityStatTask.getNodeIdDetail(), cityStatTask.getId()), CONFIRM_CHECK_DETAIL.id, countyDetail.getId(), countyUnit.getUnitId(), 0);
countyDetailTask = taskService.start(countyDetailTask);
resultIds.get("taskId").add(countyDetailTask.getId());
}
}
// 处理JSON INFO 数据
// 对于省统计来说,需要把区的数据累加到市级中去
List<CheckDeviceStatVo> statVoListCopy1 = MapperUtils.deepClone(statVoList, CheckDeviceStatVo::new);
List<CheckDeviceStatVo> statVoListCopy2 = MapperUtils.deepClone(statVoList, CheckDeviceStatVo::new);
//按照区数据与市数据进行分组 - true->区级装备统计信息 false->市级装备统计是信息
Map<Boolean, List<CheckDeviceStatVo>> regionMap = statVoListCopy1.stream()
.collect(partitioningBy(stat -> countyAreaNames.contains(stat.getAreaStatList().get(0).getAreaName())));
// 区数据
List<CheckDeviceStatVo> countyVo = regionMap.get(true);
// 市级数据
Map<String, CheckDeviceStatVo> map = regionMap.get(false).stream()
.collect(toMap(CheckDeviceStatVo::getDeviceModel, Function.identity()));
//查找区域数据内的父级地区(即市),将数据count数据add进去(通过两次get),将areaList数据也加进去
for (CheckDeviceStatVo v : countyVo) {
String couName = v.getAreaStatList().get(0).getAreaName();
String cityName = areaCache.findFatherByName(couName).getName();
//把相同型号的区级的数据merge到市级即可,没有的话改个名加进去
Integer cityStatId = areaStatIdMap.get(cityName);
map.computeIfPresent(v.getDeviceModel(), (k, value) -> value.reduce(v, cityName, cityStatId));
map.computeIfAbsent(v.getDeviceModel(), k -> {
v.getAreaStatList().forEach(area -> area.setAreaName(cityName));
return v;
});
}
//将市级Map里的数据全部取出来展平一层并累加
List<CheckDeviceStatVo> filterVoList = new ArrayList<>(map.values());
provStat.setStatInfo(JacksonUtil.toJSon(filterVoList));
statDao.save(provStat);
// 对于市统计来说,只需要自己本市以及其下地区的数据
for (DeviceCheckStat csd : cityStatList) {
List<String> cityNames = new ArrayList<>();
if (csd.getRemark().split("\\|").length <= 1) {
continue;
}
Integer cityId = Integer.valueOf(csd.getRemark().split("\\|")[2]);
String cityName = areaCache.findById(cityId).getName();
List<String> childNames = areaRepo.findByFatherId(cityId).stream().map(Area::getName).collect(toList());
cityNames.add(cityName);
cityNames.addAll(childNames);
//去除其他地区的数据
List<CheckDeviceStatVo> cityStatVo = new ArrayList<>();
statVoListCopy2.stream()
.filter(stat -> cityNames.contains(stat.getAreaStatList().get(0).getAreaName()))
.collect(Collectors.groupingBy(CheckDeviceStatVo::getDeviceModel, reducing(CheckDeviceStatVo::reduce)))
.forEach((k, v) -> cityStatVo.add(v.get()));
csd.setStatInfo(JacksonUtil.toJSon(cityStatVo));
}
statDao.saveAll(cityStatList);
return resultIds;
}
/** /**
* 根据关键字查询报告列表 * 根据关键字查询报告列表
* *
...@@ -39,7 +293,7 @@ public class ConfirmCheckServiceImpl implements ConfirmCheckService { ...@@ -39,7 +293,7 @@ public class ConfirmCheckServiceImpl implements ConfirmCheckService {
*/ */
@Override @Override
public Page<CheckStatTableVo> findAllStatTable(String keyword, int page, int size) { public Page<CheckStatTableVo> findAllStatTable(String keyword, int page, int size) {
List<CheckStatTableVo> tableVos = statRepo.findAll().stream() List<CheckStatTableVo> tableVos = statDao.findAll().stream()
.map(objTransUtil::stat2TableVo) .map(objTransUtil::stat2TableVo)
.filter(vo -> keywordFilter(vo, keyword)) .filter(vo -> keywordFilter(vo, keyword))
.collect(Collectors.toList()); .collect(Collectors.toList());
...@@ -48,6 +302,96 @@ public class ConfirmCheckServiceImpl implements ConfirmCheckService { ...@@ -48,6 +302,96 @@ public class ConfirmCheckServiceImpl implements ConfirmCheckService {
} }
/**
* 更新自动核查的任务周期
*
* @param taskPeriod 要更新成为的周期
*/
@Override
public Integer updateTaskPeriod(TaskPeriod taskPeriod) {
log.info("[核查模块] 更新自动核查任务周期,更新为 {}", taskPeriod.name());
return periodDao.save(new DeviceCheckPeriod(taskPeriod)).getId();
}
/**
* 获得当前自动核查的任务周期
*
* @return 当前的 {@link TaskPeriod}
*/
@Override
public DeviceCheckPeriod getCurrentTaskPeriod() {
return periodDao.findTopByOrderByIdDesc();
}
/**
* 获得下一次计划任务的执行时间
*
* @return 下次计划任务的执行时间
*/
@Override
public LocalDate getNextTaskDate() {
// 获得当前的period
TaskPeriod period = periodDao.findTopByOrderByIdDesc().getCronExpression();
LocalDate now = LocalDate.now();
switch (period) {
case yearly:
return now.plusYears(1L).withDayOfYear(1);
case monthly:
return now.plusMonths(1L).withDayOfMonth(1);
case quarterly:
// 3 - 当前月对3的余数 即为要添加的月份数 例如 8 + (3 - 8%3) = 9
int plusMonth = 3 - now.getMonthValue() % 3;
return now.plusMonths(plusMonth).withDayOfMonth(1);
default:
throw new ApiException("获取当前计划任务时间出错!");
}
}
/**
* 开启自动核查计划任务
*
* @return 任务是否开启成功
*/
@Override
public boolean startAutoCheckCron() {
boolean flag = false;
//从数据库动态获取执行周期
TaskPeriod period = getCurrentTaskPeriod().getCronExpression();
String cron = period.getCron();
future = threadPoolTaskScheduler.schedule(this::autoCheck, new CronTrigger(cron));
if (future != null) {
flag = true;
LocalDate nextTaskDate = getNextTaskDate();
log.info("[核查模块] 自动核查计划任务开启成功!周期为 {},下一次执行时间为 {}", period.name(), nextTaskDate);
} else {
log.error("[核查模块] 自动核查计划任务开启失败...");
}
return flag;
}
/**
* 关闭自动核查计划任务
*
* @return 任务是否关闭成功
*/
@Override
public boolean stopAutoCheckCron() {
boolean flag = false;
if (future != null) {
boolean cancel = future.cancel(true);
if (cancel) {
flag = true;
log.info("[核查模块] 自动核查计划任务停止成功!");
} else {
log.error("[核查模块] 自动核查计划任务停止失败!");
}
} else {
flag = true;
log.info("[核查模块] 自动核查计划任务已经停止了..");
}
return flag;
}
/** /**
* 关键字过滤器 * 关键字过滤器
* *
...@@ -62,4 +406,17 @@ public class ConfirmCheckServiceImpl implements ConfirmCheckService { ...@@ -62,4 +406,17 @@ public class ConfirmCheckServiceImpl implements ConfirmCheckService {
return vo.getQueryField().contains(keyword); return vo.getQueryField().contains(keyword);
} }
} }
private String addNode(String originalNode, Integer fatherId) {
return originalNode + fatherId + ".";
}
/**
* 项目开启时启动
*/
@Override
public void run(String... args) throws Exception {
//开启计划任务
startAutoCheckCron();
}
} }
package com.tykj.dev.misc.base;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Where;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
/**
* BaseEntityNoDelete.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2020/10/26 at 5:05 下午
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseEntityNoDelete {
/**
* 主键id
*/
@Id
@GeneratedValue
private Integer id;
/**
* 创建用户id
*/
@CreatedBy
private Integer createUserId;
/**
* 更新用户id
*/
@LastModifiedBy
private Integer updateUserId;
/**
* 创建时间
*/
@CreatedDate
private LocalDateTime createTime;
/**
* 更新时间
*/
@LastModifiedDate
private LocalDateTime updateTime;
}
...@@ -10,7 +10,7 @@ import com.tykj.dev.device.allot.subject.domin.AllotBill; ...@@ -10,7 +10,7 @@ import com.tykj.dev.device.allot.subject.domin.AllotBill;
import com.tykj.dev.device.apply.service.DeviceApplyBillService; import com.tykj.dev.device.apply.service.DeviceApplyBillService;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckBillDao; import com.tykj.dev.device.confirmcheck.repository.DeviceCheckBillDao;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckDetailDao; import com.tykj.dev.device.confirmcheck.repository.DeviceCheckDetailDao;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckStatRepo; import com.tykj.dev.device.confirmcheck.repository.DeviceCheckStatDao;
import com.tykj.dev.device.destroy.entity.domain.DeviceDestroyBill; import com.tykj.dev.device.destroy.entity.domain.DeviceDestroyBill;
import com.tykj.dev.device.destroy.service.DeviceDestroyBillService; import com.tykj.dev.device.destroy.service.DeviceDestroyBillService;
import com.tykj.dev.device.library.subject.vo.FileVo; import com.tykj.dev.device.library.subject.vo.FileVo;
...@@ -328,9 +328,9 @@ public class LogAspect { ...@@ -328,9 +328,9 @@ public class LogAspect {
} }
break; break;
case 7: case 7:
DeviceCheckStatRepo deviceCheckStatRepo = SpringUtils.getBean("deviceCheckStatRepo"); DeviceCheckStatDao deviceCheckStatDao = SpringUtils.getBean("deviceCheckStatRepo");
if (deviceCheckStatRepo != null) { if (deviceCheckStatDao != null) {
getFieldsParam(deviceCheckStatRepo.getOne(outPutTask.getBillId())); getFieldsParam(deviceCheckStatDao.getOne(outPutTask.getBillId()));
} }
break; break;
case 8: case 8:
......
...@@ -10,7 +10,7 @@ import com.tykj.dev.device.confirmcheck.entity.vo.CheckDetailVo; ...@@ -10,7 +10,7 @@ import com.tykj.dev.device.confirmcheck.entity.vo.CheckDetailVo;
import com.tykj.dev.device.confirmcheck.entity.vo.CheckStatVo; import com.tykj.dev.device.confirmcheck.entity.vo.CheckStatVo;
import com.tykj.dev.device.confirmcheck.entity.vo.DevLibVo; import com.tykj.dev.device.confirmcheck.entity.vo.DevLibVo;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckDetailDao; import com.tykj.dev.device.confirmcheck.repository.DeviceCheckDetailDao;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckStatRepo; import com.tykj.dev.device.confirmcheck.repository.DeviceCheckStatDao;
import com.tykj.dev.device.confirmcheck.utils.ObjTransUtil; import com.tykj.dev.device.confirmcheck.utils.ObjTransUtil;
import com.tykj.dev.device.library.repository.DeviceLibraryDao; import com.tykj.dev.device.library.repository.DeviceLibraryDao;
import com.tykj.dev.device.task.repository.TaskDao; import com.tykj.dev.device.task.repository.TaskDao;
...@@ -64,7 +64,7 @@ class DeviceCheckControllerTest extends BaseTest { ...@@ -64,7 +64,7 @@ class DeviceCheckControllerTest extends BaseTest {
@Autowired @Autowired
private DeviceCheckDetailDao detailRepo; private DeviceCheckDetailDao detailRepo;
@Autowired @Autowired
private DeviceCheckStatRepo statRepo; private DeviceCheckStatDao statRepo;
@Autowired @Autowired
private DeviceLibraryDao deviceRepo; private DeviceLibraryDao deviceRepo;
@Autowired @Autowired
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论