From 8383232e5cf8de66b31b484dd08df1c5406d6498 Mon Sep 17 00:00:00 2001 From: huxin02 Date: Fri, 7 Mar 2025 17:29:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=A4=A7=E5=B1=8F=E3=80=81?= =?UTF-8?q?=E6=A1=88=E4=BB=B6=E4=BF=A1=E6=81=AF=E3=80=81=E6=89=A7=E6=B3=95?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E3=80=81=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E7=AD=89=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/BigScreenService.java | 764 ++++++++++++++++ .../lawenforcement/service/CaseService.java | 840 ++++++++++++++++++ .../service/CheckItemService.java | 148 +++ .../service/ChecklistService.java | 139 +++ .../service/DataSyncService.java | 155 ++++ 5 files changed, 2046 insertions(+) create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/service/BigScreenService.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/service/CaseService.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/service/CheckItemService.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/service/ChecklistService.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/service/DataSyncService.java diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/BigScreenService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/BigScreenService.java new file mode 100644 index 0000000..0517c39 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/BigScreenService.java @@ -0,0 +1,764 @@ +package com.aisino.iles.lawenforcement.service; + +import com.aisino.iles.common.util.PageableHelper; +import com.aisino.iles.lawenforcement.model.*; +import com.aisino.iles.lawenforcement.model.dto.BigScreenDto; +import com.aisino.iles.lawenforcement.model.query.CaseQuery; +import com.aisino.iles.lawenforcement.model.query.EnforceCheckQuery; +import com.aisino.iles.lawenforcement.model.query.EnforcementInfoQuery; +import com.aisino.iles.lawenforcement.model.query.OfficerQuery; +import com.aisino.iles.lawenforcement.repository.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.smartlx.sso.client.model.RemoteUserInfo; +import jakarta.persistence.criteria.Predicate; +import lombok.Data; +import org.springframework.data.domain.Page; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * 执法一张图 + */ +@Service +public class BigScreenService { + + private final BigScreenRepository bigScreenRepository; + private final OnlinePatrolRepository onlinePatrolRepository; + private final EnterpriseRepository enterpriseRepository; + private final EnforcementInfoRepository enforcementInfoRepository; + private final EnforcementInfoService enforcementInfoService; + private final EnforceCheckRepository enforceCheckRepository; + private final OfficerRepository officerRepository; + private final CaseRepository caseRepository; + private final AutoEnforcementPlanRepository autoEnforcementPlanRepository; + private final SupervisionCheckRepository supervisionCheckRepository; + private final ReportCheckOperRepository reportCheckOperRepository; + + public BigScreenService(BigScreenRepository bigScreenRepository, + OnlinePatrolRepository onlinePatrolRepository, + EnterpriseRepository enterpriseRepository, + EnforcementInfoRepository enforcementInfoRepository, + EnforcementInfoService enforcementInfoService, + EnforceCheckRepository enforceCheckRepository, + OfficerRepository officerRepository, + CaseRepository caseRepository, + AutoEnforcementPlanRepository autoEnforcementPlanRepository, + SupervisionCheckRepository supervisionCheckRepository, + ReportCheckOperRepository reportCheckOperRepository) { + this.bigScreenRepository = bigScreenRepository; + this.onlinePatrolRepository = onlinePatrolRepository; + this.enterpriseRepository = enterpriseRepository; + this.enforcementInfoRepository = enforcementInfoRepository; + this.enforcementInfoService = enforcementInfoService; + this.enforceCheckRepository = enforceCheckRepository; + this.officerRepository = officerRepository; + this.caseRepository = caseRepository; + this.autoEnforcementPlanRepository = autoEnforcementPlanRepository; + this.supervisionCheckRepository = supervisionCheckRepository; + this.reportCheckOperRepository = reportCheckOperRepository; + } + + + public Map getDataOverview() { +// Long qys = bigScreenRepository.getqys(); +// Long ajs = bigScreenRepository.getajs(); + Map res = new HashMap<>(); +// res.put("qys", qys); +// res.put("ajs", ajs); + return res; + } + + public Map getEnterpriseStatistics(RemoteUserInfo user) { + String agencyCode = com.aisino.iles.common.util.StringUtils.trimEven0(user.getGajgjgdm()) + "%"; + Map res = new HashMap<>(); + Long qys = bigScreenRepository.getqys(agencyCode); + res.put("qys", qys); + res.put("A", 0L); + res.put("B", 0L); + res.put("C", 0L); + res.put("D", 0L); + List> list = bigScreenRepository.getqyfjfl(agencyCode); + // 1 A 2 B 3 C 4 D + list.stream().forEach(map -> { + Object categoryObj = map.get("business_category"); + Object numObj = map.get("num"); + if (categoryObj != null && numObj != null) { + try { + int category = Integer.parseInt(categoryObj.toString()); + long num = Long.parseLong(numObj.toString()); + String categoryLetter = switch (category) { + case 1 -> "A"; + case 2 -> "B"; + case 3 -> "C"; + case 4 -> "D"; + default -> " "; + }; + if (categoryLetter.matches("[A-D]")) { + res.put(categoryLetter, res.get(categoryLetter) + num); + } + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + }); + return res; + } + + public Map getEnterpriseStatistics2(RemoteUserInfo user) { + String agencyCode = com.aisino.iles.common.util.StringUtils.trimEven0(user.getGajgjgdm()) + "%"; + Long qys = bigScreenRepository.getqys(agencyCode); + List> list = bigScreenRepository.getqyfjfl2(agencyCode); + Map res = new HashMap<>(); + res.put("qys", qys); + res.put("wh", 0L); + res.put("gy", 0L); + res.put("sm", 0L); + res.put("jy", 0L); + res.put("ks", 0L); + res.put("qt", 0L); + list.stream().forEach(map -> { + Object categoryObj = map.get("industry_type"); + Object numObj = map.get("num"); + if (categoryObj != null && numObj != null) { + try { + int category = Integer.parseInt(categoryObj.toString()); + long num = Long.parseLong(numObj.toString()); + switch (category) { + case 1: // 矿山 + res.put("ks", res.get("ks") + num); + break; + case 2: // 危险化学品生产 + case 3: // 危险化学品经营(仓储) + case 4: // 危险化学品经营(无仓储) + res.put("wh", res.get("wh") + num); + break; + case 5: // 加油站 + res.put("jy", res.get("jy") + num); + break; + case 6: // 工业企业 + res.put("gy", res.get("gy") + num); + break; + case 7: // 商贸企业 + res.put("sm", res.get("sm") + num); + break; + case 99: // 其他 + res.put("qt", res.get("qt") + num); + break; + } + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + }); + return res; + } + + public List> getZfjcs(BigScreenDto bigScreenDto) { + LocalDateTime startTime; + LocalDateTime endTime = LocalDateTime.now(); + if ("1".equals(bigScreenDto.getTimeType())) { + startTime = endTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + } else { + startTime = LocalDateTime.of(endTime.getYear(), Month.JANUARY, 1, 0, 0); + } + List> res = bigScreenRepository.getzfjcs(startTime, endTime); + return res; + } + + public Map getAjbl() { + Long ajzs = bigScreenRepository.getajzs(); + Long ajcfs = bigScreenRepository.getajcfs(); + Map res = new HashMap<>(); + res.put("ajzs", ajzs); + res.put("ajcfs", ajcfs); + return res; + } + + public List> getZfxs() { +// {value: '1', label: '日常检查'}, +// {value: '2', label: '专项检查'}, +// {value: '3', label: '举报核查'}, +// {value: '4', label: '随机抽查'}, + List list = new ArrayList<>(); + list.add("1"); + list.add("2"); + list.add("3"); + list.add("4"); + List> data = bigScreenRepository.getzfxs(); + List> res = list.stream() + .map(item -> data.stream() + .filter(map -> map.get("check_type") != null) + .filter(map -> item.equals(map.get("check_type").toString())) + .findFirst() + .orElseGet(() -> { + Map defaultMap = new HashMap<>(); + defaultMap.put("check_type", item); + defaultMap.put("num", 0); + return defaultMap; + })) + .collect(Collectors.toList()); + return res; + } + + public List> getZfxs2() { + List> data = bigScreenRepository.getzdzfs(); + Long zxjcs = bigScreenRepository.getzxjcs(); + Long tsjbs = bigScreenRepository.gettsjbs(); + List checkTypes = Arrays.asList("1", "2"); + List> res = checkTypes.stream() + .map(checkType -> data.stream() + .filter(map -> checkType.equals(String.valueOf(map.get("check_type")))) + .findFirst() + .orElseGet(() -> { + Map defaultMap = new HashMap<>(); + defaultMap.put("check_type", checkType); + defaultMap.put("num", 0); + return defaultMap; + }) + ) + .collect(Collectors.toList()); + Map zxjcsEntry = new HashMap<>(); + zxjcsEntry.put("check_type", "3"); + zxjcsEntry.put("num", zxjcs); + res.add(zxjcsEntry); + Map tsjbsEntry = new HashMap<>(); + tsjbsEntry.put("check_type", "4"); + tsjbsEntry.put("num", tsjbs); + res.add(tsjbsEntry); + return res; + } + + public List> getAjly(RemoteUserInfo user) { +// {value: '1', label: '日常检查发现'}, 检查发现 +// {value: '2', label: '机构监测报告'}, 行业部分移送 +// {value: '3', label: '举报投诉'}, 举报核查 +// {value: '4', label: '上级交办'}, 上级交办 +// {value: '5', label: '下级情报'}, 下级报请 +// {value: '6', label: '有关部门移送'}, 处室移送 +// {value: '7', label: '其他'}, 其他 + String agencyCode = com.aisino.iles.common.util.StringUtils.trimEven0(user.getGajgjgdm()) + "%"; + List list = new ArrayList<>(); + list.add("1"); + list.add("2"); + list.add("3"); + list.add("4"); + list.add("5"); + list.add("6"); + list.add("7"); + List> data = bigScreenRepository.getajly(agencyCode); + List> res = list.stream() + .map(item -> data.stream() + .filter(map -> map.get("case_source_code") != null) + .filter(map -> item.equals(map.get("case_source_code").toString())) + .findFirst() + .orElseGet(() -> { + Map defaultMap = new HashMap<>(); + defaultMap.put("case_source_code", item); + defaultMap.put("num", 0); + return defaultMap; + })) + .collect(Collectors.toList()); + return res; + } + + public List> getJcajqs(BigScreenDto bigScreenDto) { + LocalDateTime startTime; + LocalDateTime endTime = LocalDateTime.now(); + if ("1".equals(bigScreenDto.getTimeType())) { + LocalDate currentDate = LocalDate.now(); + YearMonth yearMonth = YearMonth.from(currentDate).minusMonths(11); + startTime = LocalDateTime.of(yearMonth.getYear(), yearMonth.getMonthValue(), 1, 0, 0); + List months = IntStream.range(0, 12) + .mapToObj(i -> endTime.minusMonths(i)) + .sorted() // 按日期升序排序 + .map(date -> date.format(DateTimeFormatter.ofPattern("yyyy-MM"))) + .collect(Collectors.toList()); + List> jfjc = bigScreenRepository.getjfjcByMonth(startTime, endTime); + List> sasl = bigScreenRepository.getsaslByMonth(startTime.toLocalDate(), endTime.toLocalDate()); + // 处理数据 + List> res = months.stream() + .map(month -> { + Map jfjcMap = jfjc.stream().filter(data -> month.equals(data.get("createTime"))).findFirst().orElse(null); + Map saslMap = sasl.stream().filter(data -> month.equals(data.get("fillingDate"))).findFirst().orElse(null); + Map resultMap = new java.util.HashMap<>(); + resultMap.put("date", month); + resultMap.put("jfjc", jfjcMap != null ? jfjcMap.get("num") : 0); // 默认值设为0 + resultMap.put("sasl", saslMap != null ? saslMap.get("num") : 0); // 默认值设为0 + return resultMap; + }) + .collect(Collectors.toList()); + return res; + } else { + LocalDate currentDate = LocalDate.now(); + YearMonth yearMonth = YearMonth.from(currentDate).minusYears(4); + startTime = LocalDateTime.of(yearMonth.getYear(), 1, 1, 0, 0); + List years = IntStream.range(0, 5) + .mapToObj(i -> endTime.minusYears(i)) + .sorted() // 按日期升序排序 + .map(date -> date.format(DateTimeFormatter.ofPattern("yyyy"))) + .collect(Collectors.toList()); + List> jfjc = bigScreenRepository.getjfjcByYear(startTime, endTime); + List> sasl = bigScreenRepository.getsaslByYear(startTime.toLocalDate(), endTime.toLocalDate()); + // 处理数据 + List> res = years.stream() + .map(year -> { + Map jfjcMap = jfjc.stream().filter(data -> year.equals(data.get("createTime"))).findFirst().orElse(null); + Map saslMap = sasl.stream().filter(data -> year.equals(data.get("fillingDate"))).findFirst().orElse(null); + Map resultMap = new java.util.HashMap<>(); + resultMap.put("date", year); + resultMap.put("jfjc", jfjcMap != null ? jfjcMap.get("num") : 0); // 默认值设为0 + resultMap.put("sasl", saslMap != null ? saslMap.get("num") : 0); // 默认值设为0 + return resultMap; + }) + .collect(Collectors.toList()); + return res; + } + } + + public List> getJctj(BigScreenDto bigScreenDto) { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = LocalDateTime.of(endTime.getYear(), Month.JANUARY, 1, 0, 0); + List> res = bigScreenRepository.getjctj(startTime, endTime); + return res; + } + + public List> getAjtj(BigScreenDto bigScreenDto) { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = LocalDateTime.of(endTime.getYear(), Month.JANUARY, 1, 0, 0); + List> res = bigScreenRepository.getajtj(startTime, endTime); + return res; + } + + public List> getCfjetj(BigScreenDto bigScreenDto) { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = LocalDateTime.of(endTime.getYear(), Month.JANUARY, 1, 0, 0); + List> res = bigScreenRepository.getcfjetj(startTime, endTime); + return res; + } + + public List> getRwwj(BigScreenDto bigScreenDto) { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = LocalDateTime.of(endTime.getYear(), Month.JANUARY, 1, 0, 0); + List> res = bigScreenRepository.getrwwj(startTime, endTime); + return res; + } + + public List> getFxczftj(String type) { + LocalDate currentDate = LocalDate.now(); + if ("1".equals(type)) { + // 按月统计(最近12个月) + LocalDateTime startTime = currentDate.minusMonths(11).atStartOfDay(); + LocalDateTime endTime = LocalDateTime.now(); + List months = IntStream.rangeClosed(0, 11) + .mapToObj(i -> YearMonth.now().minusMonths(i).format(DateTimeFormatter.ofPattern("yyyy-MM"))) + .sorted() + .collect(Collectors.toList()); + List> fxczf = Optional.ofNullable( + onlinePatrolRepository.getfxczfByMonth(startTime, endTime) + ).orElse(Collections.emptyList()); + Map> fxczfMap = fxczf.stream() + .collect(Collectors.toMap( + data -> (String) data.get("createTime"), + data -> data, + (existing, replacement) -> existing + )); + return months.stream() + .map(month -> { + Map data = fxczfMap.getOrDefault(month, Collections.emptyMap()); + Map resultMap = new HashMap<>(); + resultMap.put("date", month); + resultMap.put("zxxcs", data.getOrDefault("zxxcs", 0)); + resultMap.put("wfwgs", data.getOrDefault("wfwgs", 0)); + return resultMap; + }) + .collect(Collectors.toList()); + } else if ("2".equals(type)) { + // 按年统计(最近6年) + int startYear = currentDate.getYear() - 6; + LocalDateTime startTime = LocalDateTime.of(startYear, 1, 1, 0, 0); + LocalDateTime endTime = LocalDateTime.now(); + List years = IntStream.rangeClosed(startYear, currentDate.getYear()) + .boxed() + .collect(Collectors.toList()); + List> fxczf = Optional.ofNullable( + onlinePatrolRepository.getfxczfByYear(startTime, endTime) + ).orElse(Collections.emptyList()); + Map> fxczfMap = fxczf.stream() + .collect(Collectors.toMap( + data -> (String) data.get("createTime"), + data -> data, + (existing, replacement) -> existing + )); + return years.stream() + .map(year -> { + String yearStr = String.valueOf(year); + Map data = fxczfMap.getOrDefault(yearStr, Collections.emptyMap()); + Map resultMap = new HashMap<>(); + resultMap.put("date", yearStr); + resultMap.put("zxxcs", data.getOrDefault("zxxcs", 0)); + resultMap.put("wfwgs", data.getOrDefault("wfwgs", 0)); + return resultMap; + }) + .collect(Collectors.toList()); + } + return Collections.emptyList(); // 默认返回空列表 + } + + public List> getJdjcjhtj() { + List> res = bigScreenRepository.getjdjcjh(); + return res; + } + + public List findEnterprisesByBusinessRating(String businessRating) { + List list = enterpriseRepository.findAll(buildSpecification(businessRating)); + return list; + } + + /** + * 构建查询条件 + * + * @param businessRating 查询条件 + * @return 规格 + */ + private Specification buildSpecification(String businessRating) { + return (root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + root.join(Enterprise_.agency); + if (StringUtils.hasText(businessRating)) { + predicates.add(root.get(Enterprise_.businessRating).in(Arrays.asList(businessRating))); + } + predicates.add(root.get(Enterprise_.longitude).isNotNull()); + predicates.add(root.get(Enterprise_.latitude).isNotNull()); + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } + + public List findEnforcementInfoByEnterpriseId(String enterpriseId) { + List list = new ArrayList<>(); + enforcementInfoRepository + .findByEnterpriseIdAndCreateTimeBetween(enterpriseId, LocalDateTime.now().minusYears(1), LocalDateTime.now()) + .stream() + .forEach(item -> enforcementInfoService.findEnforcementInfoById(item.getEnforcementId()).ifPresent(enforcementInfo -> list.add(enforcementInfo))); + return list; + } + + public Long getZfdxsl() { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = endTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + return bigScreenRepository.getZfdxsl(startTime, endTime); + } + + public Page getZfdxslfy(EnforcementInfoQuery query) { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = endTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + return enforcementInfoRepository.findAll(buildSpec(startTime, startTime), PageableHelper.buildPageRequest(query.page(), query.pageSize(), query.sort(), query.dir())); + } + + /** + * 构建查询条件 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return + */ + private Specification buildSpec(LocalDateTime startTime, LocalDateTime endTime) { + return (root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(EnforcementInfo_.createTime), startTime)); + predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get(EnforcementInfo_.createTime), endTime)); + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } + + public Long getZfrysl() { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = endTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + List list = enforceCheckRepository.getZfrysl(startTime, endTime); + long num = list.parallelStream() + .filter(Objects::nonNull) + .flatMap(item -> Arrays.stream(item.split(","))) + .map(String::trim) + .filter(part -> !part.isEmpty()) + .distinct() + .count(); + return num; + } + + public Page getZfryslfy(OfficerQuery query) { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = endTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + List list = enforceCheckRepository.getZfrysl(startTime, endTime); + List ids = list.parallelStream() + .filter(Objects::nonNull) + .flatMap(item -> Arrays.stream(item.split(","))) + .map(String::trim) + .filter(part -> !part.isEmpty()) + .distinct() + .collect(Collectors.toList()); + return officerRepository.findAll(buildSpec2(ids), PageableHelper.buildPageRequest(query.page(), query.pageSize(), query.sort(), query.dir())); + } + + private Specification buildSpec2(List ids) { + return Specification.where((root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + predicates.add(root.get(Officer_.officerId).in(ids)); + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }); + } + + /** + * 获取检查数量 + * + * @return 检查数量 + */ + public Long checkCount() { + LocalDate endTime = LocalDate.now(); + LocalDate startTime = endTime.withDayOfMonth(1); + return enforceCheckRepository.countByCheckDateBetween(startTime, endTime); + } + + @Transactional(readOnly = true) + public Page getzfjcslDetail(EnforceCheckQuery query) { + LocalDate endTime = LocalDate.now(); + LocalDate startTime = endTime.withDayOfMonth(1); + query.setCheckDate(new LocalDate[]{startTime, endTime}); + return enforceCheckRepository.findAll(buildCondiction(query), PageableHelper.buildPageRequest(query.page(), query.pageSize(), query.sort(), query.dir())).map(enforceCheck -> { + ZfjcDto zfjcDto = new ZfjcDto(); + AtomicReference officerName = new AtomicReference<>(""); + zfjcDto.setCheckDate(enforceCheck.getCheckDate()); + zfjcDto.setAgencyName(enforceCheck.getEnforcementInfo().getAgency().getAgencyName()); + zfjcDto.setUnitName(enforceCheck.getEnforcementInfo().getEnterprise().getUnitName()); + zfjcDto.setUnifiedSocialCode(enforceCheck.getEnforcementInfo().getEnterprise().getUnifiedSocialCode()); + Arrays.stream(enforceCheck.getOfficerIds().split(",")).forEach(id -> officerRepository.findById(id).ifPresent(officer -> officerName.set(officerName.get() + officer + ","))); + zfjcDto.setOfficers(officerName.get()); + return zfjcDto; + }); + } + + private Specification buildCondiction(EnforceCheckQuery query) { + return Specification.where((root, q, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + Optional.ofNullable(query.getCheckDate()).filter(f -> f.length == 2).map(f -> { + List timePredicates = new ArrayList<>(); + Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get(EnforceCheck_.checkDate), from)).ifPresent(timePredicates::add); + Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get(EnforceCheck_.checkDate), to)).ifPresent(timePredicates::add); + return timePredicates; + }).ifPresent(predicates::addAll); + + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }); + } + + /** + * 查询当月事故单位报告、公众举报、下级部门报告、媒体舆情监测、其他部分移送数量 + * + * @return 统计结果 + */ + public DytjDto dytjs() { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = endTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + List dtos = bigScreenRepository.getajly(startTime, endTime); + DytjDto stats = new DytjDto(); + dtos.stream().filter(dto -> "1".equals(dto.getCode())).findFirst().ifPresentOrElse(dto -> stats.setRcjdfxs(dto.getNum()), () -> stats.setRcjdfxs(0L)); + dtos.stream().filter(dto -> "2".equals(dto.getCode())).findFirst().ifPresentOrElse(dto -> stats.setJgjcbgs(dto.getNum()), () -> stats.setJgjcbgs(0L)); + dtos.stream().filter(dto -> "3".equals(dto.getCode())).findFirst().ifPresentOrElse(dto -> stats.setJbtss(dto.getNum()), () -> stats.setJbtss(0L)); + dtos.stream().filter(dto -> "4".equals(dto.getCode())).findFirst().ifPresentOrElse(dto -> stats.setSjjbs(dto.getNum()), () -> stats.setSjjbs(0L)); + dtos.stream().filter(dto -> "5".equals(dto.getCode())).findFirst().ifPresentOrElse(dto -> stats.setXjqbs(dto.getNum()), () -> stats.setXjqbs(0L)); + dtos.stream().filter(dto -> "6".equals(dto.getCode())).findFirst().ifPresentOrElse(dto -> stats.setYgbmyss(dto.getNum()), () -> stats.setYgbmyss(0L)); + dtos.stream().filter(dto -> "7".equals(dto.getCode())).findFirst().ifPresentOrElse(dto -> stats.setQts(dto.getNum()), () -> stats.setQts(0L)); + return stats; + } + + @Transactional(readOnly = true) + public Page getdytjDetail(CaseQuery query) { + LocalDateTime endTime = LocalDateTime.now(); + LocalDateTime startTime = endTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0); + query.setSupplementVerifyTime(new LocalDateTime[]{startTime, endTime}); + return caseRepository.findAll(buildQuery(query), PageableHelper.buildPageRequest(query.page(), query.pageSize(), query.sort(), query.dir())).map(c -> { + DytjsDto dto = new DytjsDto(); + dto.setAgencyName(c.getEnforcementInfo().getAgency().getAgencyName()); + dto.setUnitName(c.getEnforcementInfo().getEnterprise().getUnitName()); + dto.setUnifiedSocialCode(c.getEnforcementInfo().getEnterprise().getUnifiedSocialCode()); + dto.setCreatedTime(c.getCreatedTime()); + return dto; + }); + } + + private Specification buildQuery(CaseQuery query) { + return Specification.where((root, q, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + Optional.ofNullable(query.getConditionlike()).ifPresent(o -> predicates.add(criteriaBuilder.equal(root.get(Case_.caseSourceCode), o))); + Optional.ofNullable(query.getSupplementVerifyTime()).filter(f -> f.length == 2).map(f -> { + List timePredicates = new ArrayList<>(); + Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get(Case_.createdTime), from)).ifPresent(timePredicates::add); + Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get(Case_.createdTime), to)).ifPresent(timePredicates::add); + return timePredicates; + }).ifPresent(predicates::addAll); + + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }); + } + + @Data + public static class DytjDto { + /** + * 日常检查发现 + */ + private Long rcjdfxs; + /** + * 机构监测报告 + */ + private Long jgjcbgs; + /** + * 举报投诉 + */ + private Long jbtss; + /** + * 上级交办 + */ + private Long sjjbs; + /** + * 下级情报 + */ + private Long xjqbs; + /** + * 有关部门移送 + */ + private Long ygbmyss; + /** + * 其他 + */ + private Long qts; + + } + + @Data + public static class ZfjcDto { + + /** + * 企业名称 + */ + private String unitName; + /** + * 统一社会信用代码 + */ + private String unifiedSocialCode; + /** + * 立案日期 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate checkDate; + + /** + * 机构名称 + */ + private String agencyName; + + + private String officers; + + } + + @Data + public static class DytjsDto { + + /** + * 企业名称 + */ + private String unitName; + /** + * 统一社会信用代码 + */ + private String unifiedSocialCode; + /** + * 录入时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createdTime; + + /** + * 机构名称 + */ + private String agencyName; + + } + + public List> rwwctj() { + List> res = new ArrayList<>(); + // 用数组常量替代HashMap,减少集合初始化开销 + String[][] typeConfigs = { + {"5", "zxjcs", "zxjcwcs", "wcl"}, // 专项检查(督导检查) + {"6", "jbtss", "jbtswcs", "wcl"}, // 投诉举报(交叉互查) + {"7", "zdqyjcs", "zdqyjcwcs", "wcl"}, // 重点企业检查 + {"8", "ssjjcs", "ssjjcwcs", "wcl"} // 双随机检查 + }; + + bigScreenRepository.rwwctj().forEach(originalMap -> { + String checktype = originalMap.get("checktype").toString(); + for (String[] config : typeConfigs) { + if (config[0].equals(checktype)) { + res.add(processMap(originalMap, config[1], config[2], config[3])); + break; + } + } + }); + + return res; + } + + /** + * 处理Map,设置任务名称并计算完成率 + */ + private Map processMap(Map originalMap, String totalKey, String wcsKey, String rateKey) { + Map item = new HashMap<>(); + String checktype = originalMap.get("checktype").toString(); + String planid = originalMap.get("planid").toString(); + String taskName = switch (checktype) { + case "5" -> supervisionCheckRepository.findById(planid) + .map(SupervisionCheck::getCheckType) + .orElse("未知任务"); + case "6" -> reportCheckOperRepository.findById(planid) + .map(ReportCheckOper::getOperType) + .orElse("未知任务"); + case "7", "8" -> autoEnforcementPlanRepository.findById(planid) + .map(AutoEnforcementPlan::getTaskName) + .orElse("未知任务"); + default -> "未知任务"; + }; + item.put("taskName", taskName); + try { + + long total = parseLong(originalMap.get(totalKey)); + long wcs = parseLong(originalMap.get(wcsKey)); + item.put("sum", total); + item.put("wcs", wcs); + item.put(rateKey, total == 0 ? 0 : Math.round((double) wcs / total * 10000) / 100.0); + } catch (Exception e) { + item.put(rateKey, 0); + } + return item; + } + + private long parseLong(Object obj) { + if (obj == null) return 0; + if (obj instanceof Number num) return num.longValue(); + try { + return Long.parseLong(obj.toString().trim()); + } catch (NumberFormatException e) { + return 0; + } + } + +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/CaseService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/CaseService.java new file mode 100644 index 0000000..d1cf909 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/CaseService.java @@ -0,0 +1,840 @@ +package com.aisino.iles.lawenforcement.service; + +import com.aisino.iles.common.model.enums.IndustryCategoryForFile; +import com.aisino.iles.common.service.FtpService; +import com.aisino.iles.common.util.Constants; +import com.aisino.iles.common.util.PageableHelper; +import com.aisino.iles.common.util.PdfMerger; +import com.aisino.iles.core.exception.BusinessError; +import com.aisino.iles.core.service.GenerateCodeService; +import com.aisino.iles.lawenforcement.event.DataChangeAction; +import com.aisino.iles.lawenforcement.event.aop.PublishDataChange; +import com.aisino.iles.lawenforcement.model.*; +import com.aisino.iles.lawenforcement.model.dto.FormDataDto; +import com.aisino.iles.lawenforcement.model.enums.FlowNode; +import com.aisino.iles.lawenforcement.model.query.CaseQuery; +import com.aisino.iles.lawenforcement.repository.AgencyRepository; +import com.aisino.iles.lawenforcement.repository.CaseRepository; +import com.aisino.iles.lawenforcement.repository.DocumentRepository; +import com.aisino.iles.lawenforcement.repository.EnforcementInfoRepository; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.smartlx.sso.client.model.RemoteUserInfo; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Join; +import jakarta.persistence.criteria.JoinType; +import jakarta.persistence.criteria.Predicate; +import lombok.extern.slf4j.Slf4j; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.nio.file.Files; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAdjusters; +import java.util.*; + +import static com.aisino.iles.common.util.PdfMerger.mergePDFsWithPageNumbers; + +@Service +@Slf4j +public class CaseService { + private final CaseRepository caseRepository; + private final EnforcementInfoRepository enforcementInfoRepository; + private final DocumentRepository documentRepository; + private final ObjectMapper objectMapper; + private final FtpService ftpService; + private final GenerateCodeService generateCodeService; + private final EnforceCheckService enforceCheckService; + private final AgencyRepository agencyRepo; + + public CaseService(CaseRepository caseRepository, + EnforcementInfoRepository enforcementInfoRepository, + DocumentRepository documentRepository, + ObjectMapper objectMapper, + FtpService ftpService, + GenerateCodeService generateCodeService, + EnforceCheckService enforceCheckService, AgencyRepository agencyRepo) { + this.caseRepository = caseRepository; + this.enforcementInfoRepository = enforcementInfoRepository; + this.documentRepository = documentRepository; + this.objectMapper = objectMapper; + this.ftpService = ftpService; + this.generateCodeService = generateCodeService; + this.enforceCheckService = enforceCheckService; + this.agencyRepo = agencyRepo; + } + + /** + * 案件信息 + * + * @param query@return 分页案件信息 + */ + @Transactional(readOnly = true) + public Page findCasesPage(CaseQuery query, RemoteUserInfo user) { + if ("zfwsquery".equals(query.getSpecialCondition())) + return caseRepository.findAll(buildSpec(query, user), PageableHelper.buildPageRequest(query.page(), query.pageSize(), "fillingDate", "desc")).map(this::handleResult); + if (query.getStatus() != null && ("filed".equals(query.getStatus().getValue()) || "investigation_done".equals(query.getStatus().getValue()))) + return caseRepository.findAll(buildSpec(query, user), PageableHelper.buildPageRequest(query.page(), query.pageSize(), "fillingDate", "desc")).map(this::getCaseevidenceDetailInfo); + else + return caseRepository.findAll(buildSpec(query, user), PageableHelper.buildPageRequest(query.page(), query.pageSize(), "fillingDate", "desc")).map(this::getCaseDetailInfo); + } + + + private Case handleResult(Case caseInfoDto) { + //文书管理显示完成度 + int process = documentRepository.countByCaseIdAndStatus(caseInfoDto.getCaseId(), Document.DocumentStatus.done); + long persent = Math.round(((double) process / 31 * 100)); + caseInfoDto.setDocumentCount(process); + caseInfoDto.setDocumentProgress(persent); + caseInfoDto.getEnforcementInfo().getAgency().getAgencyName(); + caseInfoDto.getEnforcementInfo().getEnterprise().getUnitName(); + caseInfoDto.setEnterprise(caseInfoDto.getEnforcementInfo().getEnterprise()); + Optional.ofNullable(caseInfoDto.getFilePath()).filter(StringUtils::hasText).ifPresent(o -> caseInfoDto.setDownUrl(ftpService.getFileUrl(o))); + switch (caseInfoDto.getCaseSourceCode()) { + case "1" -> caseInfoDto.setCaseSourceCode("日常检查发现"); + case "2" -> caseInfoDto.setCaseSourceCode("机构监测报告"); + case "3" -> caseInfoDto.setCaseSourceCode("举报投诉"); + case "4" -> caseInfoDto.setCaseSourceCode("上级交办"); + case "5" -> caseInfoDto.setCaseSourceCode("下级情报"); + case "6" -> caseInfoDto.setCaseSourceCode("有关部门移送"); + case "7" -> caseInfoDto.setCaseSourceCode("其他"); + + } + switch (caseInfoDto.getCaseCause()) { + case "1" -> caseInfoDto.setCaseCause("安全生产行政许可类违法"); + case "2" -> caseInfoDto.setCaseCause("安全生产管理机构和管理人员类违法"); + case "3" -> caseInfoDto.setCaseCause("安全生产建设工程项目类违法"); + case "4" -> caseInfoDto.setCaseCause("安全生产规章制度类违法"); + case "5" -> caseInfoDto.setCaseCause("安全生产培训教育类违法"); + case "6" -> caseInfoDto.setCaseCause("安全生产资金投入类违法"); + case "7" -> caseInfoDto.setCaseCause("安全生产隐患管理类违法"); + case "8" -> caseInfoDto.setCaseCause("生产安全事故应急救援类违法"); + case "9" -> caseInfoDto.setCaseCause("安全生产承包租赁类违法"); + case "10" -> caseInfoDto.setCaseCause("安全生产警示标志类违法"); + case "11" -> caseInfoDto.setCaseCause("安全生产中介机构类违法"); + case "12" -> caseInfoDto.setCaseCause("安全设备使用维护类违法"); + case "13" -> caseInfoDto.setCaseCause("重大危险源管理类违法"); + case "14" -> caseInfoDto.setCaseCause("生产经营单位作业现场管理类违法"); + case "15" -> caseInfoDto.setCaseCause("生产安全事故报告类违法"); + case "16" -> caseInfoDto.setCaseCause("生产安全事故责任类违法"); + case "17" -> caseInfoDto.setCaseCause("其他"); + } + return caseInfoDto; + } + + + private Specification buildSpec(CaseQuery query, RemoteUserInfo user) { + return Specification.where((root, q, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + Optional.ofNullable(query.getCaseName()).ifPresent(o -> predicates.add(criteriaBuilder.like(root.get("caseName"), "%" + o + "%"))); + Optional.ofNullable(query.getCaseNum()).ifPresent(o -> predicates.add(criteriaBuilder.equal(root.get("caseNum"), o))); + Optional.ofNullable(query.getArchivalNum()).ifPresent(o -> predicates.add(criteriaBuilder.equal(root.get("archivalNum"), o))); + Optional.ofNullable(query.getCaseStatus()).filter("simp"::equals).ifPresent(o -> { + CriteriaBuilder.In in = criteriaBuilder.in(root.get(Case_.status)); + in.value(Case.CaseStatus.closing); + in.value(Case.CaseStatus.archived); + predicates.add(in); + }); + Join enforcementInfoCaseRoot = root.join("enforcementInfo", JoinType.LEFT); + Optional.ofNullable(query.getStatus()).ifPresent(o -> { + //进入调查取证流程查询 已立案和取证中两种状态 + if (FlowNode.filed.equals(query.getStatus())) { + CriteriaBuilder.In nods = criteriaBuilder.in(enforcementInfoCaseRoot.get(EnforcementInfo_.currentNodeCode)); + nods.value(FlowNode.filed); + nods.value(FlowNode.investigating); + predicates.add(nods); + } else if (FlowNode.reviewing_done.equals(query.getStatus())) { + // 查询立案后的所有状态案件 + CriteriaBuilder.In nods = criteriaBuilder.in(enforcementInfoCaseRoot.get(EnforcementInfo_.currentNodeCode)); + nods.value(FlowNode.filed); + nods.value(FlowNode.investigating); + nods.value(FlowNode.investigation_done); + nods.value(FlowNode.analyze_judge); + nods.value(FlowNode.inform); + nods.value(FlowNode.hearing); + nods.value(FlowNode.decided); + nods.value(FlowNode.execute); + nods.value(FlowNode.done); + predicates.add(nods); + } else { + predicates.add(criteriaBuilder.equal((enforcementInfoCaseRoot.get(EnforcementInfo_.currentNodeCode)), o)); + } +// else if (FlowNode.execute.equals(query.getStatus())) { // 到结案时查询执行及完成节点的信息 +// CriteriaBuilder.In nods = criteriaBuilder.in(enforcementInfoCaseRoot.get(EnforcementInfo_.currentNodeCode)); +// nods.value(FlowNode.execute); +// nods.value(FlowNode.done); +// predicates.add(nods); +// } + }); + Optional.ofNullable(query.getFillingDate()).filter(f -> f.length == 2).map(f -> { + List timePredicates = new ArrayList<>(); + Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get("fillingDate"), from)).ifPresent(timePredicates::add); + Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get("fillingDate"), to)).ifPresent(timePredicates::add); + return timePredicates; + }).ifPresent(predicates::addAll); + Optional.ofNullable(query.getCaseClosingDate()).filter(f -> f.length == 2).map(f -> { + List timePredicates = new ArrayList<>(); + Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get("caseClosingDate"), from)).ifPresent(timePredicates::add); + Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get("caseClosingDate"), to)).ifPresent(timePredicates::add); + return timePredicates; + }).ifPresent(predicates::addAll); + Optional.ofNullable(query.getArchiveDate()).filter(f -> f.length == 2).map(f -> { + List timePredicates = new ArrayList<>(); + Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get("archiveDate"), from)).ifPresent(timePredicates::add); + Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get("archiveDate"), to)).ifPresent(timePredicates::add); + return timePredicates; + }).ifPresent(predicates::addAll); + Optional.ofNullable(query.getConditionlike()).filter(StringUtils::hasText).ifPresent(o -> { + List orPredicates = new ArrayList<>(); + Predicate p1 = criteriaBuilder.like(root.get(Case_.caseNum), "%" + o + "%"); + orPredicates.add(criteriaBuilder.or(p1)); + Predicate p2 = criteriaBuilder.like(root.get(Case_.caseName), "%" + o + "%"); + orPredicates.add(criteriaBuilder.or(p2)); + Predicate p3 = criteriaBuilder.like(root.get(Case_.caseCause), "%" + o + "%"); + orPredicates.add(criteriaBuilder.or(p3)); + Predicate p = criteriaBuilder.or(orPredicates.toArray(new Predicate[0])); + predicates.add(p); + }); + Optional.ofNullable(query.getSupplementVerifyResult()).ifPresent(o -> { + // 填报内容查询 + if ("tb".equals(o)) { + predicates.add(criteriaBuilder.or( + criteriaBuilder.notEqual(root.get("supplementVerifyResult"), "1"), + criteriaBuilder.isNull(root.get("supplementVerifyResult")) + )); + } + //审批内容查询 + else if ("sp".equals(o)) { + predicates.add(criteriaBuilder.equal(root.get("supplementVerifyResult"), "2")); + } else { + predicates.add(criteriaBuilder.equal(root.get("supplementVerifyResult"), o)); + } + }); + Optional.ofNullable(query.getSupplementVerifyTime()).filter(f -> f.length == 2).map(f -> { + List timePredicates = new ArrayList<>(); + Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get("supplementVerifyTime"), from)).ifPresent(timePredicates::add); + Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get("supplementVerifyTime"), to)).ifPresent(timePredicates::add); + return timePredicates; + }).ifPresent(predicates::addAll); + if (null != query.getCaseIds() && !query.getCaseIds().isEmpty()) { + CriteriaBuilder.In in = criteriaBuilder.in(root.get(Case_.caseId)); + query.getCaseIds().forEach(in::value); + predicates.add(in); + } + if ("decided".equals(query.getTag())) { + Predicate p1 = criteriaBuilder.equal(enforcementInfoCaseRoot.get(EnforcementInfo_.currentNodeCode), FlowNode.hearing); + Predicate p2 = criteriaBuilder.and( + criteriaBuilder.equal(enforcementInfoCaseRoot.get(EnforcementInfo_.currentNodeCode), FlowNode.inform), + criteriaBuilder.equal(root.get(Case_.sfsqtz), "0") + ); + predicates.add(criteriaBuilder.or(p1, p2)); + } + // 机构 + Join agencyCaseRoot = root.join("agency", JoinType.LEFT); + if (StringUtils.hasText(query.getAgencyCode())) { + String code= com.aisino.iles.common.util.StringUtils.trimEven0(query.getAgencyCode()) + "%"; + predicates.add(criteriaBuilder.like((agencyCaseRoot.get(Agency_.agencyCode)), code)); + } else { + Agency currentAgency = agencyRepo.findByAgencyCode(user.getGajgjgdm()).orElseThrow(() -> new RuntimeException("当前用户机构数据错误,请检查!")); + String code= com.aisino.iles.common.util.StringUtils.trimEven0(currentAgency.getAgencyCode()) + "%"; + predicates.add(criteriaBuilder.like((agencyCaseRoot.get(Agency_.agencyCode)), code)); + } + if ("1".equals(query.getAjbjlx())) { // 案件已办结 + CriteriaBuilder.In in = criteriaBuilder.in(root.get(Case_.status)); + in.value(Case.CaseStatus.closing); + in.value(Case.CaseStatus.archived); + predicates.add(in); + } else if ("2".equals(query.getAjbjlx())) { // 案件未办结 + CriteriaBuilder.In in = criteriaBuilder.in(root.get(Case_.status)); + in.value(Case.CaseStatus.filed); + in.value(Case.CaseStatus.investigating); + in.value(Case.CaseStatus.investigation_done); + in.value(Case.CaseStatus.analyze_judge); + predicates.add(in); + } + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }); + } + + + /** + * 保存案件 + * + * @param c 案件信息 + * @return 保存后案件信息 + */ + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public Case saveCase(Case c) { + // 生成案件号 + String caseNum = generateCodeService.buildCode("xa", "case", null, 0); + c.setCaseNum(caseNum); + if (c.getArchiveDate() != null) { + // 归档 + c.setStatus(Case.CaseStatus.archived); + } + return caseRepository.save(c); + } + + @Transactional(readOnly = true) + public Optional findCaseById(String caseId) { + return caseRepository.findById(caseId).map(c -> { + //获取执法结构信息 + c.getEnforcementInfo().getAgency().getAgencyName(); + //获取企业信息 + c.getEnforcementInfo().getEnterprise().getUnitName(); + c.setEnterprise(c.getEnforcementInfo().getEnterprise()); + //获取 执法检查信息 + enforceCheckService.getEnforceCheckByEnforcementId(c.getEnforcementInfo().getEnforcementId()).ifPresent(check -> { + c.setEnforceCheck(check); + }); + return c; + }); + } + + private Case getCaseevidenceDetailInfo(Case c) { + c.getEnforcementInfo().getAgency().getAgencyName(); + c.getEnforcementInfo().getEnterprise().getUnitName(); + c.setEnterprise(c.getEnforcementInfo().getEnterprise()); + switch (c.getCaseSourceCode()) { + case "1" -> c.setCaseSourceCode("日常检查发现"); + case "2" -> c.setCaseSourceCode("机构监测报告"); + case "3" -> c.setCaseSourceCode("举报投诉"); + case "4" -> c.setCaseSourceCode("上级交办"); + case "5" -> c.setCaseSourceCode("下级情报"); + case "6" -> c.setCaseSourceCode("有关部门移送"); + case "7" -> c.setCaseSourceCode("其他"); + + } + switch (c.getCaseCause()) { + case "1" -> c.setCaseCause("安全生产行政许可类违法"); + case "2" -> c.setCaseCause("安全生产管理机构和管理人员类违法"); + case "3" -> c.setCaseCause("安全生产建设工程项目类违法"); + case "4" -> c.setCaseCause("安全生产规章制度类违法"); + case "5" -> c.setCaseCause("安全生产培训教育类违法"); + case "6" -> c.setCaseCause("安全生产资金投入类违法"); + case "7" -> c.setCaseCause("安全生产隐患管理类违法"); + case "8" -> c.setCaseCause("生产安全事故应急救援类违法"); + case "9" -> c.setCaseCause("安全生产承包租赁类违法"); + case "10" -> c.setCaseCause("安全生产警示标志类违法"); + case "11" -> c.setCaseCause("安全生产中介机构类违法"); + case "12" -> c.setCaseCause("安全设备使用维护类违法"); + case "13" -> c.setCaseCause("重大危险源管理类违法"); + case "14" -> c.setCaseCause("生产经营单位作业现场管理类违法"); + case "15" -> c.setCaseCause("生产安全事故报告类违法"); + case "16" -> c.setCaseCause("生产安全事故责任类违法"); + case "17" -> c.setCaseCause("其他"); + } + Optional.ofNullable(c.getEvidence()).ifPresent(e -> { + Optional.ofNullable(e.get("filesData")).ifPresent(list -> { + List> files = (ArrayList) list; + files.forEach(f -> { + String savePathName = f.get("savePathName"); + String url = ftpService.getFileUrl(savePathName); + String downloadUrl = ftpService.getFileUrl(savePathName); + f.put("url", url); + f.put("downloadUrl", downloadUrl); + }); + }); + }); + return c; + } + + private Case getCaseDetailInfo(Case c) { + c.getEnforcementInfo().getAgency().getAgencyName(); + c.getEnforcementInfo().getEnterprise().getUnitName(); + c.setEnterprise(c.getEnforcementInfo().getEnterprise()); + Optional.ofNullable(c.getFilePath()).filter(StringUtils::hasText).ifPresent(o -> c.setDownUrl(ftpService.getFileUrl(o))); + switch (c.getCaseSourceCode()) { + case "1" -> c.setCaseSourceCode("日常检查发现"); + case "2" -> c.setCaseSourceCode("机构监测报告"); + case "3" -> c.setCaseSourceCode("举报投诉"); + case "4" -> c.setCaseSourceCode("上级交办"); + case "5" -> c.setCaseSourceCode("下级情报"); + case "6" -> c.setCaseSourceCode("有关部门移送"); + case "7" -> c.setCaseSourceCode("其他"); + + } + + switch (c.getCaseCause()) { + case "1" -> c.setCaseCause("安全生产行政许可类违法"); + case "2" -> c.setCaseCause("安全生产管理机构和管理人员类违法"); + case "3" -> c.setCaseCause("安全生产建设工程项目类违法"); + case "4" -> c.setCaseCause("安全生产规章制度类违法"); + case "5" -> c.setCaseCause("安全生产培训教育类违法"); + case "6" -> c.setCaseCause("安全生产资金投入类违法"); + case "7" -> c.setCaseCause("安全生产隐患管理类违法"); + case "8" -> c.setCaseCause("生产安全事故应急救援类违法"); + case "9" -> c.setCaseCause("安全生产承包租赁类违法"); + case "10" -> c.setCaseCause("安全生产警示标志类违法"); + case "11" -> c.setCaseCause("安全生产中介机构类违法"); + case "12" -> c.setCaseCause("安全设备使用维护类违法"); + case "13" -> c.setCaseCause("重大危险源管理类违法"); + case "14" -> c.setCaseCause("生产经营单位作业现场管理类违法"); + case "15" -> c.setCaseCause("生产安全事故报告类违法"); + case "16" -> c.setCaseCause("生产安全事故责任类违法"); + case "17" -> c.setCaseCause("其他"); + } + + Optional.ofNullable(c.getEvidence()).ifPresent(e -> { + Optional.ofNullable(e.get("filesData")).ifPresent(list -> { + List> files = (ArrayList) list; + files.forEach(f -> { + String savePathName = f.get("savePathName"); + String url = ftpService.getFileUrl(savePathName); + String downloadUrl = ftpService.getFileUrl(savePathName); + f.put("url", url); + f.put("downloadUrl", downloadUrl); + }); + }); + }); + Optional.ofNullable(c.getExecute()).ifPresent(e -> { + Optional.ofNullable(e.get("annexs")).ifPresent(list -> { + List> files = (ArrayList) list; + files.forEach(f -> { + String savePathName = f.get("savePathName"); + String url = ftpService.getFileUrl(savePathName); + String downloadUrl = ftpService.getFileUrl(savePathName); + f.put("url", url); + f.put("downloadUrl", downloadUrl); + }); + }); + }); + return c; + } + + /** + * 查询案件集合 + * + * @param query 查询条件 + * @return 查询结果 + */ + public List listCases(CaseQuery query, RemoteUserInfo user) { + Sort sort = Sort.by(Sort.Direction.DESC, "createdTime"); + query.setSort(sort.toString()); + if ("Y".equals(query.getTag())) { + List caseIds = documentRepository.findDistinctCaseIdByStatus(Document.DocumentStatus.done); + query.setCaseIds(caseIds); + } + return caseRepository.findAll(buildSpec(query, user)); + } + + /** + * 保存调查取证材料 + * + * @param formData 调查取证材料 + * @return 保存后案件信息 + */ + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public Case saveEvidence(FormDataDto formData) { + // TODO + MultipartFile[] files = formData.getFiles(); + Case caseInfo = new Case(); + try { + caseInfo = objectMapper.readValue(formData.getFormDataJson(), Case.class); + Map evidence = caseInfo.getEvidence(); + Object filesData = evidence.get("filesData"); + List> oldfilePaths = new ArrayList<>(); + if (oldfilePaths != null) + oldfilePaths = (List>) filesData; + oldfilePaths.forEach(file -> { + if (file.get("savePathName") != null && StringUtils.hasText(String.valueOf(file.get("savePathName")))) + ftpService.deletePathFile(String.valueOf(file.get("savePathName"))); // 删除文件服务器上的文件 + }); + List> newfilePaths = new ArrayList<>(); + for (MultipartFile file : files) { + String url; + try { + url = ftpService.uploadTempFile(IndustryCategoryForFile.pub, file.getOriginalFilename(), file.getInputStream()); + if (!StringUtils.hasText(url)) { + throw new BusinessError(file.getOriginalFilename() + "失败:上传时异常"); + } + Map singlePath = new HashMap<>(); + singlePath.put("name", file.getOriginalFilename()); + singlePath.put("savePathName", url); + singlePath.put("dowloadUrl", ftpService.getFileUrl(url)); + newfilePaths.add(singlePath); + } catch (Exception e) { + throw new BusinessError(file.getOriginalFilename() + "上传失败:" + e); + } + } + caseRepository.findById(caseInfo.getCaseId()).map(c -> { + return c; + }); + } catch (JsonProcessingException e) { + log.error(e.getMessage(), e); + } + return null; + } + + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public List saveEvidence(Case c) { + return caseRepository.findById(c.getCaseId()).map(oldCase -> { + List result = new ArrayList<>(); + //删除文件 +// if (c.getEvidence() != null && c.getEvidence().get("filesData") != null && oldCase.getEvidence() != null && oldCase.getEvidence().get("filesData") != null) { +// List> newfilePaths = (List>) c.getEvidence().get("filesData"); +// List> oldfilePaths = (List>) oldCase.getEvidence().get("filesData"); +// Set> bSet = new HashSet<>(newfilePaths); +// for (Map num : oldfilePaths) { +// if (!bSet.contains(num)) { +// ftpService.deletePathFile(String.valueOf(num.get("savePathName"))); +// } +// } +// } + oldCase.setEvidence(c.getEvidence()); + result.add(oldCase); + //修改执法流程节点 + enforcementInfoRepository.findById(c.getEnforcementId()).ifPresent(enforcementInfo -> { + if (c.getStatus().equals(Case.CaseStatus.investigating)) { + enforcementInfo.setCurrentNodeCode(FlowNode.investigating); + enforcementInfo.setCurrentNode("调查取证中"); + result.add(enforcementInfo); + } else if (c.getStatus().equals(Case.CaseStatus.investigation_done)) { + enforcementInfo.setCurrentNodeCode(FlowNode.investigation_done); + enforcementInfo.setCurrentNode("调查取证完成"); + result.add(enforcementInfo); + } + }); + oldCase.setStatus(Case.CaseStatus.investigation_done); + caseRepository.save(oldCase); + return result; + }).get(); + } + + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public List fxyp(Case c) { + if (c.getAnalyzeJudge() != null && c.getAnalyzeJudge().get("shjg") != null) { + List result = new ArrayList<>(); + return caseRepository.findById(c.getCaseId()).map(oldCase -> { + result.add(oldCase); + if ((Integer) c.getAnalyzeJudge().get("shjg") == 0) { + enforcementInfoRepository.findById(c.getEnforcementId()).ifPresent(enforcementInfo -> { + enforcementInfo.setCurrentNodeCode(FlowNode.done); + enforcementInfo.setCurrentNode("结案"); + result.add(enforcementInfo); + }); + } + oldCase.setAnalyzeJudge(c.getAnalyzeJudge()); + oldCase.setStatus(Case.CaseStatus.analyze_judge); + caseRepository.save(oldCase); + return result; + }).get(); + } else { + throw new BusinessError("法制审核保存失败:数据错误,请联系管理员"); + } + } + + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public List discuss(Case c) { + if (c.getDiscuss() != null) { + List result = new ArrayList<>(); + return caseRepository.findById(c.getCaseId()).map(oldCase -> { + result.add(oldCase); + enforcementInfoRepository.findById(c.getEnforcementId()).ifPresent(enforcementInfo -> { + enforcementInfo.setCurrentNodeCode(FlowNode.analyze_judge); + enforcementInfo.setCurrentNode("审理"); + result.add(enforcementInfo); + }); + oldCase.setDiscuss(c.getDiscuss()); + caseRepository.save(oldCase); + return result; + }).get(); + } else { + throw new BusinessError("集体讨论保存失败:数据错误,请联系管理员"); + } + } + + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public List inform(Case c) { + if (c.getInform() != null) { + List result = new ArrayList<>(); + return caseRepository.findById(c.getCaseId()).map(oldCase -> { + result.add(oldCase); + enforcementInfoRepository.findById(c.getEnforcementId()).ifPresent(enforcementInfo -> { + enforcementInfo.setCurrentNodeCode(FlowNode.inform); + enforcementInfo.setCurrentNode("告知"); + result.add(enforcementInfo); + }); + oldCase.setInform(c.getInform()); + caseRepository.save(oldCase); + return result; + }).get(); + } else { + throw new BusinessError("告知失败:数据错误,请联系管理员"); + } + } + + /** + * 案件 陈述申辩或听证 + * @param c + * @return + */ + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public List informsbtz(Case c) { + if (c.getInformsbtz() != null ) { + List result = new ArrayList<>(); + return caseRepository.findById(c.getCaseId()).map(oldCase -> { + result.add(oldCase); + enforcementInfoRepository.findById(c.getEnforcementId()).ifPresent(enforcementInfo -> { + enforcementInfo.setCurrentNodeCode(FlowNode.hearing); + enforcementInfo.setCurrentNode("陈述申辩或听证"); + result.add(enforcementInfo); + }); + oldCase.setInformsbtz(c.getInformsbtz()); + caseRepository.save(oldCase); + return result; + }).get(); + } else { + throw new BusinessError("审理失败:数据错误,请联系管理员"); + } + } + + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public Case exportPdf(String caseId) throws IOException { + Case caseInfo = new Case(); + List inputs = new ArrayList<>(); + documentRepository.findByCaseIdAndStatusOrderByDocumentNoAsc(caseId, Document.DocumentStatus.done).forEach(document -> { + try { + inputs.add(new PdfMerger.PdfInput(document.getFileName(), document, ftpService.getFileAsBytes(document.getFilePath()))); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + if (inputs.size() > 0) { + PDDocument mergedDoc = null; + String path = this.getClass().getClassLoader().getResource("").getPath() + "tempExportPdf/" + caseId + ".pdf"; + File outputFile = new File(path); + File parentDir = outputFile.getParentFile(); + if (parentDir != null && !parentDir.exists()) { + parentDir.mkdirs(); // 自动创建父目录 + } + try { +// mergedDoc = PdfMerger.mergePdf(inputs); +// mergedDoc.save(path); + mergePDFsWithPageNumbers(inputs, path); + System.out.println("PDF合并并添加页码完成!"); + log.info("成功整合案卷保存成功: " + caseId + ".pdf"); + caseInfo = caseRepository.findById(caseId).map(c -> { + //如果已经生成过案卷,则先删除服务器上的老文件 + Optional.ofNullable(c.getFilePath()).filter(StringUtils::hasText).ifPresent(o -> ftpService.deletePathFile(o)); + try (InputStream in = new FileInputStream(path)) { + String saveFtpUrl = ftpService.uploadTempFile(IndustryCategoryForFile.pub, caseId + ".pdf", in); + c.setFilePath(saveFtpUrl); + c.setFilePathTime(LocalDateTime.now()); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } + return c; + }).orElse(null); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (mergedDoc != null) { + mergedDoc.close(); // 确保文档关闭 + } + } + // 删除服务器上生成的零时文件 + Files.delete(outputFile.toPath()); + } + caseInfo.setDownUrl(ftpService.getFileUrl(caseInfo.getFilePath())); + return caseInfo; + } + + + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public Case saveSupplement(Case c, RemoteUserInfo user) { + return caseRepository.findById(c.getCaseId()).map(oldCase -> { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + c.getSupplement().put("tbr", user.getXm()); + c.getSupplement().put("tbsj", LocalDateTime.now().format(formatter)); + oldCase.setSupplement(c.getSupplement()); + oldCase.setUpdatedTime(LocalDateTime.now()); + oldCase.setSupplementVerifyResult("2"); + return caseRepository.save(oldCase); + }).get(); + } + + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public Case updateSupplementVerify(Case c, RemoteUserInfo user) { + return caseRepository.findById(c.getCaseId()).map(oldCase -> { + oldCase.setSupplementVerifyResult(c.getSupplementVerifyResult()); + oldCase.setSupplementVerifyDesc(c.getSupplementVerifyDesc()); + oldCase.setSupplementVerifyUserName(user.getXm()); + oldCase.setSupplementVerifyTime(LocalDateTime.now()); + return caseRepository.save(oldCase); + }).get(); + } + + /** + * 查询案件集合 + * + * @param query 查询条件 + * @return 查询结果 + */ + @Transactional(readOnly = true) + public List listZflatj(CaseQuery query, RemoteUserInfo user) { + + Sort sort = Sort.by(Sort.Direction.DESC, "supplementVerifyTime"); + query.setSort(sort.toString()); + //判断周期类型组装日期条件 + Optional.ofNullable(query.getPeriod()).ifPresent(o -> { + if ("month".equals(o)) { + LocalDate[] fillingDate = new LocalDate[]{query.getYd(), query.getYd().with(TemporalAdjusters.lastDayOfMonth())}; + query.setFillingDate(fillingDate); + } else if ("quarter".equals(o)) { + if (query.getJd() == 1) { + LocalDate start = LocalDate.of(LocalDate.now().getYear(), 1, 1); + LocalDate end = LocalDate.of(LocalDate.now().getYear(), 3, 31); + LocalDate[] fillingDate = new LocalDate[]{start, end}; + query.setFillingDate(fillingDate); + } else if (query.getJd() == 2) { + LocalDate start = LocalDate.of(LocalDate.now().getYear(), 4, 1); + LocalDate end = LocalDate.of(LocalDate.now().getYear(), 6, 30); + LocalDate[] fillingDate = new LocalDate[]{start, end}; + query.setFillingDate(fillingDate); + } else if (query.getJd() == 3) { + LocalDate start = LocalDate.of(LocalDate.now().getYear(), 7, 1); + LocalDate end = LocalDate.of(LocalDate.now().getYear(), 9, 30); + LocalDate[] fillingDate = new LocalDate[]{start, end}; + query.setFillingDate(fillingDate); + } else if (query.getJd() == 4) { + LocalDate start = LocalDate.of(LocalDate.now().getYear(), 10, 1); + LocalDate end = LocalDate.of(LocalDate.now().getYear(), 12, 31); + LocalDate[] fillingDate = new LocalDate[]{start, end}; + query.setFillingDate(fillingDate); + } + } + }); + return caseRepository.findAll(buildSpec(query, user)).stream().map(this::transferInfo).toList(); + } + + private Case transferInfo(Case c) { + c.getEnforcementInfo().getAgency().getAgencyName(); + c.getEnforcementInfo().getEnterprise().getUnitName(); + Optional.ofNullable(c.getCaseSourceCode()).ifPresent(caseSourseCode -> { + switch (caseSourseCode) { + case "1" -> c.setCaseSourceCode("日常检查发现"); + case "2" -> c.setCaseSourceCode("机构监测报告"); + case "3" -> c.setCaseSourceCode("举报投诉"); + case "4" -> c.setCaseSourceCode("上级交办"); + case "5" -> c.setCaseSourceCode("下级情报"); + case "6" -> c.setCaseSourceCode("有关部门移送"); + case "7" -> c.setCaseSourceCode("其他"); + + } + }); + + Optional.ofNullable(c.getCaseCause()).ifPresent(caseCause -> { + switch (caseCause) { + case "1" -> c.setCaseCause("安全生产行政许可类违法"); + case "2" -> c.setCaseCause("安全生产管理机构和管理人员类违法"); + case "3" -> c.setCaseCause("安全生产建设工程项目类违法"); + case "4" -> c.setCaseCause("安全生产规章制度类违法"); + case "5" -> c.setCaseCause("安全生产培训教育类违法"); + case "6" -> c.setCaseCause("安全生产资金投入类违法"); + case "7" -> c.setCaseCause("安全生产隐患管理类违法"); + case "8" -> c.setCaseCause("生产安全事故应急救援类违法"); + case "9" -> c.setCaseCause("安全生产承包租赁类违法"); + case "10" -> c.setCaseCause("安全生产警示标志类违法"); + case "11" -> c.setCaseCause("安全生产中介机构类违法"); + case "12" -> c.setCaseCause("安全设备使用维护类违法"); + case "13" -> c.setCaseCause("重大危险源管理类违法"); + case "14" -> c.setCaseCause("生产经营单位作业现场管理类违法"); + case "15" -> c.setCaseCause("生产安全事故报告类违法"); + case "16" -> c.setCaseCause("生产安全事故责任类违法"); + case "17" -> c.setCaseCause("其他"); + } + }); + + String industryType = c.getEnforcementInfo().getEnterprise().getIndustryType(); + String industryTypeName = Constants.DictDisplay.hylbMap.get(industryType); + c.setEnterprise(c.getEnforcementInfo().getEnterprise()); + //行业类别分类 + c.getEnterprise().setIndustryType(industryTypeName); + //获取 执法检查信息 + enforceCheckService.getEnforceCheckByEnforcementId(c.getEnforcementInfo().getEnforcementId()).ifPresent(check -> { + c.setEnforceCheck(check); + }); + return c; + } + + @PublishDataChange(action = DataChangeAction.SAVE) + @Transactional + public List decided(Case c) { + if (c.getPunishmentItems() != null || c.getDecided() != null) { + List result = new ArrayList<>(); + return caseRepository.findById(c.getCaseId()).map(oldCase -> { + result.add(oldCase); + enforcementInfoRepository.findById(c.getEnforcementId()).ifPresent(enforcementInfo -> { + enforcementInfo.setCurrentNodeCode(FlowNode.decided); + enforcementInfo.setCurrentNode("决定"); + result.add(enforcementInfo); + }); + oldCase.setPunishmentItems(c.getPunishmentItems()); + oldCase.setDecided(c.getDecided()); + oldCase.setDecidePayment(c.getDecidePayment()); + oldCase.setUpdatedTime(LocalDateTime.now()); + caseRepository.save(oldCase); + return result; + }).get(); + } else { + throw new BusinessError("决定失败:数据错误,请联系管理员"); + } + } + + @Transactional + @PublishDataChange(action = DataChangeAction.SAVE) + public void execute(Case c) { + caseRepository.findById(c.getCaseId()).ifPresent(caseInfo -> { + enforcementInfoRepository.findById(c.getEnforcementId()).ifPresent(enforcementInfo -> { + enforcementInfo.setCurrentNodeCode(FlowNode.execute); + enforcementInfo.setCurrentNode("执行"); + }); + caseInfo.setExecute(c.getExecute()); + caseRepository.save(caseInfo); + }); + } + + @Transactional + @PublishDataChange(action = DataChangeAction.SAVE) + public void finalCase(Case c) { + caseRepository.findById(c.getCaseId()).ifPresent(caseInfo -> { + enforcementInfoRepository.findById(c.getEnforcementId()).ifPresent(enforcementInfo -> { + enforcementInfo.setCurrentNodeCode(FlowNode.done); + enforcementInfo.setCurrentNode("完成"); + }); + caseInfo.setStatus(Case.CaseStatus.closing); + caseInfo.setFinalCase(c.getFinalCase()); + caseRepository.save(caseInfo); + }); + } + + public Map ajtj(RemoteUserInfo user) { + String gajgjgdm = com.aisino.iles.common.util.StringUtils.trimEven0(user.getGajgjgdm()); + Map ajtj = caseRepository.ajtj(gajgjgdm + "%"); + return ajtj; + } + +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/CheckItemService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/CheckItemService.java new file mode 100644 index 0000000..ccc494a --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/CheckItemService.java @@ -0,0 +1,148 @@ +package com.aisino.iles.lawenforcement.service; + + +import com.aisino.iles.common.util.PageableHelper; +import com.aisino.iles.lawenforcement.model.CheckItem; +import com.aisino.iles.lawenforcement.model.CheckItem_; +import com.aisino.iles.lawenforcement.model.query.CheckItemQuery; +import com.aisino.iles.lawenforcement.repository.CheckItemRepository; +import com.smartlx.sso.client.model.RemoteUserInfo; +import jakarta.persistence.criteria.Predicate; +import org.springframework.data.domain.Page; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * 检查项信息服务类 + */ +@Service +public class CheckItemService { + + private final CheckItemRepository checkItemRepo; + + public CheckItemService(CheckItemRepository checkItemRepo) { + this.checkItemRepo = checkItemRepo; + + } + + /** + * 保存检查项信息 + * + * @param checkItem 检查项信息 + * @return 保存后的检查项信息 + */ + @Transactional + public CheckItem saveCheckItem(CheckItem checkItem, RemoteUserInfo user, String type) { + LocalDateTime now = LocalDateTime.now(); + if ("add".equals(type)) { + checkItem.setEnabled(true); + checkItem.setCreateTime(now); + if (null != user) { + checkItem.setCreatedBy(user.getXm()); + checkItem.setCreatedAccountBy(user.getYhwybs()); + } + } + checkItem.setUpdateTime(now); + return checkItemRepo.save(checkItem); + } + + /** + * 根据ID查询检查项信息 + * + * @param checkItemId 检查项ID + * @return 检查项信息 + */ + public Optional findCheckItemById(String checkItemId) { + return checkItemRepo.findById(checkItemId); + } + + + /** + * 根据查询条件分页查询检查项信息 + * + * @param query 查询条件 + * @return 分页检查项信息 + */ + public Page findCheckItemPage(CheckItemQuery query) { + return checkItemRepo.findAll(build(query), + PageableHelper.buildPageRequest(query.page(), query.pageSize(), + (StringUtils.hasText(query.sort()) ? query.sort() : "createTime"), + (StringUtils.hasText(query.dir()) ? query.dir() : "desc")), + "checklist"); + } + + /** + * 构建查询条件 + * + * @param query 查询条件 + * @return 规格 + */ + private Specification build(CheckItemQuery query) { + return (root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + Optional.ofNullable(query.getItemName()).filter(StringUtils::hasText).ifPresent(o -> predicates.add(criteriaBuilder.like(root.get(CheckItem_.itemName), "%" + o + "%"))); + Optional.ofNullable(query.getItemTable()).filter(StringUtils::hasText).ifPresent(o -> predicates.add(criteriaBuilder.equal(root.get(CheckItem_.itemTable), o))); + Optional.ofNullable(query.getItemType()).filter(StringUtils::hasText).ifPresent(o -> predicates.add(criteriaBuilder.equal(root.get(CheckItem_.itemType), o))); + Optional.ofNullable(query.getUpdateTimeList()).filter(f -> f.length == 2).map(f -> { + List ts = new ArrayList<>(); + Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get(CheckItem_.updateTime), from)).ifPresent(ts::add); + Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get(CheckItem_.updateTime), to)).ifPresent(ts::add); + return ts; + }).ifPresent(predicates::addAll); + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } + + + /** + * 根据ID删除检查项信息 + * + * @param checkItemId 检查项ID + */ + @Transactional + public void deleteCheckItemById(String checkItemId) { + checkItemRepo.deleteById(checkItemId); + } + + /** + * 检查项是否存在 + * + * @param checkItemId 检查项ID + * @return 是否存在 + */ + public boolean existsCheckItemById(String checkItemId) { + return checkItemRepo.existsById(checkItemId); + } + + /** + * 批量删除检查项 + * + * @param itemIds 检查项ID列表 + */ + @Transactional + public void deleteCheckItemByIds(List itemIds) { + checkItemRepo.deleteAllById(itemIds); + } + + + /** + * 查询检查项列表 + * + * @return 分页检查项信息 + */ + public List findCheckItems(CheckItemQuery query) { + if (StringUtils.hasText(query.getItemTable())) + return checkItemRepo.findByItemTableAndEnabled(query.getItemTable(), true); + else + return checkItemRepo.findByEnabled(true); + } + + +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/ChecklistService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/ChecklistService.java new file mode 100644 index 0000000..7869dec --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/ChecklistService.java @@ -0,0 +1,139 @@ +package com.aisino.iles.lawenforcement.service; + +import com.aisino.iles.common.util.PageableHelper; +import com.aisino.iles.lawenforcement.model.Checklist; +import com.aisino.iles.lawenforcement.model.Checklist_; +import com.aisino.iles.lawenforcement.model.query.ChecklistQuery; +import com.aisino.iles.lawenforcement.repository.ChecklistRepository; +import com.smartlx.sso.client.model.RemoteUserInfo; +import jakarta.persistence.criteria.Predicate; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * 检查表服务类 + */ +@Service +@Slf4j +public class ChecklistService { + private final ChecklistRepository checklistRepo; + + public ChecklistService(ChecklistRepository checklistRepo) { + this.checklistRepo = checklistRepo; + } + + /** + * 保存检查表信息 + * + * @param checklist 检查表信息 + * @return 保存后的检查表信息 + */ + @Transactional + public Checklist saveChecklist(Checklist checklist, RemoteUserInfo user, String type) { + LocalDateTime now = LocalDateTime.now(); + if ("add".equals(type)) { + checklist.setIsRemove(false); + checklist.setCreateTime(now); + } + return checklistRepo.save(checklist); + } + + /** + * 根据ID查询检查表信息 + * + * @param checklistId 检查表ID + * @return 检查表信息 + */ + public Optional findChecklistById(String checklistId) { + return checklistRepo.findById(checklistId); + } + + + /** + * 根据查询条件分页查询检查表信息 + * + * @param query 查询条件 + * @return 分页检查表信息 + */ + public Page findChecklistPage(ChecklistQuery query) { + return checklistRepo.findAll(build(query), PageableHelper.buildPageRequest(query.page(), + query.pageSize(), + (StringUtils.hasText(query.sort()) ? query.sort() : "createTime"), + (StringUtils.hasText(query.dir()) ? query.dir() : "desc"))); + } + + /** + * 构建查询条件 + * + * @param query 查询条件 + * @return 规格 + */ + private Specification build(ChecklistQuery query) { + return (root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + Optional.ofNullable(query.getIsRemove()).ifPresent(o -> predicates.add(criteriaBuilder.equal(root.get(Checklist_.isRemove), o))); + Optional.ofNullable(query.getEnabled()).ifPresent(o -> predicates.add(criteriaBuilder.equal(root.get(Checklist_.enabled), o))); + Optional.ofNullable(query.getChecklistName()).filter(StringUtils::hasText).ifPresent(o -> predicates.add(criteriaBuilder.like(root.get(Checklist_.checklistName), "%" + o + "%"))); + Optional.ofNullable(query.getDescription()).filter(StringUtils::hasText).ifPresent(o -> predicates.add(criteriaBuilder.like(root.get(Checklist_.description), "%" + o + "%"))); + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } + + + /** + * 根据ID删除检查表信息 + * + * @param checklistId 检查表ID + */ + @Transactional + public void deleteChecklistById(String checklistId) { + checklistRepo.findById(checklistId).ifPresent(checklist -> { + checklist.setIsRemove(true); + checklist.setRemoveTime(LocalDateTime.now()); + checklistRepo.save(checklist); + }); + } + + /** + * 检查表是否存在 + * + * @param checklistId 检查表ID + * @return 是否存在 + */ + public boolean existsChecklistById(String checklistId) { + return checklistRepo.existsById(checklistId); + } + + /** + * 批量删除检查表 + * + * @param itemIds 检查表ID列表 + */ + @Transactional + public void deleteChecklistByIds(List itemIds) { + checklistRepo.findAllById(itemIds).forEach(checklist -> { + checklist.setIsRemove(true); + checklist.setRemoveTime(LocalDateTime.now()); + checklistRepo.save(checklist); + }); + } + + /** + * 根据查询条件获取检查表列表 + * + * @param query 查询条件 + * @return 检查表集合 + */ + public List getChecklistList(ChecklistQuery query) { + return checklistRepo.findAll(build(query)); + } +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/DataSyncService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/DataSyncService.java new file mode 100644 index 0000000..f8702df --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/DataSyncService.java @@ -0,0 +1,155 @@ +package com.aisino.iles.lawenforcement.service; + +import com.aisino.iles.lawenforcement.config.SyncApiProperties; +import com.aisino.iles.lawenforcement.exception.DataSyncException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.smartlx.sso.client.model.AccessToken; +import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.retry.annotation.Backoff; +import org.springframework.retry.annotation.Recover; +import org.springframework.retry.annotation.Retryable; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Service +public class DataSyncService { + + // 用于死信队列的专用Logger + private static final Logger DEAD_LETTER_LOGGER = LoggerFactory.getLogger("dead-letter-log"); + + private final ObjectMapper objectMapper; + private final RestTemplate restTemplate; + private final AuthService authService; + private final SyncApiProperties syncApiProperties; + + @Value("${third-party.enterprise.yddh}") + private String yddh; + + // 用于存储实体类型与对应API路径的映射 + private final Map, String> apiPathRegistry = new HashMap<>(); + + public DataSyncService(RestTemplate restTemplate, + AuthService authService, + ObjectMapper objectMapper, + SyncApiProperties syncApiProperties) { + this.restTemplate = restTemplate; + this.authService = authService; + this.syncApiProperties = syncApiProperties; + this.objectMapper = objectMapper; + } + + /** + * 初始化API路径注册表。 + */ + @PostConstruct + public void init() { + if (syncApiProperties.getEndpoints() == null) { + log.warn("未在配置文件中找到 'iles.sync.api.endpoints' 配置。数据同步功能可能无法正常工作。"); + return; + } + syncApiProperties.getEndpoints().forEach((className, path) -> { + try { + Class clazz = Class.forName(className); + apiPathRegistry.put(clazz, path); + log.info("已注册数据同步API端点: {} -> {}", clazz.getSimpleName(), path); + } catch (ClassNotFoundException e) { + log.error("无法加载API端点配置中的类: {}。请检查 'iles.sync.api.endpoints' 配置。", className, e); + } + }); + } + + @Retryable( + retryFor = {DataSyncException.class}, // 仅在捕获到我们自定义的异常时重试 + maxAttempts = 2, // 最多尝试2次 + backoff = @Backoff(delay = 2000, multiplier = 2) // 第一次延迟2秒,第二次延迟4秒 + ) + public void sendData(T data, Class entityType) { + log.info("正在尝试发送数据,类型: [{}], 尝试次数: {}", entityType.getSimpleName(), org.springframework.retry.support.RetrySynchronizationManager.getContext().getRetryCount() + 1); + + try { + // 1. 获取动态API URL + String apiUrl = getApiUrlForEntity(entityType); + + // 2. 获取认证Token + AccessToken token = authService.getTokenBackend(yddh); + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(token.getAccess_token()); + headers.setContentType(MediaType.APPLICATION_JSON); + + // 3. 将数据对象序列化为JSON字符串 + String jsonData = objectMapper.writeValueAsString(data); + HttpEntity requestEntity = new HttpEntity<>(jsonData, headers); + + // 4. 调用第三方API + log.debug("同步数据内容: {}", jsonData); + ResponseEntity response = restTemplate.postForEntity(apiUrl, requestEntity, String.class); + + // 5. 处理响应 + if (!response.getStatusCode().is2xxSuccessful()) { + log.error("数据同步失败,URL: {}, 响应状态: {}, 响应体: {}", apiUrl, response.getStatusCode(), response.getBody()); + throw new DataSyncException("请求失败,状态码: " + response.getStatusCode()); + } + log.info("数据同步成功,URL: {}, 响应状态: {}", apiUrl, response.getStatusCode()); + + } catch (JsonProcessingException e) { + log.error("数据序列化为JSON时出错: {}", data, e); + // 对于序列化失败,不进行重试,直接进入恢复逻辑 + throw new DataSyncException("数据序列化失败", e); + } catch (RestClientException e) { + log.error("调用API时发生网络或客户端错误: {}", e.getMessage()); + // 对于网络等问题,抛出异常以触发重试 + throw new DataSyncException("因网络错误导致数据发送失败", e); + } catch (Exception e) { + log.error("处理数据同步时发生未知错误", e); + // 对于未知异常,也触发重试 + throw new DataSyncException("数据发送时发生未知错误", e); + } + } + + @Recover + public void recover(DataSyncException e, T data, Class entityType) { + String dataType = entityType.getSimpleName(); + log.error("数据类型 [{}] 的所有重试尝试均已失败。正在写入死信日志。", dataType, e); + try { + String dataAsJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(data); + String logMessage = String.format( + "{\n \"timestamp\": \"%s\",\n \"dataType\": \"%s\",\n \"error\": \"%s\",\n \"payload\": %s\n}", + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME), + dataType, + e.getMessage(), + dataAsJson + ); + DEAD_LETTER_LOGGER.error(logMessage); + } catch (com.fasterxml.jackson.core.JsonProcessingException jsonProcessingException) { + log.error("严重错误:未能将数据序列化为JSON以写入死信日志。数据将会丢失。数据类型: {}, 数据: {}", dataType, data, jsonProcessingException); + } + } + + /** + * 根据实体类型获取对应的API完整URL。 + */ + private String getApiUrlForEntity(Class entityClass) { + String relativePath = apiPathRegistry.get(entityClass); + if (relativePath == null) { + log.error("未找到实体类 {} 对应的API路径配置。", entityClass.getName()); + throw new IllegalArgumentException("未配置实体 " + entityClass.getSimpleName() + " 的API路径"); + } + return syncApiProperties.getBaseUrl() + relativePath; + } +}