进度管理大屏,摄像头排序

This commit is contained in:
lcj
2025-12-16 10:14:00 +08:00
parent 654623ad15
commit aa3628f041
28 changed files with 887 additions and 21 deletions

View File

@ -0,0 +1,77 @@
package org.dromara.bigscreen.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.bigscreen.domain.dto.ProjectImageProgressDetailReq;
import org.dromara.bigscreen.domain.progress.DesignProgressVo;
import org.dromara.bigscreen.domain.progress.MilestoneProgressVo;
import org.dromara.bigscreen.domain.progress.ProjectTotalProgressVo;
import org.dromara.bigscreen.domain.vo.ProjectImageProgressDetailVo;
import org.dromara.bigscreen.service.ProgressBigScreenService;
import org.dromara.bigscreen.service.ProjectBigScreenService;
import org.dromara.common.core.domain.R;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 进度管理大屏接口
*
* @author lilemy
* @date 2025-12-15 11:35
*/
@SaIgnore
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/progress/big/screen")
public class ProgressBigScreenController extends BaseController {
@Resource
private ProgressBigScreenService progressBigScreenService;
@Resource
private ProjectBigScreenService projectBigScreenService;
/**
* 获取项目总进度
*/
@GetMapping("/projectTotalProgress/{projectId}")
public R<ProjectTotalProgressVo> getProjectTotalProgress(@NotNull(message = "项目主键不能为空")
@PathVariable Long projectId) {
return R.ok(progressBigScreenService.getProjectTotalProgress(projectId));
}
/**
* 获取里程碑进度
*/
@GetMapping("/milestoneProgress/{projectId}")
public R<List<MilestoneProgressVo>> getMilestoneProgress(@NotNull(message = "项目主键不能为空")
@PathVariable Long projectId) {
return R.ok(progressBigScreenService.getMilestoneProgress(projectId));
}
/**
* 获取设计进度
*/
@GetMapping("/designProgress/{projectId}")
public R<DesignProgressVo> getDesignProgress(@NotNull(message = "项目主键不能为空")
@PathVariable Long projectId) {
return R.ok(progressBigScreenService.getDesignProgress(projectId));
}
/**
* 获取施工进度详情
*/
@GetMapping("/constructionProgress/detail")
public R<List<ProjectImageProgressDetailVo>> getProjectImageProgressDetail(@Validated ProjectImageProgressDetailReq req) {
return R.ok(projectBigScreenService.getProjectImageProgressDetail(req));
}
}

View File

@ -0,0 +1,27 @@
package org.dromara.bigscreen.domain.progress;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-15 17:30
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DesignProgressMajorVo {
/**
* 专业名称
*/
private String majorName;
/**
* 完成率
*/
private BigDecimal completionRate;
}

View File

@ -0,0 +1,94 @@
package org.dromara.bigscreen.domain.progress;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
/**
* @author lilemy
* @date 2025-12-15 17:07
*/
@Data
public class DesignProgressVo implements Serializable {
@Serial
private static final long serialVersionUID = 379443600182489913L;
/**
* 总设计任务进度
*/
private Long totalDesignProgress;
/**
* 当前设计任务进度
*/
private Long currentDesignProgress;
/**
* 设计任务进度趋势
*/
private Boolean designProgressTrend;
/**
* 设计任务进度环比
*/
private BigDecimal designProgressRate;
/**
* 总设计
*/
private Long totalDesign;
/**
* 已审核设计
*/
private Long reviewedDesign;
/**
* 已审核设计进度趋势
*/
private Boolean reviewedDesignTrend;
/**
* 已审核设计进度环比
*/
private BigDecimal reviewedDesignRate;
/**
* 待审核设计
*/
private Long pendingDesignReview;
/**
* 待审核设计进度趋势
*/
private Boolean pendingDesignReviewTrend;
/**
* 待审核设计进度环比
*/
private BigDecimal pendingDesignReviewRate;
/**
* 已逾期设计
*/
private Long delayedDesign;
/**
* 已逾期设计进度趋势
*/
private Boolean delayedDesignTrend;
/**
* 已逾期设计进度环比
*/
private BigDecimal delayedDesignRate;
/**
* 设计专业详情
*/
List<DesignProgressMajorVo> majorList;
}

View File

@ -0,0 +1,64 @@
package org.dromara.bigscreen.domain.progress;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* @author lilemy
* @date 2025-12-15 16:15
*/
@Data
public class MilestoneProgressVo implements Serializable {
@Serial
private static final long serialVersionUID = 5731146976460407811L;
/**
* 主键 ID
*/
private Long id;
/**
* 节点名称
*/
private String nodeName;
/**
* 对应项目结构
*/
private Long projectStructure;
/**
* 对应项目结构名称
*/
private String projectStructureName;
/**
* 预计开始时间
*/
private LocalDate planStartDate;
/**
* 预计结束时间
*/
private LocalDate planEndDate;
/**
* 实际开始时间
*/
private LocalDate practicalStartDate;
/**
* 实际结束时间
*/
private LocalDate practicalEndDate;
/**
* 当前进度
*/
private BigDecimal currentProgress;
}

View File

