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

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

上级 515efe4d
......@@ -22,7 +22,7 @@ public enum CheckType {
*/
MANUAL_CHECK(2, "手动核查");
private Integer id;
private String name;
private final Integer id;
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;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.tykj.dev.config.GlobalMap;
import com.tykj.dev.config.swagger.AutoDocument;
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.DeviceCheckBill;
import com.tykj.dev.device.confirmcheck.entity.domain.DeviceCheckDetail;
......@@ -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.repository.DeviceCheckBillDao;
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.utils.ObjTransUtil;
import com.tykj.dev.device.library.repository.DeviceLibraryDao;
......@@ -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.StatusEnum;
import com.tykj.dev.misc.utils.JacksonUtil;
import com.tykj.dev.misc.utils.MapperUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
......@@ -43,10 +42,9 @@ import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
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_STAT;
......@@ -66,7 +64,7 @@ import static java.util.stream.Collectors.*;
public class DeviceCheckController {
@Autowired
private DeviceCheckStatRepo statRepo;
private DeviceCheckStatDao statRepo;
@Autowired
private DeviceCheckBillDao billRepo;
@Autowired
......@@ -128,184 +126,40 @@ public class DeviceCheckController {
return ResponseEntity.ok(new ResultObj<>(detailVoList));
}
@ApiOperation(value = "发起自动核查", notes = "发起自动核查")
@PostMapping("/auto")
public ResultObj<Map<String, List<Integer>>> startAutoCheck() {
// 构建返回数据对象
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 = 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;
});
/**
* @param periodId 1-月度 2-季度 3-年度
* @return
*/
@ApiOperation(value = "更新自动核查周期", notes = "更新自动核查周期")
@PutMapping("/task/{period}")
public ResponseEntity updateTaskPeriod(@PathVariable Integer periodId) {
if (periodId < 1 || periodId > 3) {
return ResponseEntity.status(400).body(new ResultObj<>("提供了错误的周期参数!应该是 1/2/3 , 您提供的是" + periodId));
}
//将市级Map里的数据全部取出来展平一层并累加
List<CheckDeviceStatVo> filterVoList = new ArrayList<>(map.values());
provStat.setStatInfo(JacksonUtil.toJSon(filterVoList));
statRepo.save(provStat);
TaskPeriod period = TaskPeriod.values()[periodId - 1];
// 更新最新的周期
ccService.updateTaskPeriod(period);
// 结束当前任务,开启下轮任务
ccService.stopAutoCheckCron();
boolean startSuccess = ccService.startAutoCheckCron();
// 对于市统计来说,只需要自己本市以及其下地区的数据
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));
if (startSuccess) {
String nextTime = ccService.getNextTaskDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
return ResponseEntity.ok(new ResultObj<>(String.format("更新自动核查周期成功,下一次任务的执行时间为%s %n", nextTime)));
} else {
return ResponseEntity.status(400).body("自动核查更新周期失败了!");
}
}
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, "自动核查任务发起成功");
}
/**
* 手动发起核查
* <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;
* @author Matrix <xhyrzldf@gmail.com>
* @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;
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 org.springframework.data.domain.Page;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
/**
* CheckStatService.
*
......@@ -15,9 +21,52 @@ public interface ConfirmCheckService {
* 根据关键字查询报告列表
*
* @param keyword 要查询的字
* @param page 页码
* @param size 每页数据量
* @param page 页码
* @param size 每页数据量
* @return {@link CheckStatTableVo} 's List
*/
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;
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.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.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.jetbrains.annotations.NotNull;
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.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
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_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.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2020/10/13 at 4:07 下午
*/
@Slf4j
@Service
public class ConfirmCheckServiceImpl implements ConfirmCheckService {
public class ConfirmCheckServiceImpl implements ConfirmCheckService, CommandLineRunner {
@Autowired
private DeviceCheckStatRepo statRepo;
private DeviceCheckStatDao statDao;
@Autowired
private DeviceCheckPeriodDao periodDao;
@Autowired
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 {
*/
@Override
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)
.filter(vo -> keywordFilter(vo, keyword))
.collect(Collectors.toList());
......@@ -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 {
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;
import com.tykj.dev.device.apply.service.DeviceApplyBillService;
import com.tykj.dev.device.confirmcheck.repository.DeviceCheckBillDao;
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.service.DeviceDestroyBillService;
import com.tykj.dev.device.library.subject.vo.FileVo;
......@@ -328,9 +328,9 @@ public class LogAspect {
}
break;
case 7:
DeviceCheckStatRepo deviceCheckStatRepo = SpringUtils.getBean("deviceCheckStatRepo");
if (deviceCheckStatRepo != null) {
getFieldsParam(deviceCheckStatRepo.getOne(outPutTask.getBillId()));
DeviceCheckStatDao deviceCheckStatDao = SpringUtils.getBean("deviceCheckStatRepo");
if (deviceCheckStatDao != null) {
getFieldsParam(deviceCheckStatDao.getOne(outPutTask.getBillId()));
}
break;
case 8:
......
......@@ -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.DevLibVo;
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.library.repository.DeviceLibraryDao;
import com.tykj.dev.device.task.repository.TaskDao;
......@@ -64,7 +64,7 @@ class DeviceCheckControllerTest extends BaseTest {
@Autowired
private DeviceCheckDetailDao detailRepo;
@Autowired
private DeviceCheckStatRepo statRepo;
private DeviceCheckStatDao statRepo;
@Autowired
private DeviceLibraryDao deviceRepo;
@Autowired
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论