From b3798bcb206ef0aac3559ab3b7a52c9a115e3d42 Mon Sep 17 00:00:00 2001 From: Zhangchaoyang02 Date: Fri, 28 Feb 2025 17:14:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9C=8D=E5=8A=A1=E7=AB=AF?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AuthController.java | 113 ++++++ .../AutoEnforcementPlanController.java | 127 +++++++ .../repository/AccidentHazardRepository.java | 9 + .../AdministrativeLicenseRepository.java | 12 + .../AutoEnforcementPlanRepository.java | 10 + .../lawenforcement/service/AuthService.java | 356 ++++++++++++++++++ .../service/AutoEnforcementPlanService.java | 187 +++++++++ 7 files changed, 814 insertions(+) create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/controller/AuthController.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/controller/AutoEnforcementPlanController.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/repository/AccidentHazardRepository.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/repository/AdministrativeLicenseRepository.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/repository/AutoEnforcementPlanRepository.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/service/AuthService.java create mode 100644 server/src/main/java/com/aisino/iles/lawenforcement/service/AutoEnforcementPlanService.java diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/controller/AuthController.java b/server/src/main/java/com/aisino/iles/lawenforcement/controller/AuthController.java new file mode 100644 index 0000000..01c9b10 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/controller/AuthController.java @@ -0,0 +1,113 @@ +package com.aisino.iles.lawenforcement.controller; + +import com.aisino.iles.common.model.Fail; +import com.aisino.iles.common.model.Ok; +import com.aisino.iles.common.model.Result; +import com.aisino.iles.core.annotation.CurrentUser; +import com.aisino.iles.lawenforcement.service.AuthService; +import com.smartlx.sso.client.model.AccessToken; +import com.smartlx.sso.client.model.RemoteUserInfo; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.io.UnsupportedEncodingException; + +/** + * 支撑系统/整合统一认证 + */ +@RestController +@RequestMapping("/lawenforcement/v1/auth") +@Slf4j +public class AuthController { + private final AuthService authService; + + public AuthController(AuthService authService) { + this.authService = authService; + } + + /** + * 通过Authorization请求头获取用户信息 + * + * @param authorization Bearer token + * @return 用户信息 + */ + @GetMapping("/getSysUser") + public Result getUserInfo(@RequestHeader(name = "Authorization") String authorization) { + RemoteUserInfo userInfo = authService.getUserInfo(authorization); + return Ok.of(userInfo); + } + + /** + * 通过授权码获取token + * + * @param code 授权码 + * @return token + * @throws UnsupportedEncodingException + */ + @PostMapping("/login") + public Result login(String code) throws UnsupportedEncodingException { + AccessToken accessToken = authService.login(code); +// if ("NBH".equals(accessToken.getError())) +// return Fail.of("请去工作台维护个人信息,添加执法证号"); + return Ok.of(accessToken); + } + + /** + * 系统级别退出登录 + * 通过POST请求将session置为无效 + * + * @return Ok + */ + @PostMapping("/sysLogout") + public Result sysLogout(@RequestHeader(name = "Authorization") String authorization) { + return Ok.of(authService.sysLogout(authorization)); + } + + /** + * 退出登录 + * + * @param accessToken 令牌 + * @param userInfo 用户信息 + * @return Ok + */ + @PostMapping("/logout") + public Result logout(String accessToken, @CurrentUser RemoteUserInfo userInfo) { + authService.logout(accessToken, userInfo); + return Ok.of(); + } + + /** + * 通过GET请求获取登录URL + * + * @return map client_id and redirect_uri + */ + @GetMapping("/getLoginUrl") + public Result getLoginUrl() { + return Ok.of(authService.getLoginUrl()); + } + + /** + * 刷新令牌 + * + * @param refreshToken 刷新令牌 + * @return 新的访问令牌 + */ + @PostMapping("/refreshToken") + public Result refreshToken(String refreshToken) { + AccessToken response = authService.refreshToken(refreshToken); + return Ok.of(response); + } + + /** + * 通过手机号码获取令牌 + * + */ + @SneakyThrows + @PostMapping("/backend-token") + public Result backendToken(String mobilePhone) { + AccessToken response = authService.getTokenBackend(mobilePhone); + return Ok.of(response); + } +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/controller/AutoEnforcementPlanController.java b/server/src/main/java/com/aisino/iles/lawenforcement/controller/AutoEnforcementPlanController.java new file mode 100644 index 0000000..e504b27 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/controller/AutoEnforcementPlanController.java @@ -0,0 +1,127 @@ +package com.aisino.iles.lawenforcement.controller; + +import com.aisino.iles.common.model.Fail; +import com.aisino.iles.common.model.Ok; +import com.aisino.iles.common.model.PageResult; +import com.aisino.iles.common.model.Result; +import com.aisino.iles.common.util.Constants; +import com.aisino.iles.core.annotation.CurrentUser; +import com.aisino.iles.core.model.User; +import com.aisino.iles.lawenforcement.model.AutoEnforcementPlan; +import com.aisino.iles.lawenforcement.model.query.AutoEnforcementPlanQuery; +import com.aisino.iles.lawenforcement.service.AutoEnforcementPlanService; +import com.smartlx.sso.client.model.RemoteUserInfo; +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 综合执法/自动执法计划信息 + */ +@RestController +@RequestMapping(Constants.API_PREFIX + "/lawenforcement/autoEnforcementPlans") +public class AutoEnforcementPlanController { + + private final AutoEnforcementPlanService autoEnforcementPlanService; + + public AutoEnforcementPlanController(AutoEnforcementPlanService autoEnforcementPlanService) { + this.autoEnforcementPlanService = autoEnforcementPlanService; + } + + /** + * 创建自动执法计划 + * + * @param autoEnforcementPlan 自动执法计划 + * @return 创建结果 + */ + @PostMapping + public Result createAutoEnforcementPlan(@RequestBody AutoEnforcementPlan autoEnforcementPlan, @CurrentUser RemoteUserInfo user) { + return Ok.of(autoEnforcementPlanService.saveAutoEnforcementPlan(autoEnforcementPlan, user, "add")); + } + + /** + * 根据ID查询自动执法计划 + * + * @param planId 企业ID + * @return 自动执法计划 + */ + @GetMapping("/{planId}") + public Result getAutoEnforcementPlanById(@PathVariable String planId) { + return autoEnforcementPlanService.findAutoEnforcementPlanById(planId) + .map(e -> ((Result) Ok.of(e))) + .orElse(Fail.of("自动执法计划不存在")); + } + + + /** + * 分页查询自动执法计划 + * + * @param query 查询条件 + * @return 分页自动执法计划 + */ + @GetMapping + public PageResult getAutoEnforcementPlansPage(AutoEnforcementPlanQuery query) { + Page page = autoEnforcementPlanService.findAutoEnforcementPlansPage(query); + return PageResult.of(page); + } + + /** + * 更新自动执法计划 + * + * @param planId 企业ID + * @param autoEnforcementPlan 自动执法计划 + * @return 更新结果 + */ + @PutMapping("/{planId}") + public Result updateAutoEnforcementPlan(@PathVariable String planId, @RequestBody AutoEnforcementPlan autoEnforcementPlan, @CurrentUser RemoteUserInfo user) { + if (!autoEnforcementPlanService.existsAutoEnforcementPlanById(planId)) { + return Fail.of("自动执法计划不存在"); + } + autoEnforcementPlan.setPlanId(planId); + return Ok.of(autoEnforcementPlanService.saveAutoEnforcementPlan(autoEnforcementPlan, user, "edit")); + } + + /** + * 根据ID删除自动执法计划 + * + * @param planId 企业ID + * @return 删除结果 + */ + @DeleteMapping("/{planId}") + public Result deleteAutoEnforcementPlanById(@PathVariable String planId) { + if (!autoEnforcementPlanService.existsAutoEnforcementPlanById(planId)) { + return Fail.of("自动执法计划不存在"); + } + autoEnforcementPlanService.deleteAutoEnforcementPlanById(planId); + return Ok.of(); + } + + /** + * 批量删除自动执法计划 + * + * @param planIds 企业ID列表 + * @return 删除结果 + */ + @DeleteMapping + public Result deleteAutoEnforcementPlansByIds(@RequestBody List planIds) { + autoEnforcementPlanService.deleteAutoEnforcementPlansByIds(planIds); + return Ok.of(); + } + + /** + * 派发 + * + * @param planId 企业ID + * @param autoEnforcementPlan 自动执法计划 + * @return 更新结果 + */ + @PutMapping("/dispatched/{planId}") + public Result dispatchedAutoEnforcementPlan(@PathVariable String planId, @RequestBody AutoEnforcementPlan autoEnforcementPlan, @CurrentUser RemoteUserInfo user) { + if (!autoEnforcementPlanService.existsAutoEnforcementPlanById(planId)) { + return Fail.of("自动执法计划不存在"); + } + autoEnforcementPlan.setPlanId(planId); + return Ok.of(autoEnforcementPlanService.saveAutoEnforcementPlan(autoEnforcementPlan, user, "dispatched")); + } +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/repository/AccidentHazardRepository.java b/server/src/main/java/com/aisino/iles/lawenforcement/repository/AccidentHazardRepository.java new file mode 100644 index 0000000..e44d3a8 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/repository/AccidentHazardRepository.java @@ -0,0 +1,9 @@ +package com.aisino.iles.lawenforcement.repository; + +import com.aisino.iles.core.repository.BaseRepo; +import com.aisino.iles.lawenforcement.model.AccidentHazard; +import org.springframework.stereotype.Repository; + +@Repository +public interface AccidentHazardRepository extends BaseRepo { +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/repository/AdministrativeLicenseRepository.java b/server/src/main/java/com/aisino/iles/lawenforcement/repository/AdministrativeLicenseRepository.java new file mode 100644 index 0000000..3082d70 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/repository/AdministrativeLicenseRepository.java @@ -0,0 +1,12 @@ +package com.aisino.iles.lawenforcement.repository; + +import com.aisino.iles.core.repository.BaseRepo; +import com.aisino.iles.lawenforcement.model.AdministrativeLicense; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface AdministrativeLicenseRepository extends BaseRepo{ + List findByEnterpriseId(String enterpriseId); +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/repository/AutoEnforcementPlanRepository.java b/server/src/main/java/com/aisino/iles/lawenforcement/repository/AutoEnforcementPlanRepository.java new file mode 100644 index 0000000..2a30930 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/repository/AutoEnforcementPlanRepository.java @@ -0,0 +1,10 @@ +package com.aisino.iles.lawenforcement.repository; + +import com.aisino.iles.core.repository.BaseRepo; +import com.aisino.iles.lawenforcement.model.AutoEnforcementPlan; +import org.springframework.stereotype.Repository; + +@Repository +public interface AutoEnforcementPlanRepository extends BaseRepo { + +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/AuthService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/AuthService.java new file mode 100644 index 0000000..97094ce --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/AuthService.java @@ -0,0 +1,356 @@ +package com.aisino.iles.lawenforcement.service; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.aisino.iles.common.util.Constants; +import com.aisino.iles.core.util.RedisUtil; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.smartlx.sso.client.model.AccessToken; +import com.smartlx.sso.client.model.RemoteUserInfo; +import com.smartlx.sso.client.properties.SsoClientProperties; +import com.smartlx.sso.client.result.Result; +import com.smartlx.sso.client.service.SsoClientService; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RestTemplate; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +/** + * 认证服务 + * 处理用户认证、登录、登出等相关业务逻辑 + */ +@Service +@Slf4j +public class AuthService { + private final SsoClientService ssoClientService; + private final SsoClientProperties ssoClientProperties; + private final RestTemplate restTemplate; + private final ObjectMapper objectMapper; + private final String backendTokenUrl; + private final String agencyArr; + + public AuthService(SsoClientService ssoClientService, SsoClientProperties ssoClientProperties, + RestTemplate restTemplate, + ObjectMapper objectMapper, + @Value("${third-party.enterprise.token}") String backendTokenUrl, + @Value("${third-party.agency-arr}") String agencyArr) { + this.ssoClientService = ssoClientService; + this.ssoClientProperties = ssoClientProperties; + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + this.backendTokenUrl = backendTokenUrl; + this.agencyArr = agencyArr; + } + + /** + * 通过Authorization获取用户信息 + * + * @param authorization Bearer token + * @return 用户信息 + */ + @SneakyThrows + public RemoteUserInfo getUserInfo(String authorization) { + AccessToken accessToken = new AccessToken(); + accessToken.setAccess_token(authorization.split("Bearer ")[1]); + RemoteUserInfo userInfo = ssoClientService.getRemoteUserInfo(accessToken); + if (StringUtils.hasText(userInfo.getGajgjgdm()) && this.agencyArr.contains(userInfo.getGajgjgdm())) + userInfo.setGajgjgdm("01610100000000000"); + return userInfo; + } + + /** + * 通过授权码获取token + * + * @param code 授权码 + * @return 访问令牌 + */ + @SneakyThrows + public AccessToken login(String code) { + log.debug("通过授权码获取token, code:{}", code); + com.smartlx.sso.client.result.Result accessTokenResult = ssoClientService.getAccessToken(code); + AccessToken accessToken = accessTokenResult.getData(); + cacheUserInfo(accessToken); + return accessToken; + } + + /** + * 系统级别退出登录 + * 通过POST请求将session置为无效 + * + * @param authorization 授权头 + * @return 响应结果 + */ + public Map sysLogout(String authorization) { + String url = String.format("%s/clients/sysLogout", ssoClientProperties.getAuthorizeServer()); + RequestEntity requestEntity = RequestEntity.post(url) + .header("Authorization", authorization.startsWith("Bearer ") ? authorization : "Bearer " + authorization) + .build(); + ResponseEntity> responseEntity = restTemplate.exchange(requestEntity, new ParameterizedTypeReference<>() { + }); + + log.debug("sysLogout response:{}", responseEntity.getBody()); + return responseEntity.getBody(); + } + + /** + * 退出登录 + * + * @param accessToken 令牌 + * @param userInfo 用户信息 + */ + @SneakyThrows + public void logout(String accessToken, RemoteUserInfo userInfo) { + if (StrUtil.isNotBlank(accessToken)) { + AccessToken accessTokenObj = new AccessToken(); + accessTokenObj.setAccess_token(accessToken); + RemoteUserInfo userInfoResult = ssoClientService.getRemoteUserInfo(accessTokenObj); + if (userInfoResult != null) { + userInfo = userInfoResult; + } + } + + Optional.ofNullable(userInfo).ifPresent(u -> { + RedisUtil.del(StrUtil.format(Constants.RedisKeyPrefix.userInfo.getValue(), u.getYhwybs())); + sysLogout(u.getAccessToken().getAccess_token()); + }); + } + + /** + * 获取登录URL参数 + * + * @return 包含client_id和redirect_uri的Map + */ + public Map getLoginUrl() { + return Map.of("client_id", ssoClientProperties.getClientId(), + "redirect_uri", ssoClientProperties.getRedirectUri()); + } + + /** + * 刷新令牌 + * + * @param refreshToken 刷新令牌 + * @return 新的访问令牌 + */ + public AccessToken refreshToken(String refreshToken) { + log.debug("刷新令牌, refreshToken:{}", refreshToken); + + // 构建请求参数 + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("grant_type", "refresh_token"); + params.add("refresh_token", refreshToken); + params.add("client_id", ssoClientProperties.getClientId()); + params.add("client_secret", ssoClientProperties.getClientSecret()); + + // 创建请求实体 + RequestEntity> requestEntity = RequestEntity.post(ssoClientProperties.getTokenUrl()) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body(params); + + // 发送请求到SSO服务器 + Result response = restTemplate.exchange(requestEntity, new ParameterizedTypeReference>() { + }).getBody(); + + // 如果刷新成功,更新用户信息缓存 + if (response != null && response.getData() != null) { + try { + cacheUserInfo(response.getData()); + return response.getData(); + } catch (Exception e) { + log.error("刷新令牌后获取用户信息失败", e); + } + } + return null; + } + + /** + * 缓存用户信息 + * + * @param accessToken 访问令牌 + */ + private void cacheUserInfo(AccessToken accessToken) { + try { + RemoteUserInfo userInfo = ssoClientService.getRemoteUserInfo(accessToken); + if (!StringUtils.hasText(userInfo.getZfzjbh())) { + accessToken.setError("NBH"); + } + if (StringUtils.hasText(userInfo.getGajgjgdm()) && this.agencyArr.contains(userInfo.getGajgjgdm())) + userInfo.setGajgjgdm("01610100000000000"); + userInfo.setAccessToken(accessToken); + RedisUtil.set( + StrUtil.format(Constants.RedisKeyPrefix.userInfo.getValue(), userInfo.getYhwybs()), + userInfo, + Duration.ofSeconds(accessToken.getExpires_in()) + ); + } catch (Exception e) { + log.error("缓存用户信息失败", e); + } + } + + /** + * 通过指定URL刷新token + * + * @param accessToken 访问令牌 + * @param tokenType 令牌类型 + * @param refreshToken 刷新令牌 + * @param yddh 移动电话 + * @throws Exception 异常信息 + */ + public void refreshTokenBackend(String accessToken, String tokenType, String refreshToken, String yddh) throws Exception { + // 异步执行刷新 + CompletableFuture.runAsync(() -> { + try { + log.info("后台开始刷新令牌,移动电话:{}", yddh); + String res = HttpUtil.createPost(backendTokenUrl) + .header("Content-Type", "application/json") + .body("{\"clientId\": \"" + ssoClientProperties.getClientId() + + "\",\"clientSecret\": \"" + ssoClientProperties.getClientSecret() + + "\",\"grantType\": \"refresh_token\",\"refreshToken\": \"" + refreshToken + "\"}") + .execute() + .body(); + + AccessToken newAccessToken = parseTokenResponse(res); + if (newAccessToken != null) { + saveCacheBackendToken(newAccessToken, yddh); + log.info("后台令牌刷新成功,移动电话:{}", yddh); + } else { + log.error("后台令牌刷新失败,移动电话:{}。响应:{}", yddh, res); + } + } catch (Exception e) { + log.error("后台刷新令牌异常,移动电话:{}", yddh, e); + } + }); + } + + /** + * 通过移动电话获取token + * + * @param yddh 移动电话 + * @return AccessToken对象 + * @throws Exception 异常信息 + */ + public AccessToken getTokenBackend(String yddh) throws Exception { + // 先从Redis缓存中获取令牌 + String cacheKey = String.format(Constants.RedisKeyPrefix.backendToken.getValue(), yddh); + AccessToken cachedToken = RedisUtil.get(cacheKey, AccessToken.class); + + if (cachedToken != null) { + AccessToken accessToken = cachedToken; + // 检查令牌是否即将过期(例如,在过期前5分钟内),如果是,则在后台刷新 + if (isTokenExpiring(accessToken)) { + // 异步刷新令牌 + refreshTokenBackend(accessToken.getAccess_token(), accessToken.getToken_type(), accessToken.getRefresh_token(), yddh); + } + return accessToken; + } + + // 缓存中不存在,从远程获取 + log.info("缓存中不存在后台令牌,从远程获取,移动电话:{}", yddh); + String res = HttpUtil.createPost(backendTokenUrl) + .header("Content-Type", "application/json") + .body("{\"clientId\": \"" + ssoClientProperties.getClientId() + + "\",\"clientSecret\": \"" + ssoClientProperties.getClientSecret() + + "\",\"yddh\": \"" + yddh + "\"}") + .execute() + .body(); + log.info("获取token结果:{}", res); + + AccessToken accessToken = parseTokenResponse(res); + + if (accessToken != null) { + // 使用API返回的expires_in值,如果存在的话 + if (accessToken.getExpires_in() == null) { + accessToken.setExpires_in(7200L); // 默认2小时 + } + saveCacheBackendToken(accessToken, yddh); + return accessToken; + } else { + log.error("获取后台令牌失败,移动电话:{}。响应:{}", yddh, res); + throw new Exception("获取后台令牌失败: " + res); + } + } + + /** + * 解析token响应 + * + * @param response 响应字符串 + * @return AccessToken对象,如果解析失败则返回null + */ + private AccessToken parseTokenResponse(String response) { + try { + JsonNode tokenNode = objectMapper.readValue(response, JsonNode.class); + if (tokenNode.has("code") && 200 == tokenNode.get("code").asInt() && tokenNode.has("data")) { + JsonNode tokenData = tokenNode.get("data"); + if (tokenData != null && tokenData.has("access_token") && tokenData.has("token_type") && tokenData.has("refresh_token")) { + AccessToken accessToken = new AccessToken(); + accessToken.setAccess_token(tokenData.get("access_token").asText()); + accessToken.setToken_type(tokenData.get("token_type").asText()); + accessToken.setRefresh_token(tokenData.get("refresh_token").asText()); + // 如果有expires_in字段,则设置过期时间 + if (tokenData.has("expires_in")) { + accessToken.setExpires_in(tokenData.get("expires_in").asLong()); + } else { + // 默认1小时过期 + accessToken.setExpires_in(3600L); + } + return accessToken; + } + } + log.error("解析token响应失败,响应格式不符合预期: {}", response); + return null; + } catch (Exception e) { + log.error("解析token响应异常", e); + return null; + } + } + + /** + * 保存后台令牌到缓存 + * + * @param accessToken 令牌 + * @param yddh 移动电话 + */ + private void saveCacheBackendToken(AccessToken accessToken, String yddh) { + String cacheKey = String.format(Constants.RedisKeyPrefix.backendToken.getValue(), yddh); + // 缓存时间略短于实际过期时间,以触发刷新 + long expire = accessToken.getExpires_in() - 300; + RedisUtil.set(cacheKey, accessToken, Duration.of(expire, ChronoUnit.SECONDS)); + } + + /** + * 检查令牌是否即将过期 + * + * @param accessToken 访问令牌 + * @return 如果令牌即将过期则返回true + */ + private boolean isTokenExpiring(AccessToken accessToken) { + // 令牌在过期前5分钟内被认为是即将过期 + return accessToken.getExpires_in() <= 300; + } + + /** + * 从上下文中提取身份证号 + * 这是一个示例方法,实际实现可能需要根据具体业务逻辑调整 + * + * @return 身份证号 + */ + private String extractIdnoFromContext() { + // 实际实现可能需要从请求上下文、ThreadLocal或其他地方获取身份证号 + // 这里仅作为示例 + return null; + } +} diff --git a/server/src/main/java/com/aisino/iles/lawenforcement/service/AutoEnforcementPlanService.java b/server/src/main/java/com/aisino/iles/lawenforcement/service/AutoEnforcementPlanService.java new file mode 100644 index 0000000..54d7927 --- /dev/null +++ b/server/src/main/java/com/aisino/iles/lawenforcement/service/AutoEnforcementPlanService.java @@ -0,0 +1,187 @@ +package com.aisino.iles.lawenforcement.service; + + +import com.aisino.iles.common.util.PageableHelper; +import com.aisino.iles.lawenforcement.model.AutoEnforcementPlan; +import com.aisino.iles.lawenforcement.model.AutoEnforcementPlan_; +import com.aisino.iles.lawenforcement.model.Enterprise; +import com.aisino.iles.lawenforcement.model.dto.EnforcementInfoDto; +import com.aisino.iles.lawenforcement.model.query.AutoEnforcementPlanQuery; +import com.aisino.iles.lawenforcement.repository.AutoEnforcementPlanRepository; +import com.aisino.iles.lawenforcement.repository.EnterpriseRepository; +import com.smartlx.sso.client.model.RemoteUserInfo; +import jakarta.persistence.criteria.Predicate; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +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.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * 自动执法计划服务类 + */ +@Service +public class AutoEnforcementPlanService { + private final AutoEnforcementPlanRepository autoEnforcementPlanRepo; + private final EnterpriseRepository enterpriseRepo; + private final EnforcementInfoService enforcementInfoService; + + public AutoEnforcementPlanService(AutoEnforcementPlanRepository autoEnforcementPlanRepo, + EnterpriseRepository enterpriseRepo, + EnforcementInfoService enforcementInfoService) { + this.autoEnforcementPlanRepo = autoEnforcementPlanRepo; + this.enterpriseRepo = enterpriseRepo; + this.enforcementInfoService = enforcementInfoService; + } + + /** + * 保存自动执法计划 + * + * @param autoEnforcementPlan 自动执法计划 + * @return 保存后的自动执法计划 + */ + @Transactional + public AutoEnforcementPlan saveAutoEnforcementPlan(AutoEnforcementPlan autoEnforcementPlan, RemoteUserInfo user, String type) { + LocalDateTime now = LocalDateTime.now(); + if ("add".equals(type)) { + autoEnforcementPlan.setEntryTime(now); + autoEnforcementPlan.setTaskStatus("pending"); + } else if ("dispatched".equals(type)) { + if (StringUtils.hasText(autoEnforcementPlan.getEnterpriseIds())) {//派发生成执法信息 + String[] ids = autoEnforcementPlan.getEnterpriseIds().split(","); + EnforcementInfoDto enforcementInfoDto = new EnforcementInfoDto(); + enforcementInfoDto.setEnterpriseIds(List.of(ids)); + enforcementInfoDto.setDataFrom("4"); + enforcementInfoDto.setEnforcementName(autoEnforcementPlan.getTaskName()); + enforcementInfoDto.setEnforcementContent(autoEnforcementPlan.getTaskDescription()); + enforcementInfoDto.setEnforcementTime(new LocalDate[]{autoEnforcementPlan.getTaskDateFrom(), autoEnforcementPlan.getTaskDateTo()}); + enforcementInfoDto.setPlanId(autoEnforcementPlan.getPlanId()); + enforcementInfoDto.setPlanType(autoEnforcementPlan.getKind()); // 1:重点检查企业清单,2:双重双随机一公开清单 + enforcementInfoService.saveEnforcementInfo(enforcementInfoDto, user); + } + autoEnforcementPlan.setTaskStatus("dispatched"); + autoEnforcementPlan.setDistTime(now); + } + return autoEnforcementPlanRepo.save(autoEnforcementPlan); + } + + /** + * 批量保存自动执法计划 + * + * @param autoEnforcementPlans 自动执法计划列表 + * @return 保存后的自动执法计划列表 + */ + @Transactional + public List saveAutoEnforcementPlans(List autoEnforcementPlans) { + return autoEnforcementPlanRepo.saveAll(autoEnforcementPlans); + } + + /** + * 根据ID查询自动执法计划 + * + * @param planId 自动执法计划ID + * @return 自动执法计划 + */ + public Optional findAutoEnforcementPlanById(String planId) { + return autoEnforcementPlanRepo.findById(planId).map(o -> { + Optional.ofNullable(o.getEnterpriseIds()).filter(StringUtils::hasText).ifPresent(oo -> { + String[] ls = oo.split(","); + List enterprises = enterpriseRepo.findAllById(List.of(ls)); + o.setEnterpriseList(enterprises); + }); + return o; + }); + } + + /** + * 查询所有自动执法计划 + * + * @return 自动执法计划列表 + */ + public List findAllAutoEnforcementPlans() { + return autoEnforcementPlanRepo.findAll(); + } + + /** + * 分页查询自动执法计划 + * + * @param pageRequest 分页请求 + * @return 分页自动执法计划 + */ + public Page findAutoEnforcementPlansPage(PageRequest pageRequest) { + return autoEnforcementPlanRepo.findAll(pageRequest); + } + + /** + * 根据查询条件分页查询自动执法计划 + * + * @param query 查询条件 + * @return 分页自动执法计划 + */ + public Page findAutoEnforcementPlansPage(AutoEnforcementPlanQuery query) { + return autoEnforcementPlanRepo.findAll(buildSpecification(query), PageableHelper.buildPageRequest(query.page(), query.pageSize(), query.sort(), query.dir())); + } + + /** + * 构建查询条件 + * + * @param query 查询条件 + * @return 规格 + */ + private Specification buildSpecification(AutoEnforcementPlanQuery query) { + return (root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + Optional.ofNullable(query.getTaskName()).filter(StringUtils::hasText).ifPresent(o -> predicates.add(criteriaBuilder.like(root.get(AutoEnforcementPlan_.taskName), "%" + o + "%"))); + Optional.ofNullable(query.getTaskDescription()).filter(StringUtils::hasText).ifPresent(o -> predicates.add(criteriaBuilder.like(root.get(AutoEnforcementPlan_.taskDescription), "%" + o + "%"))); + Optional.ofNullable(query.getKind()).filter(StringUtils::hasText).ifPresent(o -> predicates.add(criteriaBuilder.equal(root.get(AutoEnforcementPlan_.kind), o))); + Optional.ofNullable(query.getTaskDateArr()).filter(f -> f.length == 2).map(f -> { + List ts = new ArrayList<>(); + Optional.ofNullable(f[0]).map(from -> criteriaBuilder.greaterThanOrEqualTo(root.get(AutoEnforcementPlan_.taskDateFrom), from)).ifPresent(ts::add); + Optional.ofNullable(f[1]).map(to -> criteriaBuilder.lessThanOrEqualTo(root.get(AutoEnforcementPlan_.taskDateTo), to)).ifPresent(ts::add); + return ts; + }).ifPresent(predicates::addAll); + Optional.ofNullable(query.getTaskDateFrom()).map(from -> predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get(AutoEnforcementPlan_.taskDateFrom), from))); + Optional.ofNullable(query.getTaskDateTo()).map(to -> predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get(AutoEnforcementPlan_.taskDateTo), to))); + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } + + + /** + * 根据ID删除自动执法计划 + * + * @param planId 自动执法计划ID + */ + @Transactional + public void deleteAutoEnforcementPlanById(String planId) { + autoEnforcementPlanRepo.deleteById(planId); + } + + /** + * 批量删除自动执法计划 + * + * @param planIds 自动执法计划ID列表 + */ + @Transactional + public void deleteAutoEnforcementPlansByIds(List planIds) { + autoEnforcementPlanRepo.deleteAllById(planIds); + } + + /** + * 自动执法计划是否存在 + * + * @param planId 自动执法计划ID + * @return 是否存在 + */ + public boolean existsAutoEnforcementPlanById(String planId) { + return autoEnforcementPlanRepo.existsById(planId); + } + +}