@ -0,0 +1,37 @@
package org.dromara.bigscreen.domain.progress;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-15 14:40
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProjectTotalProgressDetailVo {
/**
* 名称
*/
private String name;
/**
* 实际进度
*/
private BigDecimal actualProgress;
/**
* 计划进度
*/
private BigDecimal planProgress;
/**
* 完成率
*/
private BigDecimal completionRate;
}

View File

@ -0,0 +1,49 @@
package org.dromara.bigscreen.domain.progress;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
/**
* @author lilemy
* @date 2025-12-15 14:23
*/
@Data
public class ProjectTotalProgressVo implements Serializable {
@Serial
private static final long serialVersionUID = -5706098940478706815L;
/**
* 总进度
*/
private BigDecimal totalProgress;
/**
* 总计划工期(天)
*/
private Long totalPlannedDuration;
/**
* 当前计划工期(天)
*/
private Long currentPlannedDuration;
/**
* 总完成情况(万元)
*/
private BigDecimal totalCompletionAmount;
/**
* 当前完成情况(万元)
*/
private BigDecimal currentCompletionAmount;
/**
* 详情
*/
private List<ProjectTotalProgressDetailVo> detailList;
}

View File

@ -0,0 +1,38 @@
package org.dromara.bigscreen.service;
import org.dromara.bigscreen.domain.progress.DesignProgressVo;
import org.dromara.bigscreen.domain.progress.MilestoneProgressVo;
import org.dromara.bigscreen.domain.progress.ProjectTotalProgressVo;
import java.util.List;
/**
* @author lilemy
* @date 2025-12-15 14:18
*/
public interface ProgressBigScreenService {
/**
* 获取项目总进度
*
* @param projectId 项目 id
* @return 项目总进度
*/
ProjectTotalProgressVo getProjectTotalProgress(Long projectId);
/**
* 获取里程碑进度
*
* @param projectId 项目 id
* @return 里程碑进度
*/
List<MilestoneProgressVo> getMilestoneProgress(Long projectId);
/**
* 获取设计进度
*
* @param projectId 项目 id
* @return 设计进度
*/
DesignProgressVo getDesignProgress(Long projectId);
}

View File

