接入和风天气,获取项目当地天气情况
This commit is contained in:
		| @ -118,6 +118,11 @@ public class EqpMachineryDetailServiceImpl extends ServiceImpl<EqpMachineryDetai | ||||
|         if (count > 0) { | ||||
|             throw new ServiceException("该编号机械已存在", HttpStatus.BAD_REQUEST); | ||||
|         } | ||||
|         // 操作数据库 | ||||
|         boolean save = this.save(machineryDetail); | ||||
|         if (!save) { | ||||
|             throw new ServiceException("新增机械详情失败,数据库异常", HttpStatus.ERROR); | ||||
|         } | ||||
|         // 修改机械数量 | ||||
|         LambdaUpdateWrapper<EqpMachinery> lqw = new LambdaUpdateWrapper<>(); | ||||
|         lqw.eq(EqpMachinery::getId, machineryDetail.getMachineryId()); | ||||
| @ -126,11 +131,6 @@ public class EqpMachineryDetailServiceImpl extends ServiceImpl<EqpMachineryDetai | ||||
|         if (!update) { | ||||
|             throw new ServiceException("修改机械数量失败,数据库异常", HttpStatus.ERROR); | ||||
|         } | ||||
|         // 操作数据库 | ||||
|         boolean save = this.save(machineryDetail); | ||||
|         if (!save) { | ||||
|             throw new ServiceException("新增机械详情失败,数据库异常", HttpStatus.ERROR); | ||||
|         } | ||||
|         return machineryDetail.getId(); | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -0,0 +1,36 @@ | ||||
| package org.dromara.manager.weathermanager; | ||||
|  | ||||
| import lombok.Data; | ||||
| import org.springframework.boot.context.properties.ConfigurationProperties; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/5/12 17:28 | ||||
|  */ | ||||
| @Data | ||||
| @Configuration | ||||
| @ConfigurationProperties(prefix = "weather") | ||||
| public class WeatherConfig { | ||||
|  | ||||
|     /** | ||||
|      * 凭据 id | ||||
|      */ | ||||
|     private String keyId; | ||||
|  | ||||
|     /** | ||||
|      * 项目 id | ||||
|      */ | ||||
|     private String projectId; | ||||
|  | ||||
|     /** | ||||
|      * 私钥 | ||||
|      */ | ||||
|     private String privateKey; | ||||
|  | ||||
|     /** | ||||
|      * 接口地址 | ||||
|      */ | ||||
|     private String apiHost; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,144 @@ | ||||
| package org.dromara.manager.weathermanager; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/5/12 17:57 | ||||
|  */ | ||||
| public interface WeatherConstant { | ||||
|  | ||||
|     /** | ||||
|      * 城市三天的天气 | ||||
|      */ | ||||
|     String THREE_DAYS_WEATHER_PATH = "/v7/weather/3d"; | ||||
|  | ||||
|     /** | ||||
|      * 天气信息 | ||||
|      */ | ||||
|     String DAILY = "daily"; | ||||
|  | ||||
|     /** | ||||
|      * 日期 | ||||
|      */ | ||||
|     String FX_DATE = "fxDate"; | ||||
|  | ||||
|     /** | ||||
|      * 最高温度 | ||||
|      */ | ||||
|     String TEMP_MAX = "tempMax"; | ||||
|  | ||||
|     /** | ||||
|      * 最低温度 | ||||
|      */ | ||||
|     String TEMP_MIN = "tempMin"; | ||||
|  | ||||
|     /** | ||||
|      * 日出时间 | ||||
|      */ | ||||
|     String SUN_RISE = "sunrise"; | ||||
|  | ||||
|     /** | ||||
|      * 日落时间 | ||||
|      */ | ||||
|     String SUN_SET = "sunset"; | ||||
|  | ||||
|     /** | ||||
|      * 白天天气状态 | ||||
|      */ | ||||
|     String TEXT_DAY = "textDay"; | ||||
|  | ||||
|     /** | ||||
|      * 晚上天气状态 | ||||
|      */ | ||||
|     String TEXT_NIGHT = "textNight"; | ||||
|  | ||||
|     // region 天气情况 | ||||
|  | ||||
|     /** | ||||
|      * 晴 | ||||
|      */ | ||||
|     List<String> SUNNY = List.of("晴"); | ||||
|  | ||||
|     /** | ||||
|      * 多云 | ||||
|      */ | ||||
|     List<String> MANY_CLOUD = List.of("多云", "少云", "晴间多云"); | ||||
|  | ||||
|     /** | ||||
|      * 阴 | ||||
|      */ | ||||
|     List<String> CLOUDY = List.of("阴", "阴天"); | ||||
|  | ||||
|     /** | ||||
|      * 小雨 | ||||
|      */ | ||||
|     List<String> SMALL_RAIN = List.of("小雨", "毛毛雨", "细雨", "毛毛雨/细雨", "小到中雨"); | ||||
|  | ||||
|     /** | ||||
|      * 大雨 | ||||
|      */ | ||||
|     List<String> BIG_RAIN = List.of("阵雨", "强阵雨", "中雨", "大雨", "极端降雨", "暴雨", "大暴雨", "特大暴雨", "中到大雨", "大到暴雨", "暴雨到大暴雨", "大暴雨到特大暴雨"); | ||||
|  | ||||
|     /** | ||||
|      * 小雪 | ||||
|      */ | ||||
|     List<String> SMALL_SNOW = List.of("雪", "小雪", "中雪", "小到中雪"); | ||||
|  | ||||
|     /** | ||||
|      * 大雪 | ||||
|      */ | ||||
|     List<String> BIG_SNOW = List.of("大雪", "暴雪", "阵雪", "中到大雪", "大到暴雪", "阵雨夹雪"); | ||||
|  | ||||
|     /** | ||||
|      * 雷雨 | ||||
|      */ | ||||
|     List<String> THUNDERSTORM = List.of("雷阵雨", "强雷阵雨", "雷阵雨伴有冰雹"); | ||||
|  | ||||
|     /** | ||||
|      * 雨雪 | ||||
|      */ | ||||
|     List<String> RAIN_SNOW = List.of("冻雨", "雨夹雪", "雨雪天气", "阵雨夹雪"); | ||||
|  | ||||
|     /** | ||||
|      * 霾 | ||||
|      */ | ||||
|     List<String> HAZE = List.of("霾", "雾霾", "中度霾", "重度霾", "严重霾"); | ||||
|  | ||||
|     /** | ||||
|      * 雾 | ||||
|      */ | ||||
|     List<String> FOG = List.of("薄雾", "雾", "浓雾", "强浓雾", "大雾", "特强浓雾"); | ||||
|  | ||||
|     /** | ||||
|      * 沙尘 | ||||
|      */ | ||||
|     List<String> SANDSTORM = List.of("扬沙", "浮尘", "沙尘暴", "强沙尘暴"); | ||||
|  | ||||
|     /** | ||||
|      * 获取天气情况map | ||||
|      * | ||||
|      * @return 天气情况map | ||||
|      */ | ||||
|     static Map<String, List<String>> getWeatherStatusMap() { | ||||
|         Map<String, List<String>> weatherStatusMap = new HashMap<>(); | ||||
|         weatherStatusMap.put("sunny", SUNNY); | ||||
|         weatherStatusMap.put("manyCloud", MANY_CLOUD); | ||||
|         weatherStatusMap.put("cloudy", CLOUDY); | ||||
|         weatherStatusMap.put("smallRain", SMALL_RAIN); | ||||
|         weatherStatusMap.put("bigRain", BIG_RAIN); | ||||
|         weatherStatusMap.put("smallSnow", SMALL_SNOW); | ||||
|         weatherStatusMap.put("bigSnow", BIG_SNOW); | ||||
|         weatherStatusMap.put("thunderstorm", THUNDERSTORM); | ||||
|         weatherStatusMap.put("rainSnow", RAIN_SNOW); | ||||
|         weatherStatusMap.put("haze", HAZE); | ||||
|         weatherStatusMap.put("fog", FOG); | ||||
|         weatherStatusMap.put("sandstorm", SANDSTORM); | ||||
|         return weatherStatusMap; | ||||
|     } | ||||
|  | ||||
|     // endregion | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,122 @@ | ||||
| package org.dromara.manager.weathermanager; | ||||
|  | ||||
| import cn.hutool.http.HttpRequest; | ||||
| import cn.hutool.http.HttpResponse; | ||||
| import jakarta.annotation.Resource; | ||||
| import org.dromara.common.core.constant.HttpStatus; | ||||
| import org.dromara.common.core.exception.ServiceException; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| import java.math.BigDecimal; | ||||
| import java.math.RoundingMode; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.security.*; | ||||
| import java.security.spec.InvalidKeySpecException; | ||||
| import java.security.spec.PKCS8EncodedKeySpec; | ||||
| import java.time.ZoneOffset; | ||||
| import java.time.ZonedDateTime; | ||||
| import java.util.Base64; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/5/12 17:33 | ||||
|  */ | ||||
| @Component | ||||
| public class WeatherManager { | ||||
|  | ||||
|     @Resource | ||||
|     private WeatherConfig weatherConfig; | ||||
|  | ||||
|     /** | ||||
|      * 获取天气 | ||||
|      * | ||||
|      * @param lng         经度 | ||||
|      * @param lat         纬度 | ||||
|      * @param weatherPath 天气请求路径 | ||||
|      * @return 天气信息字符串 | ||||
|      */ | ||||
|     public String getWeather(String lng, String lat, String weatherPath) { | ||||
|         // 获取小数点后两位的经纬度 | ||||
|         String lngTwo = roundToTwoDecimalPlacesString(lng); | ||||
|         String latTwo = roundToTwoDecimalPlacesString(lat); | ||||
|         String location = lngTwo + "," + latTwo; | ||||
|         // 获取天气请求路径 | ||||
|         String dayWeatherUrl = getDayWeatherUrl(weatherPath, location); | ||||
|         String body; | ||||
|         try (HttpResponse result = HttpRequest.get(dayWeatherUrl) | ||||
|             .header("Authorization", "Bearer " + getJwt()) | ||||
|             .execute()) { | ||||
|             int status = result.getStatus(); | ||||
|             if (status != HttpStatus.SUCCESS) { | ||||
|                 throw new ServiceException("获取天气失败,状态码:" + status, HttpStatus.ERROR); | ||||
|             } | ||||
|             body = result.body(); | ||||
|         } | ||||
|         return body; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取天气预报 Url | ||||
|      * | ||||
|      * @param weatherPath 天气请求路径 | ||||
|      * @param location    位置 | ||||
|      */ | ||||
|     private String getDayWeatherUrl(String weatherPath, String location) { | ||||
|         return String.format("https://%s%s?location=%s", weatherConfig.getApiHost(), weatherPath, location); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取小数点后两位的经纬度 | ||||
|      * | ||||
|      * @param value 经纬度 | ||||
|      */ | ||||
|     private String roundToTwoDecimalPlacesString(String value) { | ||||
|         BigDecimal bd = new BigDecimal(value); | ||||
|         bd = bd.setScale(2, RoundingMode.HALF_UP); // 使用 RoundingMode.HALF_UP | ||||
|         return bd.toPlainString(); // 防止科学计数法 | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 获取 JWT | ||||
|      */ | ||||
|     private String getJwt() { | ||||
|         // Private key | ||||
|         String privateKeyString = weatherConfig.getPrivateKey() | ||||
|             .replace("-----BEGIN PRIVATE KEY-----", "") | ||||
|             .replace("-----END PRIVATE KEY-----", "") | ||||
|             .trim(); | ||||
|         byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString); | ||||
|         PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); | ||||
|         PrivateKey privateKey; | ||||
|         try { | ||||
|             KeyFactory keyFactory = KeyFactory.getInstance("EdDSA"); | ||||
|             privateKey = keyFactory.generatePrivate(keySpec); | ||||
|         } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { | ||||
|             throw new ServiceException("获取天气失败,加密错误", HttpStatus.ERROR); | ||||
|         } | ||||
|         // Header | ||||
|         String headerJson = "{\"alg\": \"EdDSA\", \"kid\": \"" + weatherConfig.getKeyId() + "\"}"; | ||||
|         // Payload | ||||
|         long iat = ZonedDateTime.now(ZoneOffset.UTC).toEpochSecond() - 30; | ||||
|         long exp = iat + 900; | ||||
|         String payloadJson = "{\"sub\": \"" + weatherConfig.getProjectId() + "\", \"iat\": " + iat + ", \"exp\": " + exp + "}"; | ||||
|         // Base64url header + payload | ||||
|         String headerEncoded = Base64.getUrlEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8)); | ||||
|         String payloadEncoded = Base64.getUrlEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8)); | ||||
|         String data = headerEncoded + "." + payloadEncoded; | ||||
|         // Sign | ||||
|         byte[] signature; | ||||
|         try { | ||||
|             Signature signer = Signature.getInstance("EdDSA"); | ||||
|             signer.initSign(privateKey); | ||||
|             signer.update(data.getBytes(StandardCharsets.UTF_8)); | ||||
|             signature = signer.sign(); | ||||
|         } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { | ||||
|             throw new ServiceException("获取天气失败,加密错误", HttpStatus.ERROR); | ||||
|         } | ||||
|         String signatureString = Base64.getUrlEncoder().encodeToString(signature); | ||||
|         return data + "." + signatureString; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,14 @@ | ||||
| package org.dromara.project.constant; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/5/13 10:33 | ||||
|  */ | ||||
| public interface BusProjectConstant { | ||||
|  | ||||
|     /** | ||||
|      * 项目天气封装信息缓存的 Redis Key 前缀 | ||||
|      */ | ||||
|     String PROJECT_WEATHER_LIST_VO_REDIS_KEY_PREFIX = "project:weather:list"; | ||||
|  | ||||
| } | ||||
| @ -93,7 +93,7 @@ public class BusConstructionUserController extends BaseController { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询施工人员大屏数据 | ||||
|      * 查询大屏施工人员信息 | ||||
|      */ | ||||
|     @SaCheckPermission("project:constructionUser:query") | ||||
|     @GetMapping("/gis") | ||||
|  | ||||
| @ -22,6 +22,7 @@ import org.dromara.project.domain.req.project.BusProjectQueryReq; | ||||
| import org.dromara.project.domain.req.project.BusProjectUpdateReq; | ||||
| import org.dromara.project.domain.vo.project.BusProjectContractorListVo; | ||||
| import org.dromara.project.domain.vo.project.BusProjectVo; | ||||
| import org.dromara.project.domain.vo.project.BusProjectWeatherVo; | ||||
| import org.dromara.project.service.IBusProjectService; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
| @ -121,4 +122,13 @@ public class BusProjectController extends BaseController { | ||||
|         return toAjax(projectService.deleteWithValidByIds(List.of(ids), true)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查询项目天气 | ||||
|      */ | ||||
|     @GetMapping("/weather/{id}") | ||||
|     public R<List<BusProjectWeatherVo>> getWeather(@NotNull(message = "主键不能为空") | ||||
|                                                    @PathVariable Long id) { | ||||
|         return R.ok(projectService.getWeather(id)); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,68 @@ | ||||
| package org.dromara.project.domain.vo.project; | ||||
|  | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.io.Serial; | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * @author lcj | ||||
|  * @date 2025/5/13 9:29 | ||||
|  */ | ||||
| @Data | ||||
| public class BusProjectWeatherVo implements Serializable { | ||||
|  | ||||
|     @Serial | ||||
|     private static final long serialVersionUID = 4173514725591666698L; | ||||
|  | ||||
|     /** | ||||
|      * 日期 | ||||
|      */ | ||||
|     private String date; | ||||
|  | ||||
|     /** | ||||
|      * 星期 | ||||
|      */ | ||||
|     private String week; | ||||
|  | ||||
|     /** | ||||
|      * 最高温度 | ||||
|      */ | ||||
|     private String tempMax; | ||||
|  | ||||
|     /** | ||||
|      * 最低温度 | ||||
|      */ | ||||
|     private String tempMin; | ||||
|  | ||||
|     /** | ||||
|      * 日出时间 | ||||
|      */ | ||||
|     private String sunRise; | ||||
|  | ||||
|     /** | ||||
|      * 日落时间 | ||||
|      */ | ||||
|     private String sunSet; | ||||
|  | ||||
|     /** | ||||
|      * 白天天气状态 | ||||
|      */ | ||||
|     private String dayStatus; | ||||
|  | ||||
|     /** | ||||
|      * 白天天气图标 | ||||
|      */ | ||||
|     private String dayIcon; | ||||
|  | ||||
|     /** | ||||
|      * 晚上天气状态 | ||||
|      */ | ||||
|     private String nightStatus; | ||||
|  | ||||
|     /** | ||||
|      * 晚上天气图标 | ||||
|      */ | ||||
|     private String nightIcon; | ||||
|  | ||||
| } | ||||
| @ -25,4 +25,9 @@ public class BusProjectNewsGisVo implements Serializable { | ||||
|      */ | ||||
|     private String title; | ||||
|  | ||||
|     /** | ||||
|      * 显示 | ||||
|      */ | ||||
|     private Boolean show; | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,7 @@ package org.dromara.project.service; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
| import com.baomidou.mybatisplus.extension.service.IService; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import org.dromara.common.mybatis.core.page.PageQuery; | ||||
| import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.project.domain.BusProject; | ||||
| @ -11,6 +12,7 @@ import org.dromara.project.domain.req.project.BusProjectQueryReq; | ||||
| import org.dromara.project.domain.req.project.BusProjectUpdateReq; | ||||
| import org.dromara.project.domain.vo.project.BusProjectContractorListVo; | ||||
| import org.dromara.project.domain.vo.project.BusProjectVo; | ||||
| import org.dromara.project.domain.vo.project.BusProjectWeatherVo; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| @ -120,4 +122,12 @@ public interface IBusProjectService extends IService<BusProject> { | ||||
|      */ | ||||
|     void validAuth(Collection<Long> projectIdList, Long userId); | ||||
|  | ||||
|     /** | ||||
|      * 获取天气信息 | ||||
|      * | ||||
|      * @param id 项目id | ||||
|      * @return 天气信息列表 | ||||
|      */ | ||||
|     List<BusProjectWeatherVo> getWeather(Long id); | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -100,6 +100,7 @@ public class BusProjectNewsServiceImpl extends ServiceImpl<BusProjectNewsMapper, | ||||
|         return projectNewsList.stream().map(projectNews -> { | ||||
|             BusProjectNewsGisVo projectNewsGisResp = new BusProjectNewsGisVo(); | ||||
|             BeanUtils.copyProperties(projectNews, projectNewsGisResp); | ||||
|             projectNewsGisResp.setShow(false); | ||||
|             return projectNewsGisResp; | ||||
|         }).toList(); | ||||
|     } | ||||
|  | ||||
| @ -1,12 +1,20 @@ | ||||
| package org.dromara.project.service.impl; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.date.DateTime; | ||||
| import cn.hutool.core.date.DateUtil; | ||||
| import cn.hutool.core.util.PhoneUtil; | ||||
| import cn.hutool.core.util.RandomUtil; | ||||
| import cn.hutool.json.JSONArray; | ||||
| import cn.hutool.json.JSONObject; | ||||
| import cn.hutool.json.JSONUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||
| import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||
| import com.github.benmanes.caffeine.cache.Cache; | ||||
| import com.github.benmanes.caffeine.cache.Caffeine; | ||||
| import jakarta.annotation.Resource; | ||||
| import org.dromara.common.core.constant.HttpStatus; | ||||
| import org.dromara.common.core.constant.SystemConstants; | ||||
| @ -17,6 +25,9 @@ import org.dromara.common.core.utils.StringUtils; | ||||
| import org.dromara.common.mybatis.core.page.PageQuery; | ||||
| import org.dromara.common.mybatis.core.page.TableDataInfo; | ||||
| import org.dromara.common.satoken.utils.LoginHelper; | ||||
| import org.dromara.manager.weathermanager.WeatherConstant; | ||||
| import org.dromara.manager.weathermanager.WeatherManager; | ||||
| import org.dromara.project.constant.BusProjectConstant; | ||||
| import org.dromara.project.domain.BusContractor; | ||||
| import org.dromara.project.domain.BusProject; | ||||
| import org.dromara.project.domain.BusProjectFile; | ||||
| @ -26,6 +37,7 @@ import org.dromara.project.domain.req.project.BusProjectQueryReq; | ||||
| import org.dromara.project.domain.req.project.BusProjectUpdateReq; | ||||
| import org.dromara.project.domain.vo.project.BusProjectContractorListVo; | ||||
| import org.dromara.project.domain.vo.project.BusProjectVo; | ||||
| import org.dromara.project.domain.vo.project.BusProjectWeatherVo; | ||||
| import org.dromara.project.mapper.BusProjectMapper; | ||||
| import org.dromara.project.service.IBusContractorService; | ||||
| import org.dromara.project.service.IBusProjectFileService; | ||||
| @ -33,10 +45,13 @@ import org.dromara.project.service.IBusProjectService; | ||||
| import org.dromara.project.service.IBusUserProjectRelevancyService; | ||||
| import org.springframework.beans.BeanUtils; | ||||
| import org.springframework.context.annotation.Lazy; | ||||
| import org.springframework.data.redis.core.StringRedisTemplate; | ||||
| import org.springframework.data.redis.core.ValueOperations; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
|  | ||||
| import java.util.*; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| import java.util.stream.Collectors; | ||||
|  | ||||
| /** | ||||
| @ -61,6 +76,19 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj | ||||
|     @Resource | ||||
|     private IBusProjectFileService projectFileService; | ||||
|  | ||||
|     @Resource | ||||
|     private WeatherManager weatherManager; | ||||
|  | ||||
|     @Resource | ||||
|     private StringRedisTemplate stringRedisTemplate; | ||||
|  | ||||
|     private final Cache<String, String> WEATHER_CACHE = | ||||
|         Caffeine.newBuilder().initialCapacity(1024) | ||||
|             .maximumSize(10000L) | ||||
|             // 缓存 30 分钟移除 | ||||
|             .expireAfterWrite(30L, TimeUnit.MINUTES) | ||||
|             .build(); | ||||
|  | ||||
|     /** | ||||
|      * 查询项目 | ||||
|      * | ||||
| @ -432,4 +460,98 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取天气信息 | ||||
|      * | ||||
|      * @param id 项目id | ||||
|      * @return 天气信息列表 | ||||
|      */ | ||||
|     @Override | ||||
|     public List<BusProjectWeatherVo> getWeather(Long id) { | ||||
|         BusProject project = this.getById(id); | ||||
|         if (project == null) { | ||||
|             throw new ServiceException("项目不存在"); | ||||
|         } | ||||
|         // 构建缓存 key | ||||
|         String cacheKey = String.format("%s:%s", BusProjectConstant.PROJECT_WEATHER_LIST_VO_REDIS_KEY_PREFIX, id); | ||||
|         // 查询本地缓存(caffeine) | ||||
|         String cachedValue = WEATHER_CACHE.getIfPresent(cacheKey); | ||||
|         if (cachedValue != null) { | ||||
|             // 如果缓存命中,返回结果 | ||||
|             return JSONUtil.toList(cachedValue, BusProjectWeatherVo.class); | ||||
|         } | ||||
|         // 查询分布式缓存(Redis) | ||||
|         ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue(); | ||||
|         cachedValue = valueOps.get(cacheKey); | ||||
|         if (cachedValue != null) { | ||||
|             // 如果命中Redis,存入本地缓存并返回结果 | ||||
|             WEATHER_CACHE.put(cacheKey, cachedValue); | ||||
|             return JSONUtil.toList(cachedValue, BusProjectWeatherVo.class); | ||||
|         } | ||||
|         // 获取当天及之后的天气信息 | ||||
|         String lng = project.getLng(); | ||||
|         String lat = project.getLat(); | ||||
|         if (StringUtils.isAnyBlank(lng, lat)) { | ||||
|             throw new ServiceException("项目坐标信息为空"); | ||||
|         } | ||||
|         String weatherStr = weatherManager.getWeather(lng, lat, WeatherConstant.THREE_DAYS_WEATHER_PATH); | ||||
|         // 解析为 JSONObject | ||||
|         JSONObject weatherJson = JSONUtil.parseObj(weatherStr); | ||||
|         // 获取 daily 数组 | ||||
|         JSONArray dailyArray = weatherJson.getJSONArray(WeatherConstant.DAILY); | ||||
|         // 循环遍历,封装项目天气信息 | ||||
|         List<BusProjectWeatherVo> weatherList = new ArrayList<>(); | ||||
|         for (int i = 0; i < dailyArray.size(); i++) { | ||||
|             JSONObject day = dailyArray.getJSONObject(i); | ||||
|             BusProjectWeatherVo weatherVo = new BusProjectWeatherVo(); | ||||
|             // 获取星期 | ||||
|             String dateStr = day.getStr(WeatherConstant.FX_DATE); | ||||
|             DateTime date = DateUtil.parse(dateStr, "yyyy-MM-dd"); | ||||
|             String week = DateUtil.format(date, "EEE"); | ||||
|             // 获取天气图标 | ||||
|             String textDay = day.getStr(WeatherConstant.TEXT_DAY); | ||||
|             String textNight = day.getStr(WeatherConstant.TEXT_NIGHT); | ||||
|             Map<String, List<String>> weatherStatusMap = WeatherConstant.getWeatherStatusMap(); | ||||
|             String dayStatus = getWeatherCategory(textDay, weatherStatusMap); | ||||
|             String nightStatus = getWeatherCategory(textNight, weatherStatusMap); | ||||
|             // 封装数据 | ||||
|             weatherVo.setDate(dateStr); | ||||
|             weatherVo.setWeek(week); | ||||
|             weatherVo.setTempMax(day.getStr(WeatherConstant.TEMP_MAX)); | ||||
|             weatherVo.setTempMin(day.getStr(WeatherConstant.TEMP_MIN)); | ||||
|             weatherVo.setSunRise(day.getStr(WeatherConstant.SUN_RISE)); | ||||
|             weatherVo.setSunSet(day.getStr(WeatherConstant.SUN_SET)); | ||||
|             weatherVo.setDayStatus(textDay); | ||||
|             weatherVo.setNightStatus(textNight); | ||||
|             weatherVo.setDayIcon(dayStatus); | ||||
|             weatherVo.setNightIcon(nightStatus); | ||||
|             weatherList.add(weatherVo); | ||||
|         } | ||||
|         // 更新缓存 | ||||
|         String cacheValue = JSONUtil.toJsonStr(weatherList); | ||||
|         // 更新本地缓存 | ||||
|         WEATHER_CACHE.put(cacheKey, cacheValue); | ||||
|         // 更新 Redis 缓存,设置 5 - 10 分钟随机过期,防止雪崩 | ||||
|         int cacheExpireTime = 30 * 60 + RandomUtil.randomInt(0, 300); | ||||
|         valueOps.set(cacheKey, cacheValue, cacheExpireTime, TimeUnit.SECONDS); | ||||
|         // 返回结果 | ||||
|         return weatherList; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 根据天气图标获取天气类别 | ||||
|      * | ||||
|      * @param icon 天气图标 | ||||
|      * @param map  天气图标与天气类别的映射关系 | ||||
|      * @return 天气类别 | ||||
|      */ | ||||
|     public static String getWeatherCategory(String icon, Map<String, List<String>> map) { | ||||
|         for (Map.Entry<String, List<String>> entry : map.entrySet()) { | ||||
|             if (entry.getValue().contains(icon)) { | ||||
|                 return entry.getKey(); | ||||
|             } | ||||
|         } | ||||
|         return "cloudy"; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -24,7 +24,7 @@ public class QltQualityInspectionGis { | ||||
|     /** | ||||
|      * 巡检类型 | ||||
|      */ | ||||
|     private String inspectionType; | ||||
|     private String inspectionTypeLabel; | ||||
|  | ||||
|     /** | ||||
|      * 巡检标题 | ||||
|  | ||||
| @ -38,9 +38,11 @@ import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionListG | ||||
| import org.dromara.quality.domain.vo.qualityinspection.QltQualityInspectionVo; | ||||
| import org.dromara.quality.mapper.QltQualityInspectionMapper; | ||||
| import org.dromara.quality.service.IQltQualityInspectionService; | ||||
| import org.dromara.system.domain.vo.SysDictDataVo; | ||||
| import org.dromara.system.domain.vo.SysOssVo; | ||||
| import org.dromara.system.domain.vo.SysUserVo; | ||||
| import org.dromara.system.service.ISysDictDataService; | ||||
| import org.dromara.system.service.ISysDictTypeService; | ||||
| import org.dromara.system.service.ISysOssService; | ||||
| import org.dromara.system.service.ISysUserService; | ||||
| import org.dromara.utils.DocumentUtils; | ||||
| @ -85,6 +87,9 @@ public class QltQualityInspectionServiceImpl extends ServiceImpl<QltQualityInspe | ||||
|     @Resource | ||||
|     private ISysDictDataService dictDataService; | ||||
|  | ||||
|     @Resource | ||||
|     private ISysDictTypeService dictTypeService; | ||||
|  | ||||
|     /** | ||||
|      * 查询质量-检查工单 | ||||
|      * | ||||
| @ -144,14 +149,22 @@ public class QltQualityInspectionServiceImpl extends ServiceImpl<QltQualityInspe | ||||
|         if (CollUtil.isEmpty(qualityInspectionList)) { | ||||
|             return gisVo; | ||||
|         } | ||||
|         // 获取字典值 | ||||
|         List<SysDictDataVo> dictDataVoList = dictTypeService.selectDictDataByType(QltQualityConstant.QUALITY_INSPECTION_CHECK_TYPE); | ||||
|         Map<String, String> dictDataMap = dictDataVoList.stream().collect(Collectors.toMap(SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel)); | ||||
|         // 获取最新的检查工单 | ||||
|         List<QltQualityInspection> topList = qualityInspectionList.stream() | ||||
|             .sorted(Comparator.comparing(QltQualityInspection::getCreateTime).reversed()) | ||||
|             .limit(req.getPageSize()) | ||||
|             .limit(Optional.ofNullable(req.getPageSize()).orElse(20)) | ||||
|             .toList(); | ||||
|         // 转换为 GIS 对象,并设置标签 | ||||
|         List<QltQualityInspectionGis> gisList = topList.stream().map(qualityInspection -> { | ||||
|             QltQualityInspectionGis gis = new QltQualityInspectionGis(); | ||||
|             BeanUtils.copyProperties(qualityInspection, gis); | ||||
|             String label = dictDataMap.get(qualityInspection.getInspectionType()); | ||||
|             if (label != null) { | ||||
|                 gis.setInspectionTypeLabel(label); | ||||
|             } | ||||
|             return gis; | ||||
|         }).toList(); | ||||
|         // 获取整改情况 | ||||
|  | ||||
| @ -33,7 +33,12 @@ public class HseSafetyInspectionListGisVo implements Serializable { | ||||
|     private Long safetyInspectionCount; | ||||
|  | ||||
|     /** | ||||
|      * 整改情况 | ||||
|      * 整改情况总数 | ||||
|      */ | ||||
|     private Long correctSituationCount; | ||||
|  | ||||
|     /** | ||||
|      * 整改情况百分比 | ||||
|      */ | ||||
|     private String correctSituation; | ||||
|  | ||||
|  | ||||
| @ -153,7 +153,7 @@ public class HseSafetyInspectionServiceImpl extends ServiceImpl<HseSafetyInspect | ||||
|         // 获取最新的班组列表 | ||||
|         List<HseTeamMeeting> topList = teamMeetings.stream() | ||||
|             .sorted(Comparator.comparing(HseTeamMeeting::getCreateTime).reversed()) | ||||
|             .limit(req.getPageSize()) | ||||
|             .limit(Optional.ofNullable(req.getPageSize()).orElse(20)) | ||||
|             .toList(); | ||||
|         List<Long> teamIds = topList.stream().map(HseTeamMeeting::getTeamId).toList(); | ||||
|         Map<Long, List<BusProjectTeam>> teamMap = projectTeamService.lambdaQuery() | ||||
| @ -181,6 +181,7 @@ public class HseSafetyInspectionServiceImpl extends ServiceImpl<HseSafetyInspect | ||||
|         gisVo.setTeamMeetingList(gisList); | ||||
|         gisVo.setTeamMeetingCount((long) teamMeetings.size()); | ||||
|         gisVo.setSafetyInspectionCount((long) safetyInspectionList.size()); | ||||
|         gisVo.setCorrectSituationCount(passCount); | ||||
|         gisVo.setCorrectSituation(String.format("%.2f", passCount * 100.0 / safetyInspectionList.size())); | ||||
|         return gisVo; | ||||
|     } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user