diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/NoticeService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/NoticeService.java new file mode 100644 index 0000000..005a755 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/NoticeService.java @@ -0,0 +1,315 @@ +package com.aisino.iles.lawenforcement.service; + +import com.aisino.iles.core.exception.BusinessError; +import com.aisino.iles.lawenforcement.model.*; +import com.aisino.iles.lawenforcement.model.dto.OfficerDto; +import com.aisino.iles.lawenforcement.model.query.NotificationQuery; +import com.aisino.iles.lawenforcement.repository.AgencyRepository; +import com.aisino.iles.lawenforcement.repository.NoticeReceivingUnitRepository; +import com.aisino.iles.lawenforcement.repository.NoticeRepository; +import com.aisino.iles.lawenforcement.repository.OfficerRepository; +import com.smartlx.sso.client.model.RemoteUserInfo; +import jakarta.persistence.criteria.Join; +import jakarta.persistence.criteria.Predicate; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +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.validation.annotation.Validated; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + + +/** + * 通知公告 + */ +@Service +@Validated +@Transactional(readOnly = true) +public class NoticeService { + + private NoticeRepository noticeRepository; + private NoticeReceivingUnitRepository noticeReceivingUnitRepository; + private OfficerRepository officerRepository; + private AgencyRepository agencyRepository; + + public NoticeService(NoticeRepository noticeRepository, + NoticeReceivingUnitRepository noticeReceivingUnitRepository, + OfficerRepository officerRepository, + AgencyRepository agencyRepository) { + this.noticeRepository = noticeRepository; + this.noticeReceivingUnitRepository = noticeReceivingUnitRepository; + this.officerRepository = officerRepository; + this.agencyRepository = agencyRepository; + } + + /** + * 分页查询 + * + * @param query + * @param user + * @return + */ + public Page pageNotice(NotificationQuery query, RemoteUserInfo user) { + Integer _psize = Optional.ofNullable(query.pageSize()).filter(f -> f > 0).orElse(20); + Integer _page = Optional.ofNullable(query.page()).filter(f -> f > 0).map(f -> f - 1).orElse(0); + String _sort = Optional.ofNullable(query.sort()).filter(com.aisino.iles.common.util.StringUtils::isNotEmpty).orElse(Notice_.RELEASE_TIME); + String _dir = Optional.ofNullable(query.dir()).filter(d -> Sort.Direction.fromOptionalString(d).isPresent()).orElse("desc"); + return noticeRepository.findAll(buildQueryCondition(query, user), PageRequest.of(_page, _psize, Sort.by(Sort.Direction.fromString(_dir), _sort))); + } + + /** + * 动态查询条件构建 + */ + private Specification buildQueryCondition(NotificationQuery query, RemoteUserInfo user) { + return (root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + //标题 + Optional.ofNullable(query.getNotificationTitle()).filter(com.aisino.iles.common.util.StringUtils::isNotEmpty).ifPresent(o -> predicates.add(criteriaBuilder.like(root.get("noticeTitle"), "%" + o + "%"))); + //接收单位类型 + predicates.add(criteriaBuilder.equal(root.get("receivingUnitType"), "2")); + //发布单位 + String gxdwbm; + if (!StringUtils.hasText(query.getPublishingUnitCode())) { + gxdwbm = user.getGajgjgdm(); + } else { + gxdwbm = query.getPublishingUnitCode(); + } + Optional.ofNullable(gxdwbm).filter(com.aisino.iles.common.util.StringUtils::isNotEmpty).map(f -> { + Join join = root.join(Notice_.agency); + return criteriaBuilder.like(join.get(Agency_.agencyCode), com.aisino.iles.common.util.StringUtils.trimEven0(f) + "%"); + }).ifPresent(predicates::add); +// // 接收单位 +// Optional.ofNullable(gxdwbm).filter(com.aisino.iles.common.util.StringUtils::isNotEmpty).map(f -> { +// Join join = root.join(Notice_.noticeReceivingUnit); +// return criteriaBuilder.like(join.get(NoticeReceivingUnit_.receivingUnitCode), com.aisino.iles.common.util.StringUtils.trimEven0(f) + "%"); +// }).ifPresent(predicates::add); + // 发布单位-接受单位条件 + if (com.aisino.iles.common.util.StringUtils.isNotEmpty(gxdwbm)) { + List orPredicates = new ArrayList(); + Join join = root.join(Notice_.agency); + Predicate p1 = criteriaBuilder.like(join.get(Agency_.agencyCode), com.aisino.iles.common.util.StringUtils.trimEven0(gxdwbm) + "%"); + orPredicates.add(criteriaBuilder.or(p1)); + Join join2 = root.join(Notice_.noticeReceivingUnit); + Predicate p2 = criteriaBuilder.equal(join2.get(NoticeReceivingUnit_.receivingUnitCode), gxdwbm); + orPredicates.add(criteriaBuilder.or(p2)); + Predicate p = criteriaBuilder.or(orPredicates.toArray(new Predicate[0])); + predicates.add(p); + } + //发布时间 + Optional.ofNullable(query.getReleaseTimeFist()) + .ifPresent(o -> predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("releaseTime"), o))); + Optional.ofNullable(query.getReleaseTimeLast()) + .map(date -> date.plusDays(1L)) + .map(localDate -> criteriaBuilder.lessThan(root.get("releaseTime"), localDate)) + .ifPresent(predicates::add); + Optional.ofNullable(query.getReleaseTime()).filter(f -> f.length == 2).map(f -> { + List timePredicates = new ArrayList<>(); + Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get("releaseTime"), from)).ifPresent(timePredicates::add); + Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get("releaseTime"), to)).ifPresent(timePredicates::add); + return timePredicates; + }).ifPresent(predicates::addAll); + criteriaQuery.distinct(true); + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } + + + /** + * 新增 + * + * @param notice + * @param user + * @return + */ + @Transactional + public Notice addNotice(Notice notice, RemoteUserInfo user) { + notice.setPublisherUserId(user.getYhwybs()); + notice.setReceivingUnitType("2"); // 默认接收类型为2 + notice.setPublishingUnitCode(notice.getAgency().getAgencyCode()); // 发布单位编码 + notice.setPublishingUnit(notice.getAgency().getAgencyName()); // 发布单位 + // 根据管辖单位编码查询机构,赋值机构 + notice.setAgency(queryAgency(notice.getAgency().getAgencyCode())); + Notice noticeSave = noticeRepository.save(notice); + if (notice.isSelectAll()) { + String gxdwbm = ""; + if (com.aisino.iles.common.util.StringUtils.isNotEmpty(notice.getLtdJurisdictionCode())) { + gxdwbm = com.aisino.iles.common.util.StringUtils.trimEven0(notice.getLtdJurisdictionCode()); + } else { + if (StringUtils.isEmpty(gxdwbm)) { + gxdwbm = com.aisino.iles.common.util.StringUtils.trimEven0(user.getGajgjgdm()); + } + } + officerRepository.findByAgencyCode(gxdwbm + "%").forEach(a -> { + NoticeReceivingUnit unit = new NoticeReceivingUnit(); + unit.setNoticeId(noticeSave.getNoticeId()); // 通知ID + unit.setReceivingUnitId(a.getAgencyId()); // 接受单位ID + unit.setReceivingUnitCode(a.getAgencyCode()); // 接收单位代码 + unit.setReceivingUnitName(a.getAgencyName()); // 接受人姓名 + unit.setMsgflag("0"); // 查看标识 + unit.setCollectionTime(LocalDateTime.now()); // 收取时间 + unit.setCertificateNo(a.getCertificateNo()); // 执法证号ID + noticeReceivingUnitRepository.save(unit); + }); + } else { // 前台选择接收人 + Set jsrs = notice.getPeoplePolices(); + if (null != jsrs && jsrs.size() > 0) { + jsrs.forEach(j -> { + NoticeReceivingUnit unit = new NoticeReceivingUnit(); +// Optional officer = officerRepository.findByCertificateNo(j.getCertificateNo()); +// if (!officer.isPresent()) { +// throw new BusinessError("该 " + j.getCertificateNo() + " 接收人不存在!"); +// } + Optional agency = agencyRepository.findById(j.getAgencyId()); + if (!agency.isPresent()) throw new BusinessError("该 "+j.getCertificateNo() + " 所属单位不存在!"); + unit.setNoticeId(noticeSave.getNoticeId()); // 通知ID + unit.setReceivingUnitId(agency.get().getAgencyId()); // 接受单位ID + unit.setReceivingUnitCode(agency.get().getAgencyCode()); // 接收单位代码 + unit.setReceivingUnitName(agency.get().getAgencyName()); // 接受人姓名 + unit.setMsgflag("0"); // 查看标识 + unit.setCollectionTime(LocalDateTime.now()); // 收取时间 + // unit.setCertificateNo(officer.get().getCertificateNo()); // 执法证号ID + noticeReceivingUnitRepository.save(unit); + }); + } + } + return noticeSave; + } + + /** + * 单条查询 + * + * @param noticeId + * @return + */ + public Optional findOneNotice(String noticeId, RemoteUserInfo user) { + return noticeRepository.findById(noticeId).map(notice -> this.listNoticeItem(notice, user)); + } + + @Transactional + public Notice listNoticeItem(Notice notice, RemoteUserInfo user) { + List unitList = noticeReceivingUnitRepository.findByNoticeId(notice.getNoticeId()).stream().collect(Collectors.toList()); + Set officers = new HashSet<>(); + unitList.forEach(e -> { + Officer officer = new Officer(); + Optional agencyOptional = agencyRepository.findByAgencyCode(e.getReceivingUnitCode()); + if (!agencyOptional.isPresent()) { + throw new BusinessError("该 "+e.getCertificateNo() + " 接受单位不存在!"); + } +// Optional officerOptional = officerRepository.findByCertificateNo(e.getCertificateNo()); +// if (!officerOptional.isPresent()) { +// throw new BusinessError("该 "+e.getCertificateNo() + " 执法证号不存在!"); +// } +// officer.setOfficerId(officerOptional.get().getOfficerId()); // 执法人员唯一ID(ULID) +// officer.setCertificateNo(e.getCertificateNo()); // 执法证号(唯一标识) +// officer.setOfficerName(officerOptional.get().getOfficerName()); // 执法人员姓名 +// officer.setAgencyId(officerOptional.get().getAgencyId()); // 所属执法机构ID(ULID) +// officer.setRole(officerOptional.get().getRole()); // 角色 +// officer.setRoleName(officerOptional.get().getRoleName()); // 角色名称 + officer.setAgency(agencyOptional.get()); // 机构 + officer.setAgencyId(agencyOptional.get().getAgencyId()); // 机构ID + officer.setAgencyCode(agencyOptional.get().getAgencyCode()); // 机构代码 + officer.setAgencyName(agencyOptional.get().getAgencyName()); // 机构名称 + officer.setAgencySimpleCode(agencyOptional.get().getAgencySimpleCode()); // 机构简码 + officer.setLeaf(agencyOptional.get().getLeaf()); // 是否为最下级 + officers.add(officer); + }); + notice.setPeoplePolices(officers); + return notice; + } + + /** + * 修改 + */ + @Transactional + public void modifyNotice(String noticeId, Notice notice, RemoteUserInfo user) { + Optional noticeQuery = noticeRepository.findById(noticeId); + Notice noticeSave = noticeQuery.get(); + if (noticeQuery.isPresent()) { + com.aisino.iles.common.util.BeanUtils.copyNoNullProperties(notice, noticeSave, "noticeReceivingUnit"); + // 根据管辖单位编码查询机构,赋值机构 + notice.setAgency(queryAgency(notice.getAgency().getAgencyCode())); + notice.setPublishingUnitCode(notice.getAgency().getAgencyCode()); // 发布单位编码 + notice.setPublishingUnit(notice.getAgency().getAgencyName()); // 发布单位 + if (notice.isSelectAll()) { + String gxdwbm = ""; + if (com.aisino.iles.common.util.StringUtils.isNotEmpty(notice.getLtdJurisdictionCode())) { + gxdwbm = com.aisino.iles.common.util.StringUtils.trimEven0(notice.getLtdJurisdictionCode()); + } else { + if (StringUtils.isEmpty(gxdwbm)) { + gxdwbm = com.aisino.iles.common.util.StringUtils.trimEven0(user.getGajgjgdm()); + } + } + officerRepository.findByAgencyCode(gxdwbm + "%").forEach(a -> { + NoticeReceivingUnit unit = new NoticeReceivingUnit(); + unit.setNoticeId(noticeSave.getNoticeId()); // 通知ID + unit.setReceivingUnitId(a.getAgencyId()); // 接受单位ID + unit.setReceivingUnitCode(a.getAgencyCode()); // 接收单位代码 + unit.setReceivingUnitName(a.getAgencyName()); // 接受人姓名 + unit.setMsgflag("0"); // 查看标识 + unit.setCollectionTime(LocalDateTime.now()); // 收取时间 + noticeReceivingUnitRepository.save(unit); + }); + } else { // 前台选择接收人 + Set jsrs = notice.getPeoplePolices(); + if (null != jsrs && jsrs.size() > 0) { + jsrs.forEach(j -> { + NoticeReceivingUnit unit = new NoticeReceivingUnit(); +// Optional officer = officerRepository.findByAgencyCertificateNo(j.getCertificateNo()); +// if (!officer.isPresent()) { +// throw new BusinessError("该 " + j.getCertificateNo() + " 接收人不存在!"); +// } + Optional agency = agencyRepository.findById(j.getAgencyId()); + if (!agency.isPresent()) { + throw new BusinessError("该 "+j.getCertificateNo() + " 所属单位不存在!"); + } + unit.setNoticeId(noticeSave.getNoticeId()); // 通知ID + unit.setReceivingUnitId(agency.get().getAgencyId()); // 接受单位ID + unit.setReceivingUnitCode(agency.get().getAgencyCode()); // 接收单位代码 + unit.setReceivingUnitName(agency.get().getAgencyName()); // 接受人姓名 + unit.setMsgflag("0"); // 查看标识 + unit.setCollectionTime(LocalDateTime.now()); // 收取时间 +// unit.setCertificateNo(officer.get().getCertificateNo()); // 执法证号ID + noticeReceivingUnitRepository.save(unit); + }); + } + } + } + } + + /** + * 删除 + * + * @param noticeId + */ + @Transactional + public void removeNotice(String noticeId, RemoteUserInfo user) { + noticeReceivingUnitRepository.deleteBynoticeId(noticeId); + noticeRepository.deleteById(noticeId); + } + + + /** + * 通知通告列表 + * + * @param query 查询参数 + * @param user 当前用户 + * @return 通知通告列表 + */ + public List list(NotificationQuery query, RemoteUserInfo user) { + return noticeRepository.findAll(buildQueryCondition(query, user), Sort.by(Sort.Direction.DESC, Notice_.RELEASE_TIME)); + } + + public Agency queryAgency(String agencyCode) { + Optional agency = agencyRepository.findByAgencyCode(agencyCode); + if (!agency.isPresent()) { + throw new BusinessError("该 "+agencyCode + " 所属单位不存在!"); + } + return agency.get(); + } +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/OffSiteLawEnforceService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/OffSiteLawEnforceService.java new file mode 100644 index 0000000..5bf955d --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/OffSiteLawEnforceService.java @@ -0,0 +1,109 @@ +package com.aisino.iles.lawenforcement.service; + +import com.aisino.iles.lawenforcement.repository.EnterpriseRepository; +import com.aisino.iles.lawenforcement.repository.EnterpriseWarnRepository; +import com.aisino.iles.lawenforcement.repository.OnlinePatrolRepository; + +import jodd.util.StringUtil; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +@Service +public class OffSiteLawEnforceService { + + private final EnterpriseRepository enterpriseRepository; + private final OnlinePatrolRepository onlinePatrolRepository; + private final EnterpriseWarnRepository enterpriseWarnRepository; + + public OffSiteLawEnforceService(EnterpriseRepository enterpriseRepository, + OnlinePatrolRepository onlinePatrolRepository, + EnterpriseWarnRepository enterpriseWarnRepository) { + this.enterpriseRepository = enterpriseRepository; + this.onlinePatrolRepository = onlinePatrolRepository; + this.enterpriseWarnRepository = enterpriseWarnRepository; + } + + public Long getQyjrtj() { + return enterpriseRepository.findQyjrtj(); + } + + public Map getQyjrlxtj() { + Map res = new HashMap<>(); + List> qyjrlx = enterpriseRepository.findQyjrlxtj(); + res.put("ks", getLongValue(qyjrlx, "1")); + res.put("wh", getLongValue(qyjrlx, "2") + getLongValue(qyjrlx, "3") + getLongValue(qyjrlx, "4")); + res.put("jyz", getLongValue(qyjrlx, "5")); + res.put("gm", getLongValue(qyjrlx, "6") + getLongValue(qyjrlx, "7")); + res.put("aqsc", getLongValue(qyjrlx, "8") + getLongValue(qyjrlx, "9") + getLongValue(qyjrlx, "10")); + res.put("jzsg", enterpriseRepository.findQyjzsgtj()); + res.put("yy", enterpriseRepository.findQyyytj()); + return res; + } + + private Long getLongValue(List> dataList, String key) { + for (Map map : dataList) { + if (key.equals(map.get("industry_type").toString())) { + String value = map.get("num").toString(); + return StringUtil.isNotEmpty(value) ? Long.valueOf(value) : 0L; + } + } + return 0L; + } + + public Map getFxczfzs() { + Long sumNum = onlinePatrolRepository.getSumNum(); + LocalDateTime endTime = LocalDateTime.now(); + Long weekNum = onlinePatrolRepository.getNumByCreatTime(endTime.minusWeeks(1), endTime); + Long monthNum = onlinePatrolRepository.getNumByCreatTime(endTime.minusMonths(1), endTime); + Long yearNum = onlinePatrolRepository.getNumByCreatTime(endTime.minusYears(1), endTime); + Map res = new HashMap<>(); + res.put("sumNum", sumNum); + res.put("weekNum", weekNum); + res.put("monthNum", monthNum); + res.put("yearNum", yearNum); + return res; + } + + public List> getQyyjtj() { + List> res = enterpriseWarnRepository.getNumGroupByEventDesc(); + return res; + } + + public List> getFxczftj(String type) { + if ("1".equals(type)) { + return onlinePatrolRepository.getFxczftjByAgency(); + } else { + LocalDate currentDate = LocalDate.now(); + YearMonth yearMonth = YearMonth.from(currentDate).minusMonths(11); + LocalDateTime startTime = LocalDateTime.of(yearMonth.getYear(), yearMonth.getMonthValue(), 1, 0, 0); + LocalDateTime endTime = LocalDateTime.now(); + List months = IntStream.range(0, 12) + .mapToObj(i -> endTime.minusMonths(i)) + .sorted() // 按日期升序排序 + .map(date -> date.format(DateTimeFormatter.ofPattern("yyyy-MM"))) + .collect(Collectors.toList()); + List> fxczftj = onlinePatrolRepository.getfxczftjByMonth(startTime, endTime); + // 处理数据 + List> res = months.stream() + .map(month -> { + Map fxczftjMap = fxczftj.stream().filter(data -> month.equals(data.get("createTime"))).findFirst().orElse(null); + Map resultMap = new java.util.HashMap<>(); + resultMap.put("date", month); + resultMap.put("zs", fxczftjMap != null ? fxczftjMap.get("zs") : 0); // 默认值设为0 + return resultMap; + }) + .collect(Collectors.toList()); + return res; + } + } + +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/OfficerService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/OfficerService.java new file mode 100644 index 0000000..9ab5d51 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/OfficerService.java @@ -0,0 +1,296 @@ +package com.aisino.iles.lawenforcement.service; + +import cn.hutool.core.util.StrUtil; +import com.aisino.iles.common.util.PageableHelper; +import com.aisino.iles.common.util.StringUtils; +import com.aisino.iles.core.exception.BusinessError; +import com.aisino.iles.lawenforcement.model.Agency; +import com.aisino.iles.lawenforcement.model.Officer; +import com.aisino.iles.lawenforcement.model.Officer_; +import com.aisino.iles.lawenforcement.model.dto.OfficerDto; +import com.aisino.iles.lawenforcement.model.query.OfficerQuery; +import com.aisino.iles.lawenforcement.repository.AgencyRepository; +import com.aisino.iles.lawenforcement.repository.OfficerRepository; +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 java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * 执法人员服务类 + */ +@Service +public class OfficerService { + + private final OfficerRepository officerRepository; + private final AgencyRepository agencyRepo; + + public OfficerService(OfficerRepository officerRepository, + AgencyRepository agencyRepo) { + this.officerRepository = officerRepository; + this.agencyRepo = agencyRepo; + } + + /** + * 保存执法人员信息 + * + * @param officer 执法人员信息 + * @return 保存后的执法人员信息 + */ + @Transactional + public Officer saveOfficer(Officer officer) { + // 基础去空格与校验 + String name = StrUtil.trimToNull(officer.getOfficerName()); + String lawNo = StrUtil.trimToNull(officer.getLawNo()); + String certNo = StrUtil.trimToNull(officer.getCertificateNo()); + String agencyId = StrUtil.trimToNull(officer.getAgencyId()); + String contactPhone = StrUtil.trimToNull(officer.getContactPhone()); + + if (name == null) { + throw new IllegalArgumentException("执法人员姓名不能为空"); + } + if (lawNo == null) { + throw new IllegalArgumentException("执法号不能为空"); + } + if (agencyId == null) { + throw new IllegalArgumentException("所属执法机构不能为空"); + } + + // 机构存在性校验 + agencyRepo.findById(agencyId).orElseThrow(() -> new IllegalArgumentException("所属执法机构不存在")); + + officer.setOfficerName(name); + officer.setLawNo(lawNo); + officer.setCertificateNo(certNo); + officer.setAgencyId(agencyId); + officer.setContactPhone(contactPhone); + + boolean isCreate = StrUtil.isBlank(officer.getOfficerId()); + + // 执法号唯一性 + officerRepository.findByLawNo(lawNo) + .filter(existing -> isCreate || !existing.getOfficerId().equals(officer.getOfficerId())) + .ifPresent(e -> { + throw new IllegalStateException("执法号已存在"); + }); + + // 执法证号唯一性(可选字段:若传入则校验唯一) + if (StrUtil.isNotBlank(certNo)) { + officerRepository.findByCertificateNo(certNo) + .filter(existing -> isCreate || !existing.getOfficerId().equals(officer.getOfficerId())) + .ifPresent(e -> { + throw new IllegalStateException("执法证号已存在"); + }); + } + + Officer saved = officerRepository.save(officer); + // 填充瞬态机构字段,便于前端展示 + populateAgencyTransientFields(saved); + return saved; + } + + /** + * 批量保存执法人员信息 + * + * @param officers 执法人员信息列表 + * @return 保存后的执法人员信息列表 + */ + @Transactional + public List saveOfficers(List officers) { + return officerRepository.saveAll(officers); + } + + /** + * 根据ID查询执法人员信息 + * + * @param officerId 执法人员ID + * @return 执法人员信息 + */ + public Optional findOfficerById(String officerId) { + return officerRepository.findById(officerId, "officer-with-agency") + .map(o -> { + populateAgencyTransientFields(o); + return o; + }); + } + + /** + * 根据系统用户id查询执法人员信息 + * + * @param certificateNo 系统用户id + * @return 执法人员信息 + */ + public Optional findOfficerByCertificateNo(String certificateNo) { + return officerRepository.findWithAgencyByCertificateNo(certificateNo) + .map(o -> { + populateAgencyTransientFields(o); + return o; + }); + } + + /** + * 根据所属执法机构ID查询执法人员列表 + * + * @param agencyId 执法机构ID + * @return 执法人员列表 + */ + public List findOfficersByAgencyId(String agencyId) { + Optional agencyOptional = agencyRepo.findById(agencyId); + if (agencyOptional.isPresent()) { + String agencyCode = agencyOptional.get().getAgencyCode(); + return officerRepository.findByAgencyCodeLike(StringUtils.trimEven0(agencyCode) + "%"); + } else { + throw new BusinessError("不存在此执法机构ID【" + agencyId + "】"); + } + } + + /** + * 根据执法人员姓名模糊查询执法人员列表 + * + * @param officerName 执法人员姓名 + * @return 执法人员列表 + */ + public List findOfficersByOfficerName(String officerName) { + return officerRepository.findByOfficerNameContaining(officerName); + } + + /** + * 分页查询执法人员信息 + * + * @param officerQuery@return 分页执法人员信息 + */ + public Page findOfficersPage(OfficerQuery officerQuery) { + Page page = officerRepository.findAll( + buildSpec(officerQuery), + PageableHelper.buildPageRequest(officerQuery.page(), officerQuery.pageSize(), officerQuery.sort(), officerQuery.dir()), + "officer-with-agency" + ); + // 填充瞬态机构字段 + page.getContent().forEach(this::populateAgencyTransientFields); + return page; + } + + private Specification buildSpec(OfficerQuery query) { + return (root, q, builder) -> { + List predicates = Stream.of( + Optional.ofNullable(query.getOfficerId()) + .map(StrUtil::trimToNull) + .map(id -> builder.equal(root.get(Officer_.officerId), id)), + Optional.ofNullable(query.getOfficerName()) + .map(StrUtil::trimToNull) + .map(name -> builder.like(root.get(Officer_.officerName), "%" + name + "%")), + Optional.ofNullable(query.getLawNo()) + .map(StrUtil::trimToNull) + .map(no -> builder.equal(root.get(Officer_.lawNo), no)), + Optional.ofNullable(query.getCertificateNo()) + .map(StrUtil::trimToNull) + .map(no -> builder.equal(root.get(Officer_.certificateNo), no)), + Optional.ofNullable(query.getAgencyId()) + .map(StrUtil::trimToNull) + .map(aid -> builder.equal(root.get(Officer_.agencyId), aid)), + Optional.ofNullable(query.getContactPhone()) + .map(StrUtil::trimToNull) + .map(p -> builder.like(root.get(Officer_.contactPhone), "%" + p + "%")) + ).filter(Optional::isPresent) + .map(Optional::get) + .toList(); + return builder.and(predicates.toArray(new Predicate[0])); + }; + } + + /** + * 条件查询执法人员信息 + * + * @param spec 查询条件 + * @return 执法人员信息列表 + */ + public List findOfficersBySpec(Specification spec) { + return officerRepository.findAll(spec); + } + + + /** + * 根据ID删除执法人员信息 + * + * @param officerId 执法人员ID + */ + @Transactional + public void deleteOfficerById(String officerId) { + officerRepository.deleteById(officerId); + } + + /** + * 批量删除执法人员信息 + * + * @param officerIds 执法人员ID列表 + */ + @Transactional + public void deleteOfficersByIds(List officerIds) { + officerRepository.deleteAllById(officerIds); + } + + /** + * 检查执法人员是否存在 + * + * @param officerId 执法人员ID + * @return 是否存在 + */ + public boolean existsOfficerById(String officerId) { + return officerRepository.existsById(officerId); + } + + /** + * 执法号是否已存在 + * + * @param lawNo 执法号 + * @param excludeOfficerId 排除的执法人员ID(编辑场景传入自身ID) + * @return true 表示已存在;false 表示不存在 + */ + public boolean existsLawNo(String lawNo, String excludeOfficerId) { + String no = StrUtil.trimToNull(lawNo); + if (no == null) return false; + return officerRepository.findByLawNo(no) + .filter(o -> excludeOfficerId == null || !o.getOfficerId().equals(excludeOfficerId)) + .isPresent(); + } + + /** + * 获取执法人员总数 + * + * @return 执法人员总数 + */ + public long countOfficers() { + return officerRepository.count(); + } + + /** + * 查询执法人员列表 + * + * @param query 查询条件 + * @return 执法人员列表 + */ + public List listOfficers(OfficerQuery query) { + List list = officerRepository.findAll(buildSpec(query), "officer-with-agency"); + list.forEach(this::populateAgencyTransientFields); + return list; + } + + /** + * 填充机构相关的瞬态字段,便于前端直接展示 + */ + private void populateAgencyTransientFields(Officer officer) { + if (officer == null || officer.getAgency() == null) return; + Agency a = officer.getAgency(); + officer.setAgencyName(a.getAgencyName()); + officer.setAgencyCode(a.getAgencyCode()); + officer.setAgencySimpleCode(a.getAgencySimpleCode()); + officer.setAgencyLevel(a.getAgencyLevel() == null ? null : a.getAgencyLevel().toString()); + officer.setLeaf(a.getLeaf()); + } + +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/OnlinePatrolService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/OnlinePatrolService.java new file mode 100644 index 0000000..d29c1ed --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/OnlinePatrolService.java @@ -0,0 +1,225 @@ +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.PageableHelper; +import com.aisino.iles.core.exception.BusinessError; +import com.aisino.iles.lawenforcement.model.EnforceCheck; +import com.aisino.iles.lawenforcement.model.EnforcementInfo; +import com.aisino.iles.lawenforcement.model.OnlinePatrol; +import com.aisino.iles.lawenforcement.model.dto.OnlinePatrolDto; +import com.aisino.iles.lawenforcement.model.enums.FlowNode; +import com.aisino.iles.lawenforcement.model.query.OnlinePatrolQuery; +import com.aisino.iles.lawenforcement.repository.OnlinePatrolRepository; +import com.aisino.iles.lawenforcement.repository.*; +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 org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +@Service +public class OnlinePatrolService { + + private final OnlinePatrolRepository onlinePatrolRepository; + private final EnforcementInfoRepository enforcementInfoRepository; + private final EnforceCheckRepository enforceCheckRepository; + private final FtpService ftpService; + private final ExecutorService fileUploadExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); + + public OnlinePatrolService(OnlinePatrolRepository onlinePatrolRepository, + EnforcementInfoRepository enforcementInfoRepository, + EnforceCheckRepository enforceCheckRepository, + FtpService ftpService) { + this.onlinePatrolRepository = onlinePatrolRepository; + this.enforcementInfoRepository = enforcementInfoRepository; + this.enforceCheckRepository = enforceCheckRepository; + this.ftpService = ftpService; + } + + /** + * 保存在线巡查信息 + * + * @param onlinePatrolDto 在线巡查信息 + */ + @Transactional + public void saveOnlinePatrol(OnlinePatrolDto onlinePatrolDto) { + OnlinePatrol onlinePatrol = new OnlinePatrol(); + onlinePatrol.setEnterpriseId(onlinePatrolDto.getEnterpriseId()); + onlinePatrol.setAgencyId(onlinePatrolDto.getAgencyId()); + onlinePatrol.setIsNormal(onlinePatrolDto.getIsNormal()); + onlinePatrol.setDescription(onlinePatrolDto.getDescription()); + onlinePatrol.setCreateTime(onlinePatrolDto.getCreateTime()); + onlinePatrol.setApprovalStatus("0"); + onlinePatrol.setCreateUserId(onlinePatrolDto.getCreateUserId()); + onlinePatrol.setCreateUserName(onlinePatrolDto.getCreateUserName()); + MultipartFile[] files = onlinePatrolDto.getFiles(); + if (files != null && files.length > 0) { + List> list = uploadAllFiles(files); + onlinePatrol.setAnnexs(list); + } + onlinePatrolRepository.save(onlinePatrol); + } + + // 上传所有文件并返回结果 + private List> uploadAllFiles(MultipartFile[] files) { + // 1. 转换为List并过滤空文件 + List validFiles = Arrays.stream(files).filter(file -> !file.isEmpty()).collect(Collectors.toList()); + + // 2. 创建上传任务 + List>> uploadFutures = validFiles.stream().map(this::uploadFile).collect(Collectors.toList()); + + // 3. 合并所有Future + CompletableFuture allFutures = CompletableFuture.allOf(uploadFutures.toArray(new CompletableFuture[0])); + + // 4. 获取所有结果 + return allFutures.thenApply(v -> uploadFutures.stream().map(CompletableFuture::join).collect(Collectors.toList())).join(); // 在当前线程等待完成 + } + + // 单个文件上传方法 + private CompletableFuture> uploadFile(MultipartFile file) { + return CompletableFuture.supplyAsync(() -> { + try { + String originalFilename = file.getOriginalFilename(); + String fileExtension = getFileExtension(originalFilename); + + // 上传文件 + String url = ftpService.uploadTempFile(IndustryCategoryForFile.pub, originalFilename, file.getInputStream()); + + if (!StringUtils.hasText(url)) { + throw new BusinessError("文件上传失败: " + originalFilename); + } + + // 构建返回结果 + Map result = new HashMap<>(); + result.put("name", originalFilename); + result.put("type", fileExtension); + result.put("savePathName", url); + result.put("downloadUrl", ftpService.getFileUrl(url)); + result.put("size", file.getSize()); + + return result; + } catch (Exception e) { + throw new BusinessError("文件上传异常: " + file.getOriginalFilename(), e); + } + }, fileUploadExecutor); // 使用专用线程池 + } + + // 获取文件扩展名 + private String getFileExtension(String filename) { + if (filename == null) { + return ""; + } + int lastDotIndex = filename.lastIndexOf('.'); + return lastDotIndex == -1 ? "" : filename.substring(lastDotIndex + 1); + } + + /** + * 分页查询在线巡查信息 + * + * @param query@return 分页在线巡查信息 + */ + @Transactional(readOnly = true) + public Page findOnlinePatrolPage(OnlinePatrolQuery query) { + return onlinePatrolRepository + .findAll(buildSpecification(query), PageableHelper.buildPageRequest(query.page(), query.pageSize(), "createTime", "desc")) + .map(this::handleResult); + } + + private Specification buildSpecification(OnlinePatrolQuery query) { + return Specification.where((root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); +// predicates.add(criteriaBuilder.equal(root.get("approvalStatus"), "0")); + Optional.ofNullable(query.getIndustryType()).ifPresent(o -> predicates.add(criteriaBuilder.equal(root.get("enterprise").get("industryType"), o))); + Optional.ofNullable(query.getUnitName()).ifPresent(o -> predicates.add(criteriaBuilder.like(root.get("enterprise").get("unitName"), "%"+ com.aisino.iles.common.util.StringUtils.trimEven0(o) + "%"))); + Optional.ofNullable(query.getUnifiedSocialCode()).ifPresent(o -> predicates.add(criteriaBuilder.like(root.get("enterprise").get("unifiedSocialCode"), com.aisino.iles.common.util.StringUtils.trimEven0(o) + "%"))); +// Optional.ofNullable(query.getCreateTimeArr()).filter(f -> f.length == 2).map(f -> { +// List ts = new ArrayList<>(); +// Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get(EnforcementInfo_.createTime), from)).ifPresent(ts::add); +// Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get(EnforcementInfo_.createTime), to)).ifPresent(ts::add); +// return ts; +// }).ifPresent(predicates::addAll); + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }); + } + + private OnlinePatrol handleResult(OnlinePatrol onlinePatrol) { + Optional.ofNullable(onlinePatrol.getEnterprise()).ifPresent(enterprise -> enterprise.getUnitName()); + Optional.ofNullable(onlinePatrol.getAgency()).ifPresent(agency -> agency.getAgencyName()); + List> annexs = onlinePatrol.getAnnexs(); + if (annexs != null) { + annexs.forEach(annex -> { + String savePathName = annex.get("savePathName").toString(); + String fileUrl = ftpService.getFileUrl(savePathName); + annex.put("downloadUrl", fileUrl); + }); + onlinePatrol.setAnnexs(annexs); + } + return onlinePatrol; + } + + + /** + * 保存在线巡查信息 + * + * @param onlinePatrolDto 在线巡查审批信息 + */ + @Transactional + public void saveOnlinePatrolApproval(OnlinePatrolDto onlinePatrolDto, RemoteUserInfo user) { + String approvalStatus = onlinePatrolDto.getApprovalStatus(); + if ("1".equals(approvalStatus)) { + EnforcementInfo enforcementInfo = new EnforcementInfo(); + enforcementInfo.setEnterpriseId(onlinePatrolDto.getEnterpriseId()); + enforcementInfo.setAgencyId(onlinePatrolDto.getAgencyId()); + enforcementInfo.setCurrentNodeCode(FlowNode.plan_approval); + enforcementInfo.setCurrentNode("方案待审批"); + enforcementInfo.setDataFrom("7"); + enforcementInfo.setCreateTime(LocalDateTime.now()); + enforcementInfoRepository.save(enforcementInfo); + EnforceCheck enforceCheck = new EnforceCheck(); + Optional.ofNullable(onlinePatrolDto.getCheckItemIds()).ifPresent(ids -> enforceCheck.setCheckItemIds(String.join(",", ids))); + enforceCheck.setCheckType(onlinePatrolDto.getCheckType()); + enforceCheck.setEnforcementId(enforcementInfo.getEnforcementId()); + enforceCheck.setCreateTime(LocalDateTime.now()); + enforceCheck.setCheckStatus("1"); + enforceCheck.setCheckFlag("1"); + enforceCheck.setWriterId(user.getYhwybs()); + enforceCheck.setCreatedBy(user.getXm()); + enforceCheck.setCreatedAccountBy(user.getYhwybs()); + enforceCheckRepository.save(enforceCheck); + onlinePatrolRepository + .findById(onlinePatrolDto.getOnlinePatrolId()) + .ifPresent(onlinePatrol -> { + onlinePatrol.setApprovalStatus("1"); + onlinePatrol.setApprovalUserId(onlinePatrolDto.getApprovalUserId()); + onlinePatrol.setApprovalUserName(onlinePatrolDto.getApprovalUserName()); + onlinePatrol.setApprovalReceipt(onlinePatrolDto.getApprovalReceipt()); + onlinePatrol.setIsCreateEnforce("1"); + onlinePatrol.setEnforcementId(enforcementInfo.getEnforcementId()); + onlinePatrolRepository.save(onlinePatrol); + }); + } else { + onlinePatrolRepository + .findById(onlinePatrolDto.getOnlinePatrolId()) + .ifPresent(onlinePatrol -> { + onlinePatrol.setApprovalStatus("2"); + onlinePatrol.setApprovalUserId(onlinePatrolDto.getApprovalUserId()); + onlinePatrol.setApprovalUserName(onlinePatrolDto.getApprovalUserName()); + onlinePatrol.setApprovalReceipt(onlinePatrolDto.getApprovalReceipt()); + onlinePatrol.setIsCreateEnforce("2"); + onlinePatrolRepository.save(onlinePatrol); + }); + } + } + +}