@ -0,0 +1,295 @@
package org.dromara.bigscreen.service.impl;
import cn.hutool.core.collection.CollUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.bigscreen.domain.progress.*;
import org.dromara.bigscreen.service.ProgressBigScreenService;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.utils.BigDecimalUtil;
import org.dromara.design.domain.DesVolumeCatalog;
import org.dromara.design.domain.DesVolumeFile;
import org.dromara.design.service.IDesVolumeCatalogService;
import org.dromara.design.service.IDesVolumeFileService;
import org.dromara.progress.constant.PgsProgressCategoryConstant;
import org.dromara.progress.domain.PgsConstructionSchedulePlan;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanQueryReq;
import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryValueTotalVo;
import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanDateVo;
import org.dromara.progress.service.IPgsConstructionSchedulePlanService;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.progress.service.IPgsProgressPlanService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.dromara.system.domain.vo.SysDictDataVo;
import org.dromara.system.service.ISysDictDataService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author lilemy
* @date 2025-12-15 14:18
*/
@Slf4j
@Service
public class ProgressBigScreenServiceImpl implements ProgressBigScreenService {
@Resource
private IBusProjectService projectService;
@Resource
private IPgsProgressCategoryService progressCategoryService;
@Resource
private IPgsProgressPlanService progressPlanService;
@Resource
private IPgsConstructionSchedulePlanService constructionSchedulePlanService;
@Resource
private IDesVolumeCatalogService volumeCatalogService;
@Resource
private IDesVolumeFileService volumeFileService;
@Resource
private ISysDictDataService dictDataService;
/**
* 获取项目总进度
*
* @param projectId 项目 id
* @return 项目总进度
*/
@Override
public ProjectTotalProgressVo getProjectTotalProgress(Long projectId) {
ProjectTotalProgressVo vo = new ProjectTotalProgressVo();
// 获取项目和项目子项
BusProject project = projectService.getById(projectId);
if (project == null) {
return vo;
}
List<BusProject> projects = projectService.lambdaQuery()
.eq(BusProject::getPId, projectId)
.list();
projects.add(project);
List<Long> projectIds = projects.stream().map(BusProject::getId).toList();
// 获取当前项目所有父级类别
List<PgsProgressCategory> topList = progressCategoryService.lambdaQuery()
.in(PgsProgressCategory::getProjectId, projectIds)
.eq(PgsProgressCategory::getParentId, PgsProgressCategoryConstant.TOP_PARENT_ID)
.list();
if (CollUtil.isEmpty(topList)) {
return vo;
}
List<Long> topIds = topList.stream().map(PgsProgressCategory::getId).toList();
List<PgsProgressCategory> children = progressCategoryService.getLeafNodesByTopIds(topIds);
BigDecimal completedPercentage = progressCategoryService.getCompletedPercentage(children);
vo.setTotalProgress(completedPercentage);
// 获取总计划工期
PgsProgressPlanQueryReq queryDate = new PgsProgressPlanQueryReq();
queryDate.setProjectId(projectId);
PgsProgressPlanDateVo dateVo = progressPlanService.queryDate(queryDate);
if (dateVo != null && dateVo.getStartDate() != null && dateVo.getEndDate() != null) {
LocalDate startDate = dateVo.getStartDate();
LocalDate endDate = dateVo.getEndDate();
LocalDate now = LocalDate.now();
long totalDays = ChronoUnit.DAYS.between(startDate, endDate);
vo.setTotalPlannedDuration(totalDays);
if (now.isAfter(endDate)) {
vo.setCurrentPlannedDuration(totalDays);
} else if (now.isBefore(startDate)) {
vo.setCurrentPlannedDuration(0L);
} else {
vo.setCurrentPlannedDuration(ChronoUnit.DAYS.between(startDate, now) + 1);
}
}
// 获取整体完成情况
PgsProgressCategoryValueTotalVo valueTotal = progressCategoryService.getValueTotal(children, true);
vo.setTotalCompletionAmount(valueTotal.getTotalValue());
vo.setCurrentCompletionAmount(valueTotal.getCurrentValue());
// 获取详情
Map<String, List<PgsProgressCategory>> nameMap = topList.stream()
.collect(Collectors.groupingBy(PgsProgressCategory::getName));
List<ProjectTotalProgressDetailVo> detailList = new ArrayList<>();
for (Map.Entry<String, List<PgsProgressCategory>> entry : nameMap.entrySet()) {
ProjectTotalProgressDetailVo detailVo = new ProjectTotalProgressDetailVo();
String name = entry.getKey();
detailVo.setName(name);
List<PgsProgressCategory> value = entry.getValue();
List<Long> top = value.stream().map(PgsProgressCategory::getId).toList();
List<PgsProgressCategory> nameChildren = progressCategoryService.getLeafNodesByTopIds(top, children);
BigDecimal completedTotal = nameChildren.stream().map(PgsProgressCategory::getCompleted)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal planTotal = nameChildren.stream().map(PgsProgressCategory::getPlanTotal)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal total = nameChildren.stream().map(PgsProgressCategory::getTotal)
.reduce(BigDecimal.ZERO, BigDecimal::add);
detailVo.setActualProgress(completedTotal);
detailVo.setPlanProgress(planTotal);
detailVo.setCompletionRate(BigDecimalUtil.toPercentage(completedTotal, total));
detailList.add(detailVo);
}
vo.setDetailList(detailList);
return vo;
}
/**
* 获取里程碑进度
*
* @param projectId 项目 id
* @return 里程碑进度
*/
@Override
public List<MilestoneProgressVo> getMilestoneProgress(Long projectId) {
List<MilestoneProgressVo> voList = new ArrayList<>();
List<PgsConstructionSchedulePlan> planList = constructionSchedulePlanService.lambdaQuery()
.eq(PgsConstructionSchedulePlan::getProjectId, projectId)
.list();
if (CollUtil.isEmpty(planList)) {
return voList;
}
List<PgsConstructionSchedulePlan> topList = planList.stream().filter(plan -> plan.getParentId().equals(0L)).toList();
return topList.stream().map(plan -> {
MilestoneProgressVo vo = new MilestoneProgressVo();
BeanUtils.copyProperties(plan, vo);
// 获取子节点
List<PgsConstructionSchedulePlan> allChildren = constructionSchedulePlanService.getAllChildren(plan.getId(), planList);
long count = allChildren.stream().filter(child -> child.getStatus().equals("4")).count();
BigDecimal percentage = BigDecimalUtil.toPercentage(new BigDecimal(count), new BigDecimal(allChildren.size()));
vo.setCurrentProgress(percentage);
return vo;
}).toList();
}
/**
* 获取设计进度
*
* @param projectId 项目 id
* @return 设计进度
*/
@Override
public DesignProgressVo getDesignProgress(Long projectId) {
DesignProgressVo vo = new DesignProgressVo();
List<DesVolumeCatalog> catalogList = volumeCatalogService.lambdaQuery()
.eq(DesVolumeCatalog::getProjectId, projectId).list();
if (CollUtil.isEmpty(catalogList)) {
return vo;
}
LocalDate nowDate = LocalDate.now();
long currentDesignProgress = 0L;
BigDecimal designProgressThisM = BigDecimal.ZERO;
BigDecimal designProgressLastM = BigDecimal.ZERO;
long currentDelay = 0L;
BigDecimal delayThisD = BigDecimal.ZERO;
BigDecimal delayLastD = BigDecimal.ZERO;
// 总数量
vo.setTotalDesignProgress((long) catalogList.size());
LocalDateTime firstDayOfMonth = LocalDateTime.now().withDayOfMonth(1).with(LocalTime.MIN);
LocalDateTime lastMonthFirstDay = LocalDateTime.now().minusMonths(1).withDayOfMonth(1).with(LocalTime.MIN);
for (DesVolumeCatalog catalog : catalogList) {
// 已出图状态
if (catalog.getDesignState().equals("1")) {
currentDesignProgress++;
// 获取当月和上月的完成数量
LocalDateTime finishTime = catalog.getFinishTime();
if (finishTime != null) {
if (finishTime.isAfter(firstDayOfMonth)) {
designProgressThisM = designProgressThisM.add(BigDecimal.ONE);
} else if (finishTime.isBefore(lastMonthFirstDay)) {
designProgressLastM = designProgressLastM.add(BigDecimal.ONE);
}
}
} else if (!catalog.getPlannedCompletion().isAfter(nowDate) && catalog.getDesignState().equals("2")) {
currentDelay++;
if (catalog.getPlannedCompletion().isEqual(nowDate)) {
delayThisD = delayThisD.add(BigDecimal.ONE);
} else if (catalog.getPlannedCompletion().isEqual(nowDate.minusDays(1))) {
delayLastD = delayLastD.add(BigDecimal.ONE);
}
}
}
// 计算完成情况
vo.setCurrentDesignProgress(currentDesignProgress);
vo.setDesignProgressTrend(designProgressThisM.compareTo(designProgressLastM) >= 0);
vo.setDesignProgressRate(BigDecimalUtil.toLoopPercentage(designProgressThisM, designProgressLastM));
// 总逾期数量
vo.setDelayedDesign(currentDelay);
vo.setDelayedDesignTrend(delayThisD.compareTo(delayLastD) >= 0);
vo.setDelayedDesignRate(BigDecimalUtil.toLoopPercentage(delayThisD, delayLastD));
// 获取各专业完成情况
List<DesignProgressMajorVo> majorList = new ArrayList<>();
Map<String, List<DesVolumeCatalog>> specialtyMap = catalogList.stream()
.collect(Collectors.groupingBy(DesVolumeCatalog::getSpecialty));
List<SysDictDataVo> desUserMajor = dictDataService.selectByDictType("des_user_major");
if (CollUtil.isEmpty(desUserMajor)) {
log.error("专业字典 des_user_major 数据不存在");
} else {
Map<String, String> dictMap = desUserMajor.stream()
.collect(Collectors.toMap(SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel));
specialtyMap.forEach((specialty, list) -> {
DesignProgressMajorVo majorVo = new DesignProgressMajorVo();
majorVo.setMajorName(dictMap.getOrDefault(specialty, specialty));
BigDecimal total = new BigDecimal(list.size());
long count = list.stream().filter(catalog -> catalog.getDesignState().equals("1")).count();
majorVo.setCompletionRate(BigDecimalUtil.toPercentage(new BigDecimal(count), total));
majorList.add(majorVo);
});
}
vo.setMajorList(majorList);
// 审核信息
Set<Long> ids = catalogList.stream().map(DesVolumeCatalog::getDesign).collect(Collectors.toSet());
List<DesVolumeFile> fileList = volumeFileService.lambdaQuery()
.in(DesVolumeFile::getVolumeCatalogId, ids)
.list();
long reviewedDesign = 0L;
BigDecimal reviewedDesignThisM = BigDecimal.ZERO;
BigDecimal reviewedDesignLastM = BigDecimal.ZERO;
long pendingReviewDesign = 0L;
BigDecimal pendingReviewDesignThisD = BigDecimal.ZERO;
BigDecimal pendingReviewDesignLastD = BigDecimal.ZERO;
for (DesVolumeFile file : fileList) {
String status = file.getStatus();
if (BusinessStatusEnum.FINISH.getStatus().equals(status)) {
reviewedDesign++;
// 获取当月和上月的完成数量
LocalDateTime finishTime = file.getFinishTime();
if (finishTime != null) {
if (finishTime.isAfter(firstDayOfMonth)) {
reviewedDesignThisM = reviewedDesignThisM.add(BigDecimal.ONE);
} else if (finishTime.isBefore(lastMonthFirstDay)) {
reviewedDesignLastM = reviewedDesignLastM.add(BigDecimal.ONE);
}
}
} else if (BusinessStatusEnum.WAITING.getStatus().equals(status)) {
pendingReviewDesign++;
Date createTime = file.getCreateTime();
LocalDate createDate = createTime.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
if (createDate.isEqual(nowDate)) {
pendingReviewDesignThisD = pendingReviewDesignThisD.add(BigDecimal.ONE);
} else if (createDate.isEqual(nowDate.minusDays(1))) {
pendingReviewDesignLastD = pendingReviewDesignLastD.add(BigDecimal.ONE);
}
}
}
vo.setReviewedDesign(reviewedDesign);
vo.setReviewedDesignTrend(reviewedDesignThisM.compareTo(reviewedDesignLastM) >= 0);
vo.setReviewedDesignRate(BigDecimalUtil.toLoopPercentage(reviewedDesignThisM, reviewedDesignLastM));
vo.setPendingDesignReview(pendingReviewDesign);
vo.setPendingDesignReviewTrend(pendingReviewDesignThisD.compareTo(pendingReviewDesignLastD) >= 0);
vo.setPendingDesignReviewRate(BigDecimalUtil.toLoopPercentage(pendingReviewDesignThisD, pendingReviewDesignLastD));
return vo;
}
}

