企业级大屏

This commit is contained in:
lcj
2025-09-09 19:49:14 +08:00
parent c75563b46a
commit 5b991396c2
25 changed files with 702 additions and 173 deletions

View File

@ -3,9 +3,12 @@ package org.dromara.bigscreen.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.annotation.Resource;
import org.dromara.bigscreen.domain.dto.WeatherQueryReq;
import org.dromara.bigscreen.domain.vo.WeatherVo;
import org.dromara.bigscreen.domain.vo.EnterpriseKeyIndexVo;
import org.dromara.bigscreen.domain.vo.OutputValueComparisonVo;
import org.dromara.bigscreen.domain.vo.ProjectProgressAnalysisVo;
import org.dromara.bigscreen.service.EnterpriseBigScreenService;
import org.dromara.common.core.domain.R;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -29,6 +32,33 @@ public class EnterpriseBigScreenController {
@Resource
private EnterpriseBigScreenService enterpriseBigScreenService;
/**
* 获取关键指标
*/
@SaCheckPermission("enterprise:bigScreen:keyIndex")
@GetMapping("/keyIndex")
public R<EnterpriseKeyIndexVo> getEnterpriseKeyIndex() {
return R.ok(enterpriseBigScreenService.getEnterpriseKeyIndex());
}
/**
* 项目进度分析
*/
@SaCheckPermission("enterprise:bigScreen:projectProgress")
@GetMapping("/projectProgress")
public R<ProjectProgressAnalysisVo> getProjectProgress() {
return R.ok(enterpriseBigScreenService.getProjectProgressAnalysis());
}
/**
* 项目产值对比
*/
@SaCheckPermission("enterprise:bigScreen:projectOutputValueComparison")
@GetMapping("/projectOutputValueComparison")
public R<List<OutputValueComparisonVo>> getProjectOutputValueComparison() {
return R.ok(enterpriseBigScreenService.getProjectOutputValueComparison());
}
/**
* 查询天气
*/

View File

@ -11,13 +11,13 @@ import org.dromara.ctr.domain.CtrExpensesContract;
import org.dromara.ctr.domain.CtrIncomeContract;
import org.dromara.ctr.service.ICtrExpensesContractService;
import org.dromara.ctr.service.ICtrIncomeContractService;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.out.domain.OutSettlementValueOwner;
import org.dromara.out.domain.OutSettlementValueSubcontract;
import org.dromara.out.service.IOutSettlementValueOwnerService;
import org.dromara.out.service.IOutSettlementValueSubcontractService;
import org.dromara.project.domain.vo.project.BusProjectGisVo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@ -526,8 +526,6 @@ public class MoneyBigScreenController {
}
/**
* 获取当前月份的开始时间和结束时间
*
@ -548,7 +546,7 @@ public class MoneyBigScreenController {
*/
@SaCheckPermission("project:bigScreen:weather")
@GetMapping("/weather/{projectId}")
public R<List<BusProjectWeatherVo>> getProjectWeather(@NotNull(message = "主键不能为空")
public R<List<WeatherVo>> getProjectWeather(@NotNull(message = "主键不能为空")
@PathVariable Long projectId) {
return R.ok(moneyBigScreenService.getProjectWeather(projectId));
}

View File

@ -23,8 +23,8 @@ import org.dromara.land.service.IBusLandBlockService;
import org.dromara.land.service.IBusLandTransferLedgerService;
import org.dromara.other.domain.OthYs7Device;
import org.dromara.other.service.IOthYs7DeviceService;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -113,7 +113,7 @@ public class ProjectBigScreenController {
*/
@SaCheckPermission("project:bigScreen:weather")
@GetMapping("/weather/{projectId}")
public R<List<BusProjectWeatherVo>> getProjectWeather(@NotNull(message = "主键不能为空")
public R<List<WeatherVo>> getProjectWeather(@NotNull(message = "主键不能为空")
@PathVariable Long projectId) {
return R.ok(projectBigScreenService.getProjectWeather(projectId));
}

View File

@ -1,5 +1,6 @@
package org.dromara.bigscreen.domain.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serial;
@ -18,11 +19,13 @@ public class WeatherQueryReq implements Serializable {
/**
* 经度
*/
@NotBlank(message = "经度不能为空")
private String lng;
/**
* 纬度
*/
@NotBlank(message = "纬度不能为空")
private String lat;
}

View File

@ -0,0 +1,38 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-09-09 15:59
*/
@Data
public class EnterpriseKeyIndexVo implements Serializable {
@Serial
private static final long serialVersionUID = -3987781906203623727L;
/**
* 在建项目数量
*/
private Long ongoingProject;
/**
* 合同总额(单位:亿元)
*/
private BigDecimal totalContractAmount;
/**
* 总容量
*/
private BigDecimal totalCapacity;
/**
* 今日施工项目数量
*/
private Long todayProject;
}

View File

@ -0,0 +1,38 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-09-09 19:12
*/
@Data
public class OutputValueComparisonVo implements Serializable {
@Serial
private static final long serialVersionUID = -6902563869975528076L;
/**
* 项目id
*/
private Long projectId;
/**
* 项目名称
*/
private String projectName;
/**
* 计划产值
*/
private BigDecimal planValue;
/**
* 实际产值
*/
private BigDecimal actualValue;
}

View File

@ -0,0 +1,33 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-09-09 16:04
*/
@Data
public class PeopleOverviewVo implements Serializable {
@Serial
private static final long serialVersionUID = -4353811031023888101L;
/**
* 出勤人数
*/
private Long attendanceNumber;
/**
* 出勤率
*/
private BigDecimal attendanceRate;
/**
* 施工人员数量
*/
private Long constructorNumber;
}

View File

@ -0,0 +1,39 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
/**
* @author lilemy
* @date 2025-09-09 16:51
*/
@Data
public class ProjectProgressAnalysisVo implements Serializable {
@Serial
private static final long serialVersionUID = -2170524608375159201L;
/**
* 并网总容量 (MW)
*/
private BigDecimal gridConnectedCapacity;
/**
* 计划总容量 (MW)
*/
private BigDecimal plannedCapacity;
/**
* 延期项目数量
*/
private Integer delayedProjectCount;
/**
* 项目进度详情
*/
List<ProjectProgressDetailVo> projectProgressDetailList;
}

View File

@ -0,0 +1,33 @@
package org.dromara.bigscreen.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-09-09 16:55
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProjectProgressDetailVo {
/**
* 项目名称
*/
private String projectName;
/**
* 项目容量
*/
private BigDecimal projectCapacity;
/**
* 施工进度百分比 (0~100)
*/
private BigDecimal completionRate;
}

View File

@ -1,7 +1,10 @@
package org.dromara.bigscreen.service;
import org.dromara.bigscreen.domain.dto.WeatherQueryReq;
import org.dromara.bigscreen.domain.vo.WeatherVo;
import org.dromara.bigscreen.domain.vo.EnterpriseKeyIndexVo;
import org.dromara.bigscreen.domain.vo.OutputValueComparisonVo;
import org.dromara.bigscreen.domain.vo.ProjectProgressAnalysisVo;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import java.util.List;
@ -11,6 +14,27 @@ import java.util.List;
*/
public interface EnterpriseBigScreenService {
/**
* 获取关键指标
*
* @return 关键指标
*/
EnterpriseKeyIndexVo getEnterpriseKeyIndex();
/**
* 获取项目进度分析
*
* @return 项目进度分析
*/
ProjectProgressAnalysisVo getProjectProgressAnalysis();
/**
* 获取项目产值对比
*
* @return 项目产值对比
*/
List<OutputValueComparisonVo> getProjectOutputValueComparison();
/**
* 获取3天的天气列表
*

View File

@ -1,8 +1,8 @@
package org.dromara.bigscreen.service;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.project.domain.vo.project.BusProjectGisVo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import java.util.List;
@ -25,7 +25,7 @@ public interface MoneyBigScreenService {
* @param projectId 项目id
* @return 项目天气
*/
List<BusProjectWeatherVo> getProjectWeather(Long projectId);
List<WeatherVo> getProjectWeather(Long projectId);
/**
* 获取项目安全天数

View File

@ -3,9 +3,9 @@ package org.dromara.bigscreen.service;
import org.dromara.bigscreen.domain.vo.ProjectImageProgressVo;
import org.dromara.bigscreen.domain.vo.ProjectPeopleVo;
import org.dromara.bigscreen.domain.vo.ProjectSafetyInspectionVo;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.gps.domain.bo.GpsEquipmentBo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo;
import java.util.List;
@ -22,7 +22,7 @@ public interface ProjectBigScreenService {
* @param projectId 项目id
* @return 项目天气
*/
List<BusProjectWeatherVo> getProjectWeather(Long projectId);
List<WeatherVo> getProjectWeather(Long projectId);
/**
* 获取项目安全天数

View File

@ -1,11 +1,43 @@
package org.dromara.bigscreen.service.impl;
import cn.hutool.core.collection.CollUtil;
import jakarta.annotation.Resource;
import org.dromara.bigscreen.domain.dto.WeatherQueryReq;
import org.dromara.bigscreen.domain.vo.WeatherVo;
import org.dromara.bigscreen.domain.vo.EnterpriseKeyIndexVo;
import org.dromara.bigscreen.domain.vo.OutputValueComparisonVo;
import org.dromara.bigscreen.domain.vo.ProjectProgressAnalysisVo;
import org.dromara.bigscreen.domain.vo.ProjectProgressDetailVo;
import org.dromara.bigscreen.service.EnterpriseBigScreenService;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.utils.BigDecimalUtil;
import org.dromara.ctr.domain.CtrExpensesContract;
import org.dromara.ctr.domain.CtrIncomeContract;
import org.dromara.ctr.service.ICtrExpensesContractService;
import org.dromara.ctr.service.ICtrIncomeContractService;
import org.dromara.manager.weathermanager.WeatherConstant;
import org.dromara.manager.weathermanager.WeatherManager;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.out.domain.OutConstructionValue;
import org.dromara.out.domain.OutMonthPlanAudit;
import org.dromara.out.domain.OutValueAllocation;
import org.dromara.out.service.IOutConstructionValueService;
import org.dromara.out.service.IOutMonthPlanAuditService;
import org.dromara.out.service.IOutValueAllocationService;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author lilemy
@ -14,6 +46,211 @@ import java.util.List;
@Service
public class EnterpriseBigScreenServiceImpl implements EnterpriseBigScreenService {
@Resource
private WeatherManager weatherManager;
@Resource
private IBusProjectService projectService;
@Resource
private IPgsProgressCategoryService progressCategoryService;
@Resource
private IPgsProgressPlanDetailService progressPlanDetailService;
@Resource
private ICtrIncomeContractService incomeContractService;
@Resource
private ICtrExpensesContractService expensesContractService;
@Resource
private IOutValueAllocationService outValueAllocationService;
@Resource
private IOutMonthPlanAuditService outMonthPlanAuditService;
@Resource
private IOutConstructionValueService outConstructionValueService;
/**
* 获取关键指标
*
* @return 关键指标
*/
@Override
public EnterpriseKeyIndexVo getEnterpriseKeyIndex() {
EnterpriseKeyIndexVo vo = new EnterpriseKeyIndexVo();
// 在建项目
List<BusProject> projectList = projectService.lambdaQuery()
.eq(BusProject::getStatus, 0)
.eq(BusProject::getPId, 0)
.list();
// 总容量
BigDecimal totalCapacity = projectList.stream().map(BusProject::getActual)
.filter(s -> s != null && !s.isBlank()) // 过滤掉空值
.map(BigDecimal::new) // 转成 BigDecimal
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 总合同金额
List<CtrIncomeContract> incomeContractList = incomeContractService.lambdaQuery()
.select(CtrIncomeContract::getAmount)
.list();
BigDecimal totalIncomeAmount = incomeContractList.stream()
.map(CtrIncomeContract::getAmount)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
List<CtrExpensesContract> expensesContractList = expensesContractService.lambdaQuery()
.select(CtrExpensesContract::getAmount)
.list();
BigDecimal totalExpensesAmount = expensesContractList.stream()
.map(CtrExpensesContract::getAmount)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 今日施工项目数量
Long todayProject = progressPlanDetailService.lambdaQuery()
.select(PgsProgressPlanDetail::getProjectId)
.eq(PgsProgressPlanDetail::getDate, LocalDate.now())
.groupBy(PgsProgressPlanDetail::getProjectId)
.count();
vo.setOngoingProject((long) projectList.size());
vo.setTotalCapacity(totalCapacity);
vo.setTotalContractAmount(totalIncomeAmount.add(totalExpensesAmount));
vo.setTodayProject(todayProject);
return vo;
}
/**
* 获取项目进度分析
*
* @return 项目进度分析
*/
@Override
public ProjectProgressAnalysisVo getProjectProgressAnalysis() {
ProjectProgressAnalysisVo vo = new ProjectProgressAnalysisVo();
// 1. 查询顶级项目
List<BusProject> projectList = projectService.lambdaQuery()
.select(BusProject::getId, BusProject::getProjectName, BusProject::getActual, BusProject::getPlan)
.eq(BusProject::getStatus, 0)
.eq(BusProject::getPId, 0)
.list();
if (CollUtil.isEmpty(projectList)) {
return vo;
}
// 2. 拿到顶级项目 id
List<Long> projectIds = projectList.stream()
.map(BusProject::getId)
.distinct()
.toList();
// 3. 查询子项目pId 在顶级项目id里
List<BusProject> subProject = projectService.lambdaQuery()
.select(BusProject::getId, BusProject::getPId)
.in(BusProject::getPId, projectIds)
.list();
// 4. 按父项目id分组子项目
Map<Long, List<BusProject>> subProjectMap = subProject.stream()
.collect(Collectors.groupingBy(BusProject::getPId));
// 5. 查询所有子项目的进度分类
List<PgsProgressCategory> progressCategoryList = progressCategoryService.lambdaQuery()
.select(PgsProgressCategory::getId,
PgsProgressCategory::getProjectId,
PgsProgressCategory::getCompleted,
PgsProgressCategory::getTotal)
.in(CollUtil.isNotEmpty(subProject),
PgsProgressCategory::getProjectId,
subProject.stream().map(BusProject::getId).toList())
.list();
// 6. 按子项目id分组进度分类
Map<Long, List<PgsProgressCategory>> progressCategoryMap = progressCategoryList.stream()
.collect(Collectors.groupingBy(PgsProgressCategory::getProjectId));
BigDecimal gridConnectedCapacity = projectList.stream().map(BusProject::getActual)
.filter(s -> s != null && !s.isBlank()) // 过滤掉空值
.map(BigDecimal::new) // 转成 BigDecimal
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal plannedCapacity = projectList.stream().map(BusProject::getPlan)
.filter(s -> s != null && !s.isBlank()) // 过滤掉空值
.map(BigDecimal::new) // 转成 BigDecimal
.reduce(BigDecimal.ZERO, BigDecimal::add);
List<ProjectProgressDetailVo> detailVoList = projectList.stream().map(project -> {
ProjectProgressDetailVo detailVo = new ProjectProgressDetailVo();
detailVo.setProjectName(project.getProjectName());
detailVo.setProjectCapacity(new BigDecimal(project.getActual()));
List<BusProject> children = subProjectMap.getOrDefault(project.getId(), List.of());
List<PgsProgressCategory> categoryList = new ArrayList<>();
for (BusProject child : children) {
categoryList.addAll(progressCategoryMap.getOrDefault(child.getId(), List.of()));
}
if (CollUtil.isNotEmpty(categoryList)) {
BigDecimal completed = categoryList.stream().map(PgsProgressCategory::getCompleted)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal total = categoryList.stream().map(PgsProgressCategory::getTotal)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
detailVo.setCompletionRate(BigDecimalUtil.toPercentage(completed, total));
}
return detailVo;
}).toList();
vo.setGridConnectedCapacity(gridConnectedCapacity);
vo.setPlannedCapacity(plannedCapacity);
// todo 获取延迟项目数
vo.setDelayedProjectCount(0);
vo.setProjectProgressDetailList(detailVoList);
return vo;
}
/**
* 获取项目产值对比
*
* @return 项目产值对比
*/
@Override
public List<OutputValueComparisonVo> getProjectOutputValueComparison() {
List<OutputValueComparisonVo> list = new ArrayList<>();
// 查询顶级项目
List<BusProject> projectList = projectService.lambdaQuery()
.select(BusProject::getId, BusProject::getProjectName, BusProject::getActual, BusProject::getPlan)
.eq(BusProject::getStatus, 0)
.eq(BusProject::getPId, 0)
.list();
// 计划产值
List<OutValueAllocation> planList = outValueAllocationService.lambdaQuery()
.select(OutValueAllocation::getProjectId, OutValueAllocation::getOwnerTotalValue)
.list();
Map<Long, BigDecimal> planMap = planList.stream()
.collect(Collectors.toMap(OutValueAllocation::getProjectId, OutValueAllocation::getOwnerTotalValue));
// 实际产值
// 施工产值
List<OutConstructionValue> constructionValueList = outConstructionValueService.lambdaQuery()
.select(OutConstructionValue::getProjectId, OutConstructionValue::getOwnerValue)
.eq(OutConstructionValue::getAuditStatus, BusinessStatusEnum.FINISH.getStatus())
.list();
// 采购产值
// 设计产值
List<OutMonthPlanAudit> designValueList = outMonthPlanAuditService.lambdaQuery()
.select(OutMonthPlanAudit::getProjectId, OutMonthPlanAudit::getDesignValue)
.eq(OutMonthPlanAudit::getType, "1")
.list();
// 封装数据
projectList.stream().map(project -> {
OutputValueComparisonVo vo = new OutputValueComparisonVo();
vo.setProjectId(project.getId());
vo.setProjectName(project.getProjectName());
vo.setPlanValue(planMap.getOrDefault(project.getId(), BigDecimal.ZERO));
// 设计产值
List<OutMonthPlanAudit> designValue = designValueList.stream()
.filter(design -> design.getProjectId().equals(project.getId()))
.toList();
vo.setActualValue(designValue.stream()
.filter(Objects::nonNull)
.map(OutMonthPlanAudit::getDesignValue)
.reduce(BigDecimal.ZERO, BigDecimal::add));
// 施工产值
return vo;
}).toList();
return list;
}
/**
* 获取3天的天气列表
*
@ -22,6 +259,6 @@ public class EnterpriseBigScreenServiceImpl implements EnterpriseBigScreenServic
*/
@Override
public List<WeatherVo> getWeather3DaysList(WeatherQueryReq req) {
return List.of();
return weatherManager.getWeatherListVo(req.getLng(), req.getLat(), WeatherConstant.THREE_DAYS_WEATHER_PATH);
}
}

View File

@ -4,10 +4,10 @@ import jakarta.annotation.Resource;
import org.dromara.bigscreen.service.MoneyBigScreenService;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.vo.project.BusProjectGisVo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.dromara.project.service.IBusProjectService;
import org.springframework.stereotype.Service;
@ -40,7 +40,7 @@ public class MoneyBigScreenServiceImpl implements MoneyBigScreenService {
* @return 项目天气
*/
@Override
public List<BusProjectWeatherVo> getProjectWeather(Long projectId) {
public List<WeatherVo> getProjectWeather(Long projectId) {
checkProject(projectId);
return projectService.getWeather(projectId);
}

View File

@ -16,6 +16,7 @@ import org.dromara.common.utils.BigDecimalUtil;
import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.contractor.service.ISubConstructionUserService;
import org.dromara.gps.domain.bo.GpsEquipmentBo;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.enums.PgsProgressUnitTypeEnum;
import org.dromara.progress.service.IPgsProgressCategoryService;
@ -23,7 +24,6 @@ import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.BusProjectTeam;
import org.dromara.project.domain.BusProjectTeamMember;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo;
import org.dromara.project.service.*;
import org.dromara.safety.domain.HseRecognizeRecord;
@ -75,7 +75,7 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
* @return 项目天气
*/
@Override
public List<BusProjectWeatherVo> getProjectWeather(Long projectId) {
public List<WeatherVo> getProjectWeather(Long projectId) {
checkProject(projectId);
return projectService.getWeather(projectId);
}

View File

@ -1,11 +1,17 @@
package org.dromara.manager.weathermanager;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@ -16,7 +22,10 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;
/**
* @author lilemy
@ -58,6 +67,67 @@ public class WeatherManager {
return body;
}
/**
* 获取天气
*
* @param lng 经度
* @param lat 纬度
* @param weatherPath 天气请求路径
* @return 天气信息
*/
public List<WeatherVo> getWeatherListVo(String lng, String lat, String weatherPath) {
String weather = this.getWeather(lng, lat, weatherPath);
// 解析为 JSONObject
JSONObject weatherJson = JSONUtil.parseObj(weather);
// 获取 daily 数组
JSONArray dailyArray = weatherJson.getJSONArray(WeatherConstant.DAILY);
// 循环遍历,封装项目天气信息
List<WeatherVo> weatherList = new ArrayList<>();
for (int i = 0; i < dailyArray.size(); i++) {
JSONObject day = dailyArray.getJSONObject(i);
WeatherVo weatherVo = new WeatherVo();
// 获取星期
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 = this.getWeatherCategory(textDay, weatherStatusMap);
String nightStatus = this.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);
}
return weatherList;
}
/**
* 根据天气图标获取天气类别
*
* @param icon 天气图标
* @param map 天气图标与天气类别的映射关系
* @return 天气类别
*/
public 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";
}
/**
* 获取天气预报 Url
*

View File

@ -8,10 +8,7 @@ import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailPercentageCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailQueryReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq;
import org.dromara.progress.domain.dto.progressplandetail.*;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailUnFinishVo;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailVo;
@ -62,6 +59,16 @@ public class PgsProgressPlanDetailController extends BaseController {
return toAjax(pgsProgressPlanDetailService.insertPercentageDetail(req));
}
/**
* 新增进度计划详情(数量设施)
*/
@SaCheckPermission("progress:progressPlanDetail:insertNumber")
@RepeatSubmit()
@PostMapping("/insert/number")
public R<Void> insertNumberDetail(@Validated @RequestBody PgsProgressPlanDetailNumberCreateReq req) {
return toAjax(pgsProgressPlanDetailService.insertNumberDetail(req));
}
/**
* 获取进度计划详情已完成设施详细信息
*

View File

@ -0,0 +1,31 @@
package org.dromara.progress.domain.dto.progressplandetail;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-09-09 18:06
*/
@Data
public class PgsProgressPlanDetailNumberCreateReq implements Serializable {
@Serial
private static final long serialVersionUID = 6264982582390127674L;
/**
* 主键id
*/
@NotNull(message = "主键id不能为空")
private Long id;
/**
* 完成数量
*/
@NotNull(message = "完成数量不能为空")
private BigDecimal finishedNumber;
}

View File

@ -6,10 +6,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailPercentageCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailQueryReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq;
import org.dromara.progress.domain.dto.progressplandetail.*;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNumVo;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailUnFinishVo;
@ -51,6 +48,14 @@ public interface IPgsProgressPlanDetailService extends IService<PgsProgressPlanD
*/
Boolean insertPercentageDetail(PgsProgressPlanDetailPercentageCreateReq req);
/**
* 插入进度计划详情设施
*
* @param req 插入进度计划详情设施参数
* @return 是否插入成功
*/
Boolean insertNumberDetail(PgsProgressPlanDetailNumberCreateReq req);
/**
* 分页查询进度计划详情已完成设施列表
*

View File

@ -26,12 +26,8 @@ import org.dromara.progress.constant.PgsProgressCategoryConstant;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.PgsProgressPlan;
import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailPercentageCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailQueryReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq;
import org.dromara.progress.domain.dto.progressplandetail.*;
import org.dromara.progress.domain.enums.PgsFinishStatusEnum;
import org.dromara.progress.domain.enums.PgsProgressUnitTypeEnum;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNumVo;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailUnFinishVo;
@ -354,12 +350,76 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
BigDecimal completed = progressCategory.getCompleted();
BigDecimal completedTotal = completed.subtract(number).add(finishedNumber);
progressCategory.setCompleted(completedTotal);
if (progressCategory.getUnitType().equals(PgsProgressUnitTypeEnum.NUMBER.getValue())
&& completedTotal.compareTo(progressCategory.getTotal()) == 0) {
if (completedTotal.compareTo(BigDecimal.valueOf(100)) == 0) {
progressCategory.setStatus(PgsFinishStatusEnum.FINISH.getValue());
}
if (progressCategory.getUnitType().equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue())
&& completedTotal.compareTo(BigDecimal.valueOf(100)) == 0) {
// 判断当前是否已完成计划数量
BigDecimal nowFinishedNumber = progressPlan.getFinishedNumber();
if (oldFinishedNumberTotal.compareTo(progressPlan.getPlanNumber()) < 0
&& nowFinishedNumber.compareTo(progressPlan.getPlanNumber()) >= 0) {
progressCategory.setPlanTotal(progressCategory.getPlanTotal().subtract(progressPlan.getPlanNumber()));
}
boolean updateCategory = progressCategoryService.updateById(progressCategory);
if (!updateCategory) {
throw new ServiceException("更新进度分类异常", HttpStatus.ERROR);
}
return true;
}
/**
* 插入进度计划详情设施
*
* @param req 插入进度计划详情设施参数
* @return 是否插入成功
*/
@Override
public Boolean insertNumberDetail(PgsProgressPlanDetailNumberCreateReq req) {
// 校验
BigDecimal finishedNumber = req.getFinishedNumber();
// 判断是否小于 0
if (finishedNumber.compareTo(BigDecimal.ZERO) < 0) {
throw new ServiceException("完成数量不能小于0", HttpStatus.BAD_REQUEST);
}
Long id = req.getId();
PgsProgressPlanDetail progressPlanDetail = this.getById(id);
if (progressPlanDetail == null) {
throw new ServiceException("进度计划详情信息不存在", HttpStatus.NOT_FOUND);
}
Long progressPlanId = progressPlanDetail.getProgressPlanId();
PgsProgressPlan progressPlan = progressPlanService.getById(progressPlanId);
if (progressPlan == null) {
throw new ServiceException("进度计划信息不存在", HttpStatus.NOT_FOUND);
}
Long progressCategoryId = progressPlanDetail.getProgressCategoryId();
PgsProgressCategory progressCategory = progressCategoryService.getById(progressCategoryId);
if (progressCategory == null) {
throw new ServiceException("进度计划类别信息不存在", HttpStatus.NOT_FOUND);
}
// 校验:总完成数不能超过总计划数
BigDecimal number = progressPlanDetail.getFinishedNumber(); // 旧的完成数
BigDecimal oldFinishedNumberTotal = progressPlan.getFinishedNumber();
BigDecimal newFinishedNumberTotal = oldFinishedNumberTotal.subtract(number).add(finishedNumber);
if (newFinishedNumberTotal.compareTo(progressPlan.getPlanNumber()) > 0) {
throw new ServiceException("总完成数量不能超过计划数量", HttpStatus.BAD_REQUEST);
}
// 更新 detail
progressPlanDetail.setFinishedNumber(finishedNumber);
boolean update = this.updateById(progressPlanDetail);
if (!update) {
throw new ServiceException("更新进度计划详情异常", HttpStatus.ERROR);
}
// 更新 plan
progressPlan.setFinishedNumber(newFinishedNumberTotal);
boolean result = progressPlanService.updateById(progressPlan);
if (!result) {
throw new ServiceException("更新进度计划异常", HttpStatus.ERROR);
}
// 更新 category
BigDecimal completed = progressCategory.getCompleted();
BigDecimal completedTotal = completed.subtract(number).add(finishedNumber);
progressCategory.setCompleted(completedTotal);
// 如果完成数量 >= 总数量,标记为完成
if (completedTotal.compareTo(progressCategory.getTotal()) >= 0) {
progressCategory.setStatus(PgsFinishStatusEnum.FINISH.getValue());
}
// 判断当前是否已完成计划数量

View File

@ -17,6 +17,7 @@ import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.project.domain.dto.project.*;
import org.dromara.project.domain.vo.project.*;
import org.dromara.project.service.IBusProjectService;
@ -190,7 +191,7 @@ public class BusProjectController extends BaseController {
* 查询项目天气
*/
@GetMapping("/weather/{id}")
public R<List<BusProjectWeatherVo>> getWeather(@NotNull(message = "主键不能为空")
public R<List<WeatherVo>> getWeather(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(projectService.getWeather(id));
}

View File

@ -1,68 +0,0 @@
package org.dromara.project.domain.vo.project;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @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;
}

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.dto.project.*;
import org.dromara.project.domain.vo.project.*;
@ -173,7 +174,7 @@ public interface IBusProjectService extends IService<BusProject> {
* @param id 项目id
* @return 天气信息列表
*/
List<BusProjectWeatherVo> getWeather(Long id);
List<WeatherVo> getWeather(Long id);
/**
* 获取项目安全天数

View File

@ -3,12 +3,8 @@ package org.dromara.project.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
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.toolkit.Wrappers;
@ -38,6 +34,7 @@ import org.dromara.facility.domain.vo.matrix.FacMatrixStructureVo;
import org.dromara.facility.service.IFacMatrixService;
import org.dromara.manager.weathermanager.WeatherConstant;
import org.dromara.manager.weathermanager.WeatherManager;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.enums.PgsRelevancyStructureEnum;
import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryStructureVo;
@ -807,7 +804,7 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
* @return 天气信息列表
*/
@Override
public List<BusProjectWeatherVo> getWeather(Long id) {
public List<WeatherVo> getWeather(Long id) {
BusProject project = this.getById(id);
if (project == null) {
throw new ServiceException("项目不存在");
@ -818,7 +815,7 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
String cachedValue = WEATHER_CACHE.getIfPresent(cacheKey);
if (cachedValue != null) {
// 如果缓存命中,返回结果
return JSONUtil.toList(cachedValue, BusProjectWeatherVo.class);
return JSONUtil.toList(cachedValue, WeatherVo.class);
}
// 查询分布式缓存Redis
ValueOperations<String, String> valueOps = stringRedisTemplate.opsForValue();
@ -826,7 +823,7 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
if (cachedValue != null) {
// 如果命中Redis存入本地缓存并返回结果
WEATHER_CACHE.put(cacheKey, cachedValue);
return JSONUtil.toList(cachedValue, BusProjectWeatherVo.class);
return JSONUtil.toList(cachedValue, WeatherVo.class);
}
// 获取当天及之后的天气信息
String lng = project.getLng();
@ -834,39 +831,7 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
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);
}
List<WeatherVo> weatherList = weatherManager.getWeatherListVo(lng, lat, WeatherConstant.THREE_DAYS_WEATHER_PATH);
// 更新缓存
String cacheValue = JSONUtil.toJsonStr(weatherList);
// 更新本地缓存
@ -1172,20 +1137,4 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
return roots;
}
/**
* 根据天气图标获取天气类别
*
* @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";
}
}