View File

@ -370,7 +370,7 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
// 如果有叶子节点,统计进度和状态;否则初始化为未完成 // 如果有叶子节点,统计进度和状态;否则初始化为未完成
if (CollUtil.isNotEmpty(leafNodesByTopIds)) { if (CollUtil.isNotEmpty(leafNodesByTopIds)) {
topVo.setProgressTotal(progressCategoryService.getCompletedPercentage(leafNodesByTopIds)); topVo.setProgressTotal(progressCategoryService.getCompletedPercentage(leafNodesByTopIds));
topVo.setValueTotal(progressCategoryService.getValueTotal(leafNodesByTopIds, true)); topVo.setValueTotal(progressCategoryService.getValueTotal(leafNodesByTopIds, true).getCurrentValue());
} else { } else {
topVo.setProgressTotal(BigDecimal.ZERO); topVo.setProgressTotal(BigDecimal.ZERO);
topVo.setValueTotal(BigDecimal.ZERO); topVo.setValueTotal(BigDecimal.ZERO);

View File

@ -25,4 +25,24 @@ public class BigDecimalUtil {
.divide(divisor, 2, RoundingMode.HALF_UP); .divide(divisor, 2, RoundingMode.HALF_UP);
} }
/**
* 计算环比 = (本次 - 上次) / 上次 × 100% 的绝对值
*
* @param thisNum 本次数量
* @param lastNum 上次数量
* @return 环比 = (本次 - 上次) / 上次 × 100% 的绝对值
*/
public static BigDecimal toLoopPercentage(BigDecimal thisNum, BigDecimal lastNum) {
if (thisNum == null || lastNum == null) {
return BigDecimal.valueOf(0.00);
}
if (lastNum.compareTo(BigDecimal.ZERO) == 0) {
return BigDecimal.valueOf(100.00);
}
return thisNum.subtract(lastNum)
.multiply(new BigDecimal("100"))
.divide(lastNum, 2, RoundingMode.HALF_UP)
.abs();
}
} }

View File

@ -8,6 +8,7 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial; import java.io.Serial;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
/** /**
* 卷册目录对象 des_volume_catalog * 卷册目录对象 des_volume_catalog
@ -74,6 +75,11 @@ public class DesVolumeCatalog extends BaseEntity {
*/ */
private LocalDate plannedCompletion; private LocalDate plannedCompletion;
/**
* 实际完成时间
*/
private LocalDateTime finishTime;
/** /**
* 状态(字典) * 状态(字典)
*/ */

View File

@ -1,11 +1,13 @@
package org.dromara.design.domain; package org.dromara.design.domain;
import org.dromara.common.mybatis.core.domain.BaseEntity; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial; import java.io.Serial;
import java.time.LocalDateTime;
/** /**
* 卷册文件对象 des_volume_file * 卷册文件对象 des_volume_file
@ -28,7 +30,6 @@ public class DesVolumeFile extends BaseEntity {
public static final String WASTE = "4"; public static final String WASTE = "4";
/** /**
* 主键ID * 主键ID
*/ */
@ -80,4 +81,9 @@ public class DesVolumeFile extends BaseEntity {
*/ */
private String auditStatus; private String auditStatus;
/**
* 实际完成时间
*/
private LocalDateTime finishTime;
} }

View File

@ -89,6 +89,11 @@ public class DesVolumeCatalogVo implements Serializable {
*/ */
private LocalDate plannedCompletion; private LocalDate plannedCompletion;
/**
* 实际完成时间
*/
private LocalDateTime finishTime;
/** /**
* 状态(字典) * 状态(字典)
*/ */

View File

@ -6,6 +6,7 @@ import org.dromara.design.domain.DesVolumeFile;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime;
/** /**
@ -76,6 +77,11 @@ public class DesVolumeFileVo implements Serializable {
*/ */
private String auditStatus; private String auditStatus;
/**
* 实际完成时间
*/
private LocalDateTime finishTime;
/** /**
* 是否弹窗 * 是否弹窗
*/ */

View File

@ -12,7 +12,6 @@ import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.domain.dto.UserDTO;
import org.dromara.common.core.domain.event.ProcessDeleteEvent; import org.dromara.common.core.domain.event.ProcessDeleteEvent;
import org.dromara.common.core.domain.event.ProcessEvent; import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.domain.event.ProcessTaskEvent; import org.dromara.common.core.domain.event.ProcessTaskEvent;
@ -48,8 +47,8 @@ import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* 卷册文件Service业务层处理 * 卷册文件Service业务层处理
@ -602,9 +601,12 @@ public class DesVolumeFileServiceImpl extends ServiceImpl<DesVolumeFileMapper, D
return; return;
} }
desVolumeFile.setAuditStatus(processEvent.getStatus()); desVolumeFile.setAuditStatus(processEvent.getStatus());
if (processEvent.getStatus().equals(BusinessStatusEnum.FINISH.getStatus())) {
desVolumeFile.setFinishTime(LocalDateTime.now());
}
this.updateById(desVolumeFile); this.updateById(desVolumeFile);
//如果完成,以前的图纸类型变为作废图纸,状态改为作废 暂定 //如果完成,以前的图纸类型变为作废图纸,状态改为作废 暂定
if (processEvent.getStatus().equals("finish")) { if (processEvent.getStatus().equals(BusinessStatusEnum.FINISH.getStatus())) {
// this.lambdaUpdate().set(DesVolumeFile::getStatus, "2") // this.lambdaUpdate().set(DesVolumeFile::getStatus, "2")
// .set(DesVolumeFile::getType, "4") // .set(DesVolumeFile::getType, "4")
// .eq(DesVolumeFile::getVolumeCatalogId, desVolumeFile.getVolumeCatalogId()) // .eq(DesVolumeFile::getVolumeCatalogId, desVolumeFile.getVolumeCatalogId())
@ -684,6 +686,7 @@ public class DesVolumeFileServiceImpl extends ServiceImpl<DesVolumeFileMapper, D
//修改目录状态 //修改目录状态
volumeCatalogService.update(Wrappers.<DesVolumeCatalog>lambdaUpdate() volumeCatalogService.update(Wrappers.<DesVolumeCatalog>lambdaUpdate()
.set(DesVolumeCatalog::getDesignState, "1") .set(DesVolumeCatalog::getDesignState, "1")
.set(DesVolumeCatalog::getFinishTime, LocalDateTime.now())
.eq(DesVolumeCatalog::getDesign, desVolumeFile.getVolumeCatalogId()) .eq(DesVolumeCatalog::getDesign, desVolumeFile.getVolumeCatalogId())
); );
//异步处理二维码 //异步处理二维码

View File

@ -43,18 +43,17 @@ public class IncSyncYs7DeviceData {
} }
} }
//同步摄像头全天录像开关状态 //同步摄像头全天录像开关状态 每 1 天执行一次
// 每 1 分钟执行一次
@Scheduled(cron = "1 0 0 * * ?") @Scheduled(cron = "1 0 0 * * ?")
// @Scheduled(cron = "0 */10 * * * ?") // @Scheduled(cron = "0 */10 * * * ?")
public void getEnable() { public void getEnable() {
log.info("定时同步摄像头设备数据"); log.info("定时同步摄像头全天录像开关状态");
List<OthYs7Device> ys7DeviceList = ys7DeviceService.getBaseMapper().selectList(new LambdaQueryWrapper<OthYs7Device>().orderByDesc(OthYs7Device::getCreateTime)); List<OthYs7Device> ys7DeviceList = ys7DeviceService.getBaseMapper().selectList(new LambdaQueryWrapper<OthYs7Device>().orderByDesc(OthYs7Device::getCreateTime));
Boolean result = ys7DeviceService.saveOrUpdateEnableByDeviceList(ys7DeviceList); Boolean result = ys7DeviceService.saveOrUpdateEnableByDeviceList(ys7DeviceList);
if (result) { if (result) {
log.info("定时同步摄像头设备数据成功"); log.info("定时同步摄像头全天录像开关状态成功");
} else { } else {
log.info("没有需要定时同步的设备"); log.info("没有需要定时同步的摄像头全天录像开关状态");
} }
} }

View File

@ -111,6 +111,11 @@ public class OthYs7Device implements Serializable {
*/ */
private String detail; private String detail;
/**
* 排序
*/
private Integer sortData;
/** /**
* 备注 * 备注
*/ */

View File

@ -40,6 +40,11 @@ public class OthYs7DeviceUpdateReq implements Serializable {
*/ */
private String detail; private String detail;
/**
* 排序
*/
private Integer sortData;
/** /**
* 备注 * 备注
*/ */

View File

@ -97,6 +97,11 @@ public class OthYs7DeviceVo implements Serializable {
*/ */
private String detail; private String detail;
/**
* 排序
*/
private Integer sortData;
/** /**
* 备注 * 备注
*/ */

View File

@ -290,6 +290,7 @@ public class OthYs7DeviceServiceImpl extends ServiceImpl<OthYs7DeviceMapper, Oth
lqw.like(StringUtils.isNotBlank(deviceType), OthYs7Device::getDeviceType, deviceType); lqw.like(StringUtils.isNotBlank(deviceType), OthYs7Device::getDeviceType, deviceType);
lqw.like(StringUtils.isNotBlank(deviceSerial), OthYs7Device::getDeviceSerial, deviceSerial); lqw.like(StringUtils.isNotBlank(deviceSerial), OthYs7Device::getDeviceSerial, deviceSerial);
lqw.like(StringUtils.isNotBlank(deviceVersion), OthYs7Device::getDeviceVersion, deviceVersion); lqw.like(StringUtils.isNotBlank(deviceVersion), OthYs7Device::getDeviceVersion, deviceVersion);
lqw.orderByAsc(OthYs7Device::getSortData);
lqw.orderByDesc(OthYs7Device::getProjectId); lqw.orderByDesc(OthYs7Device::getProjectId);
lqw.orderByDesc(OthYs7Device::getStatus); lqw.orderByDesc(OthYs7Device::getStatus);
return lqw; return lqw;
@ -478,6 +479,7 @@ public class OthYs7DeviceServiceImpl extends ServiceImpl<OthYs7DeviceMapper, Oth
/** /**
* 查询范围日期和设备本地录像列表 * 查询范围日期和设备本地录像列表
*
* @param req * @param req
* @return * @return
*/ */
@ -488,8 +490,8 @@ public class OthYs7DeviceServiceImpl extends ServiceImpl<OthYs7DeviceMapper, Oth
vo.setDateList(dateList); vo.setDateList(dateList);
if (CollectionUtils.isNotEmpty(dateList) && dateList.size() > 1) { if (CollectionUtils.isNotEmpty(dateList) && dateList.size() > 1) {
String first = dateList.getFirst(); String first = dateList.getFirst();
req.setStartTime(first+" 00:00:00"); req.setStartTime(first + " 00:00:00");
req.setEndTime(first+" 23:59:59"); req.setEndTime(first + " 23:59:59");
} }
List<DeviceLocalVideoRecordsVo> deviceLocalVideo = getDeviceLocalVideo(req); List<DeviceLocalVideoRecordsVo> deviceLocalVideo = getDeviceLocalVideo(req);
vo.setDeviceList(deviceLocalVideo); vo.setDeviceList(deviceLocalVideo);

View File

@ -0,0 +1,28 @@
package org.dromara.progress.domain.vo.progresscategory;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author lilemy
* @date 2025-12-15 15:28
*/
@Data
public class PgsProgressCategoryValueTotalVo implements Serializable {
@Serial
private static final long serialVersionUID = 3568038376181464491L;
/**
* 总产值
*/
private BigDecimal totalValue;
/**
* 当前产值
*/
private BigDecimal currentValue;
}

View File

@ -0,0 +1,28 @@
package org.dromara.progress.domain.vo.progressplan;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
/**
* @author lilemy
* @date 2025-12-15 15:01
*/
@Data
public class PgsProgressPlanDateVo implements Serializable {
@Serial
private static final long serialVersionUID = -2179633422685929795L;
/**
* 计划开始时间
*/
private LocalDate startDate;
/**
* 计划结束时间
*/
private LocalDate endDate;
}

View File

@ -91,6 +91,15 @@ public interface IPgsConstructionSchedulePlanService extends IService<PgsConstru
*/ */
List<PgsConstructionSchedulePlanVo> getVoList(List<PgsConstructionSchedulePlan> constructionSchedulePlanList); List<PgsConstructionSchedulePlanVo> getVoList(List<PgsConstructionSchedulePlan> constructionSchedulePlanList);
/**
* 获取所有子节点
*
* @param parentId 父节点 ID
* @param allList 所有节点列表
* @return 所有子节点列表
*/
List<PgsConstructionSchedulePlan> getAllChildren(Long parentId, List<PgsConstructionSchedulePlan> allList);
/** /**
* 导出Excel * 导出Excel
* *

View File

@ -220,7 +220,7 @@ public interface IPgsProgressCategoryService extends IService<PgsProgressCategor
* @param selectValue true:业主产值 false:分包产值 * @param selectValue true:业主产值 false:分包产值
* @return 项目进度产值 * @return 项目进度产值
*/ */
BigDecimal getValueTotal(List<PgsProgressCategory> categoryList, Boolean selectValue); PgsProgressCategoryValueTotalVo getValueTotal(List<PgsProgressCategory> categoryList, Boolean selectValue);
/** /**
* 获取项目进度类别未完成数量 * 获取项目进度类别未完成数量

View File

@ -9,6 +9,7 @@ import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.PgsProgressPlan; import org.dromara.progress.domain.PgsProgressPlan;
import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanCreateReq; import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanCreateReq;
import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanQueryReq; import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanQueryReq;
import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanDateVo;
import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanVo; import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanVo;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -47,6 +48,14 @@ public interface IPgsProgressPlanService extends IService<PgsProgressPlan> {
*/ */
List<PgsProgressPlanVo> queryList(PgsProgressPlanQueryReq req); List<PgsProgressPlanVo> queryList(PgsProgressPlanQueryReq req);
/**
* 查询进度计划日期(最早的开始时间和最晚的结束时间)
*
* @param req 查询条件
* @return 进度计划日期(最早的开始时间和最晚的结束时间)
*/
PgsProgressPlanDateVo queryDate(PgsProgressPlanQueryReq req);
/** /**
* 新增进度计划 * 新增进度计划
* *

View File

@ -199,6 +199,26 @@ public class PgsConstructionSchedulePlanServiceImpl extends ServiceImpl<PgsConst
return constructionSchedulePlanList.stream().map(this::getVo).toList(); return constructionSchedulePlanList.stream().map(this::getVo).toList();
} }
/**
* 获取所有子节点
*
* @param parentId 父节点 ID
* @param allList 所有节点列表
* @return 所有子节点列表
*/
@Override
public List<PgsConstructionSchedulePlan> getAllChildren(Long parentId, List<PgsConstructionSchedulePlan> allList) {
List<PgsConstructionSchedulePlan> result = new ArrayList<>();
for (PgsConstructionSchedulePlan node : allList) {
if (Objects.equals(node.getParentId(), parentId)) {
result.add(node);
// 递归找子节点
result.addAll(getAllChildren(node.getId(), allList));
}
}
return result;
}
// region 导出 excel // region 导出 excel
/** /**

View File

@ -1547,10 +1547,14 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
// 遍历所有项目进度,计算总完成数和总数 // 遍历所有项目进度,计算总完成数和总数
for (PgsProgressCategory category : categoryList) { for (PgsProgressCategory category : categoryList) {
String unitType = category.getUnitType();
if (StringUtils.isBlank(unitType) || PgsProgressUnitTypeEnum.NULL.getValue().equals(unitType)) {
continue;
}
BigDecimal completed = category.getCompleted(); BigDecimal completed = category.getCompleted();
BigDecimal total = category.getTotal(); BigDecimal total = category.getTotal();
if (PgsProgressUnitTypeEnum.PERCENTAGE.getValue().equals(category.getUnitType())) { if (PgsProgressUnitTypeEnum.PERCENTAGE.getValue().equals(unitType)) {
completed = completed.divide(BigDecimal.valueOf(100L), 4, RoundingMode.HALF_UP).multiply(total); completed = completed.divide(BigDecimal.valueOf(100L), 4, RoundingMode.HALF_UP).multiply(total);
} }
@ -1646,14 +1650,17 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
* @return 项目进度产值 * @return 项目进度产值
*/ */
@Override @Override
public BigDecimal getValueTotal(List<PgsProgressCategory> categoryList, Boolean selectValue) { public PgsProgressCategoryValueTotalVo getValueTotal(List<PgsProgressCategory> categoryList, Boolean selectValue) {
PgsProgressCategoryValueTotalVo vo = new PgsProgressCategoryValueTotalVo();
vo.setCurrentValue(BigDecimal.ZERO);
vo.setTotalValue(BigDecimal.ZERO);
// 如果没有数据则返回0 // 如果没有数据则返回0
if (CollUtil.isEmpty(categoryList)) { if (CollUtil.isEmpty(categoryList)) {
return BigDecimal.ZERO; return vo;
} }
BigDecimal currentValue = BigDecimal.ZERO;
BigDecimal totalValue = BigDecimal.ZERO; BigDecimal totalValue = BigDecimal.ZERO;
// 遍历所有项目进度,计算总完成数和总数 // 遍历所有项目进度,计算总完成数和总数
for (PgsProgressCategory category : categoryList) { for (PgsProgressCategory category : categoryList) {
BigDecimal completed = category.getCompleted(); BigDecimal completed = category.getCompleted();
@ -1662,9 +1669,12 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
if (PgsProgressUnitTypeEnum.PERCENTAGE.getValue().equals(category.getUnitType())) { if (PgsProgressUnitTypeEnum.PERCENTAGE.getValue().equals(category.getUnitType())) {
completed = completed.divide(BigDecimal.valueOf(100L), 4, RoundingMode.HALF_UP).multiply(total); completed = completed.divide(BigDecimal.valueOf(100L), 4, RoundingMode.HALF_UP).multiply(total);
} }
totalValue = totalValue.add(completed.multiply(price)); currentValue = currentValue.add(completed.multiply(price));
totalValue = totalValue.add(selectValue ? category.getOwnerOutputValue() : category.getConstructionOutputValue());
} }
return totalValue.setScale(4, RoundingMode.HALF_UP); vo.setCurrentValue(currentValue.setScale(4, RoundingMode.HALF_UP));
vo.setTotalValue(totalValue.setScale(4, RoundingMode.HALF_UP));
return vo;
} }
/** /**

View File

@ -22,6 +22,7 @@ import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailC
import org.dromara.progress.domain.enums.PgsDelayStatusEnum; import org.dromara.progress.domain.enums.PgsDelayStatusEnum;
import org.dromara.progress.domain.enums.PgsFinishStatusEnum; import org.dromara.progress.domain.enums.PgsFinishStatusEnum;
import org.dromara.progress.domain.enums.PgsProgressUnitTypeEnum; import org.dromara.progress.domain.enums.PgsProgressUnitTypeEnum;
import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanDateVo;
import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanVo; import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanVo;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNumVo; import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNumVo;
import org.dromara.progress.mapper.PgsProgressPlanMapper; import org.dromara.progress.mapper.PgsProgressPlanMapper;
@ -104,6 +105,24 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
return list.stream().map(this::getVo).toList(); return list.stream().map(this::getVo).toList();
} }
/**
* 查询进度计划日期(最早的开始时间和最晚的结束时间)
*
* @param req 查询条件
* @return 进度计划日期(最早的开始时间和最晚的结束时间)
*/
@Override
public PgsProgressPlanDateVo queryDate(PgsProgressPlanQueryReq req) {
List<PgsProgressPlan> planList = this.list(this.buildQueryWrapper(req));
PgsProgressPlanDateVo dateVo = new PgsProgressPlanDateVo();
if (CollUtil.isEmpty(planList)) {
return dateVo;
}
dateVo.setStartDate(planList.stream().map(PgsProgressPlan::getStartDate).min(LocalDate::compareTo).orElse(null));
dateVo.setEndDate(planList.stream().map(PgsProgressPlan::getEndDate).max(LocalDate::compareTo).orElse(null));
return dateVo;
}
/** /**
* 新增进度计划 * 新增进度计划
* *