Compare commits

...

25 Commits

Author SHA1 Message Date
zt
a8cb16ab3f 通知 2025-09-10 20:21:01 +08:00
2c45762c66 09-10-netty优化 2025-09-10 19:41:11 +08:00
056b28af31 我的任务优化、工程量清单优化、gps消息websocket连接、物资管理:物资验收入库添加附件 2025-09-10 19:38:10 +08:00
lcj
7dd6d97a3e 进度管理app 2025-09-10 19:18:30 +08:00
zt
697beb67c4 通知 2025-09-10 17:34:49 +08:00
lcj
4d627af3a1 进度管理app、注解翻译项目名称 2025-09-10 16:43:49 +08:00
ab332c462f 09-10-netty设置系统消息type为2 2025-09-10 16:11:30 +08:00
0f3d1e38be 09-10-netty优化 2025-09-10 16:00:43 +08:00
lcj
4392a287cc 修改bug 2025-09-10 10:03:53 +08:00
lcj
f38538be33 修改进度管理 2025-09-10 00:15:55 +08:00
lcj
ede1e501b4 企业级大屏 2025-09-09 23:42:24 +08:00
4a2b62cf92 我的任务bug修改 2025-09-09 21:52:49 +08:00
zt
325f392e8f 大屏,消息 2025-09-09 20:39:00 +08:00
lcj
5b991396c2 企业级大屏 2025-09-09 19:49:14 +08:00
c75563b46a 09-09-修改 2025-09-09 18:53:28 +08:00
724ebf8dbd 09-09-netty完善修改 2025-09-09 18:47:48 +08:00
a52b9078a0 gps定位接口 2025-09-09 17:47:49 +08:00
9d682a3290 09-09-netty发送系统消息 2025-09-09 17:08:39 +08:00
lcj
abad289c2b 进度管理,企业级大屏,修改bug 2025-09-09 15:42:00 +08:00
820188863e 修改一览表单价精度 2025-09-09 15:24:17 +08:00
113b5debc9 供应商bug修改 2025-09-09 10:40:17 +08:00
6b4cd4ae0d Merge remote-tracking branch 'origin/dev' into dev 2025-09-09 09:12:54 +08:00
261dd0b643 09-09-netty消息搭建 2025-09-09 09:12:19 +08:00
zt
71f3810e51 Merge remote-tracking branch 'origin/dev' into dev 2025-09-08 20:03:11 +08:00
zt
fa835684d4 消息 2025-09-08 20:02:51 +08:00
143 changed files with 4502 additions and 409 deletions

View File

@ -307,7 +307,6 @@
<artifactId>snail-job-client-job-core</artifactId> <artifactId>snail-job-client-job-core</artifactId>
<version>${snailjob.version}</version> <version>${snailjob.version}</version>
</dependency> </dependency>
<!-- 加密包引入 --> <!-- 加密包引入 -->
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>

View File

@ -6,6 +6,7 @@ import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.codec.Base64; import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -41,16 +42,20 @@ import org.dromara.web.domain.vo.TenantListVo;
import org.dromara.web.service.IAuthStrategy; import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService; import org.dromara.web.service.SysLoginService;
import org.dromara.web.service.SysRegisterService; import org.dromara.web.service.SysRegisterService;
import org.dromara.websocket.domain.ChatGroup;
import org.dromara.websocket.service.Impl.ChatGroupServiceImpl;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/** /**
* 认证 * 认证
@ -72,6 +77,7 @@ public class AuthController {
private final ISysSocialService socialUserService; private final ISysSocialService socialUserService;
private final ISysClientService clientService; private final ISysClientService clientService;
private final ScheduledExecutorService scheduledExecutorService; private final ScheduledExecutorService scheduledExecutorService;
private final ChatGroupServiceImpl chatGroupService;
/** /**
@ -103,10 +109,7 @@ public class AuthController {
// Long userId = LoginHelper.getUserId(); // Long userId = LoginHelper.getUserId();
// scheduledExecutorService.schedule(() -> { // scheduledExecutorService.schedule(() -> {
// SseMessageDto dto = new SseMessageDto(); // chatGroupService.createSystem(userId,client.getClientKey());
// dto.setMessage("欢迎登录新能源项目管理系统");
// dto.setUserIds(List.of(userId));
// SseMessageUtils.publishMessage(dto);
// }, 5, TimeUnit.SECONDS); // }, 5, TimeUnit.SECONDS);
return R.ok(loginVo); return R.ok(loginVo);
} }

View File

@ -55,7 +55,8 @@ public class UserActionListener implements SaTokenListener {
String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY); String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY);
String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY); String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY);
dto.setUserName(username); dto.setUserName(username);
dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY)); String clientId = (String) loginModel.getExtra(LoginHelper.CLIENT_KEY);
dto.setClientKey(clientId);
dto.setDeviceType(loginModel.getDevice()); dto.setDeviceType(loginModel.getDevice());
dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY)); dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY));
TenantHelper.dynamic(tenantId, () -> { TenantHelper.dynamic(tenantId, () -> {
@ -75,7 +76,7 @@ public class UserActionListener implements SaTokenListener {
SpringUtils.context().publishEvent(logininforEvent); SpringUtils.context().publishEvent(logininforEvent);
// 更新登录信息 // 更新登录信息
loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip); loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip);
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); log.info("user doLogin, userId:{}, token:{}, clientid{}", loginId, tokenValue, clientId);
} }
/** /**

View File

@ -80,4 +80,9 @@ public interface CacheNames {
*/ */
String ONLINE_TOKEN = "online_tokens"; String ONLINE_TOKEN = "online_tokens";
/**
* 项目名称
*/
String PROJECT_NAME = "project_name#30d";
} }

View File

@ -0,0 +1,17 @@
package org.dromara.common.core.service;
/**
* @author lilemy
* @date 2025-09-10 16:15
*/
public interface ProjectService {
/**
* 通过项目ID查询项目名称
*
* @param projectId 项目ID
* @return 项目名称
*/
String selectProjectNameById(Long projectId);
}

View File

@ -32,4 +32,9 @@ public interface TransConstant {
*/ */
String OSS_ID_TO_URL = "oss_id_to_url"; String OSS_ID_TO_URL = "oss_id_to_url";
/**
* 项目id转名称
*/
String PROJECT_ID_TO_NAME = "project_id_to_name";
} }

View File

@ -0,0 +1,35 @@
package org.dromara.common.translation.core.impl;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.dromara.common.core.service.ProjectService;
import org.dromara.common.translation.annotation.TranslationType;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.common.translation.core.TranslationInterface;
/**
* @author lilemy
* @date 2025-09-10 16:13
*/
@AllArgsConstructor
@TranslationType(type = TransConstant.PROJECT_ID_TO_NAME)
public class ProjectNameTranslationImpl implements TranslationInterface<String> {
@Resource
private ProjectService projectService;
/**
* 翻译
*
* @param key 需要被翻译的键(不为空)
* @param other 其他参数
* @return 返回键对应的值
*/
@Override
public String translation(Object key, String other) {
if (key instanceof Long id) {
return projectService.selectProjectNameById(id);
}
return null;
}
}

View File

@ -4,3 +4,4 @@ org.dromara.common.translation.core.impl.DictTypeTranslationImpl
org.dromara.common.translation.core.impl.OssUrlTranslationImpl org.dromara.common.translation.core.impl.OssUrlTranslationImpl
org.dromara.common.translation.core.impl.UserNameTranslationImpl org.dromara.common.translation.core.impl.UserNameTranslationImpl
org.dromara.common.translation.core.impl.NicknameTranslationImpl org.dromara.common.translation.core.impl.NicknameTranslationImpl
org.dromara.common.translation.core.impl.ProjectNameTranslationImpl

View File

@ -12,6 +12,8 @@ public interface WebSocketConstants {
*/ */
String LOGIN_USER_KEY = "loginUser"; String LOGIN_USER_KEY = "loginUser";
String PROJECT_ID = "projectId";
/** /**
* 订阅的频道 * 订阅的频道
*/ */

View File

@ -13,6 +13,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY; import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY;
import static org.dromara.common.websocket.constant.WebSocketConstants.PROJECT_ID;
/** /**
* WebSocketHandler 实现类 * WebSocketHandler 实现类
@ -27,14 +28,17 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
*/ */
@Override @Override
public void afterConnectionEstablished(WebSocketSession session) throws IOException { public void afterConnectionEstablished(WebSocketSession session) throws IOException {
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); // LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
if (ObjectUtil.isNull(loginUser)) { Long loginUser = (Long) session.getAttributes().get(PROJECT_ID);
// if (ObjectUtil.isNull(loginUser) ) {
if (loginUser == null ) {
session.close(CloseStatus.BAD_DATA); session.close(CloseStatus.BAD_DATA);
log.info("[connect] invalid token received. sessionId: {}", session.getId()); log.info("[connect] invalid token received. sessionId: {}", session.getId());
return; return;
} }
WebSocketSessionHolder.addSession(loginUser.getUserId(), session); WebSocketSessionHolder.addSession(loginUser, session);
log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType()); // WebSocketSessionHolder.addSession(loginUser.getUserId(), session);
// log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
} }
/** /**
@ -47,11 +51,13 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
@Override @Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 从WebSocket会话中获取登录用户信息 // 从WebSocket会话中获取登录用户信息
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); // LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
Long loginUser = (Long) session.getAttributes().get(PROJECT_ID);
// 创建WebSocket消息DTO对象 // 创建WebSocket消息DTO对象
WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto(); WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto();
webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId())); // webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId()));
webSocketMessageDto.setSessionKeys(List.of(loginUser));
webSocketMessageDto.setMessage(message.getPayload()); webSocketMessageDto.setMessage(message.getPayload());
WebSocketUtils.publishMessage(webSocketMessageDto); WebSocketUtils.publishMessage(webSocketMessageDto);
} }
@ -100,13 +106,16 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
*/ */
@Override @Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); // LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
if (ObjectUtil.isNull(loginUser)) { Long loginUser = (Long) session.getAttributes().get(PROJECT_ID);
// if (ObjectUtil.isNull(loginUser)) {
if (loginUser != null ) {
log.info("[disconnect] invalid token received. sessionId: {}", session.getId()); log.info("[disconnect] invalid token received. sessionId: {}", session.getId());
return; return;
} }
WebSocketSessionHolder.removeSession(loginUser.getUserId()); // WebSocketSessionHolder.removeSession(loginUser.getUserId());
log.info("[disconnect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType()); WebSocketSessionHolder.removeSession(loginUser);
// log.info("[disconnect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
} }
/** /**

View File

@ -15,6 +15,7 @@ import org.springframework.web.socket.server.HandshakeInterceptor;
import java.util.Map; import java.util.Map;
import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY; import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY;
import static org.dromara.common.websocket.constant.WebSocketConstants.PROJECT_ID;
/** /**
* WebSocket握手请求的拦截器 * WebSocket握手请求的拦截器
@ -44,6 +45,8 @@ public class PlusWebSocketInterceptor implements HandshakeInterceptor {
String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY); String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY); String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString(); String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
String projectIdStr = ServletUtils.getRequest().getParameter("projectId");
Long projectId = Long.parseLong(projectIdStr);
if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) { if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
// token 无效 // token 无效
throw NotLoginException.newInstance(StpUtil.getLoginType(), throw NotLoginException.newInstance(StpUtil.getLoginType(),
@ -52,6 +55,7 @@ public class PlusWebSocketInterceptor implements HandshakeInterceptor {
} }
attributes.put(LOGIN_USER_KEY, loginUser); attributes.put(LOGIN_USER_KEY, loginUser);
attributes.put(PROJECT_ID,projectId);
return true; return true;
} catch (NotLoginException e) { } catch (NotLoginException e) {
log.error("WebSocket 认证失败'{}',无法访问系统资源", e.getMessage()); log.error("WebSocket 认证失败'{}',无法访问系统资源", e.getMessage());

View File

@ -252,6 +252,11 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -42,6 +42,14 @@ public class BusBiddingLimitVersions extends BaseEntity {
*/ */
private String versions; private String versions;
/**
* 版本号名称
*/
private String versionsName;
/** /**
* excel文件 * excel文件
*/ */

View File

@ -44,6 +44,14 @@ public class BusBiddingLimitVersionsBo extends BaseEntity {
@NotBlank(message = "版本号不能为空", groups = { AddGroup.class, EditGroup.class }) @NotBlank(message = "版本号不能为空", groups = { AddGroup.class, EditGroup.class })
private String versions; private String versions;
/**
* 版本号名称
*/
private String versionsName;
/** /**
* excel文件 * excel文件
*/ */

View File

@ -52,6 +52,14 @@ public class BusBiddingLimitVersionsVo implements Serializable {
@ExcelProperty(value = "版本号") @ExcelProperty(value = "版本号")
private String versions; private String versions;
/**
* 版本号名称
*/
private String versionsName;
/** /**
* excel文件 * excel文件
*/ */

View File

@ -189,7 +189,7 @@ public class BusBiddingLimitListServiceImpl extends ServiceImpl<BusBiddingLimitL
listVoList.stream().filter(vo -> vo.getUnitPrice() != null && vo.getUnitPrice().compareTo(BigDecimal.ZERO) != 0) listVoList.stream().filter(vo -> vo.getUnitPrice() != null && vo.getUnitPrice().compareTo(BigDecimal.ZERO) != 0)
.filter(vo -> vo.getQuantity() != null && vo.getQuantity().compareTo(BigDecimal.ZERO) != 0) .filter(vo -> vo.getQuantity() != null && vo.getQuantity().compareTo(BigDecimal.ZERO) != 0)
.forEach(item -> { .forEach(item -> {
item.setPrice(item.getUnitPrice().multiply(item.getQuantity()).setScale(2, RoundingMode.HALF_UP)); item.setPrice(item.getUnitPrice().multiply(item.getQuantity()).setScale(4, RoundingMode.HALF_UP));
}); });
//构建父子映射 //构建父子映射
@ -230,7 +230,7 @@ public class BusBiddingLimitListServiceImpl extends ServiceImpl<BusBiddingLimitL
BigDecimal totalPrice = node.getChildren().stream() BigDecimal totalPrice = node.getChildren().stream()
.map(BusBiddingLimitListVo::getPrice) .map(BusBiddingLimitListVo::getPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add) .reduce(BigDecimal.ZERO, BigDecimal::add)
.setScale(2, RoundingMode.HALF_UP); .setScale(4, RoundingMode.HALF_UP);
node.setPrice(totalPrice); node.setPrice(totalPrice);
} }
} }

View File

@ -0,0 +1,220 @@
package org.dromara.bigscreen.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.dromara.bigscreen.domain.dto.WeatherQueryReq;
import org.dromara.bigscreen.domain.vo.*;
import org.dromara.bigscreen.service.EnterpriseBigScreenService;
import org.dromara.common.core.domain.R;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.project.domain.BusAttendance;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.BusUserProjectRelevancy;
import org.dromara.project.service.IBusAttendanceService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.project.service.IBusUserProjectRelevancyService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
/**
* 企业级大屏
*
* @author lilemy
* @date 2025-09-09 14:55
*/
@Validated
@RestController
@RequestMapping("/enterprise/big/screen")
public class EnterpriseBigScreenController {
@Resource
private EnterpriseBigScreenService enterpriseBigScreenService;
@Resource
private IBusUserProjectRelevancyService userProjectRelevancyService;
@Resource
private IBusAttendanceService attendanceService;
@Resource
private IBusProjectService projectService;
/**
* 获取关键指标
*/
@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());
}
/**
* 风险预警
*/
@SaCheckPermission("enterprise:bigScreen:riskEarlyWarning")
@GetMapping("/riskEarlyWarning")
public R<List<RiskEarlyWarningVo>> getRiskEarlyWarning() {
return R.ok(enterpriseBigScreenService.getRiskEarlyWarning());
}
/**
* 查询天气
*/
@SaCheckPermission("enterprise:bigScreen:weather")
@GetMapping("/weather")
public R<List<WeatherVo>> getProjectWeather(WeatherQueryReq req) {
return R.ok(enterpriseBigScreenService.getWeather3DaysList(req));
}
/**
* 查询安全天数
*/
@SaCheckPermission("enterprise:bigScreen:safetyDay")
@GetMapping("/safetyDay")
public R<Long> getProjectSafetyDay() {
LocalDate date = LocalDate.of(2023, 1, 1);
LocalDate now = LocalDate.now();
long days = Math.abs(ChronoUnit.DAYS.between(date, now));
return R.ok(days);
}
/**
* 人数统计
*/
@SaCheckPermission("enterprise:bigScreen:peopleCount")
@GetMapping("/peopleCount")
public R<PeopleCountVo> getProjectPeopleCount() {
PeopleCountVo peopleCountVo = new PeopleCountVo();
List<BusUserProjectRelevancy> list = userProjectRelevancyService.list();
//0系统管理员 1普通人员 2项目管理员 3分包人员
peopleCountVo.setConstructionPersonnelCount(list.stream().filter(item -> "1".equals(item.getUserType()))
.map(BusUserProjectRelevancy::getUserId)
.distinct().count());
peopleCountVo.setManagersCount(list.stream().filter(item -> "2".equals(item.getUserType()))
.map(BusUserProjectRelevancy::getUserId)
.distinct().count());
peopleCountVo.setSubcontractorsCount(list.stream().filter(item -> "3".equals(item.getUserType()))
.map(BusUserProjectRelevancy::getUserId)
.distinct().count());
return R.ok(peopleCountVo);
}
/**
* 出勤人数统计
*/
@SaCheckPermission("enterprise:bigScreen:allAttendanceCount")
@GetMapping("/allAttendanceCount")
public R<TodayAttendanceCountVo> getAllAttendanceCount() {
TodayAttendanceCountVo todayAttendanceCountVo = new TodayAttendanceCountVo();
List<BusAttendance> list = attendanceService.list(Wrappers.<BusAttendance>lambdaQuery()
.eq(BusAttendance::getClockDate, LocalDate.now())
.in(BusAttendance::getClockStatus, Arrays.asList("1", "2", "3"))
);
long attendanceCount = list.stream().map(BusAttendance::getUserId).distinct().count();
todayAttendanceCountVo.setAttendanceCount(attendanceCount);
// 查询总人数
List<BusUserProjectRelevancy> relevancyList = userProjectRelevancyService.list();
long totalUserCount = relevancyList.stream().map(BusUserProjectRelevancy::getUserId).distinct().count();
// 计算考勤率(保留一位小数)
if (totalUserCount > 0) {
BigDecimal rate = new BigDecimal(attendanceCount * 100)
.divide(new BigDecimal(totalUserCount), 1, RoundingMode.HALF_UP);
todayAttendanceCountVo.setAttendanceRate(rate.doubleValue());
} else {
todayAttendanceCountVo.setAttendanceRate(0.0);
}
return R.ok(todayAttendanceCountVo);
}
/**
* 每个项目的出勤人数
*/
@SaCheckPermission("enterprise:bigScreen:projectAttendanceCount")
@GetMapping("/projectAttendanceCount")
public R<List<ProjectAttendanceCountVo>> getProjectAttendanceCount() {
ArrayList<ProjectAttendanceCountVo> projectAttendanceCountVos = new ArrayList<>();
List<BusAttendance> list = attendanceService.list(Wrappers.<BusAttendance>lambdaQuery()
.eq(BusAttendance::getClockDate, LocalDate.now())
.in(BusAttendance::getClockStatus, Arrays.asList("1", "2", "3"))
);
List<BusUserProjectRelevancy> relevancyList = userProjectRelevancyService.list();
// 转换为 Map<projectId, 去重后的 userId 数量>
Map<Long, Integer> projectUserCountMap = relevancyList.stream()
.collect(Collectors.groupingBy(
BusUserProjectRelevancy::getProjectId,
Collectors.mapping(
BusUserProjectRelevancy::getUserId,
Collectors.collectingAndThen(
Collectors.toSet(),
Set::size
)
)
));
for (Long projectId : projectUserCountMap.keySet()) {
ProjectAttendanceCountVo projectAttendanceCountVo = new ProjectAttendanceCountVo();
BusProject byId = projectService.getById(projectId);
if (byId == null) {
continue;
}
projectAttendanceCountVo.setProjectName(byId.getProjectName());
long count = list.stream().filter(item -> item.getProjectId().equals(projectId))
.map(BusAttendance::getUserId)
.distinct()
.count();
Integer i = projectUserCountMap.get(projectId);
BigDecimal rate = new BigDecimal("0.0");
if (i > 0) {
rate = new BigDecimal(count * 100)
.divide(new BigDecimal(projectUserCountMap.get(projectId)), 1, RoundingMode.HALF_UP);
}
projectAttendanceCountVo.setAttendanceRate(rate.doubleValue());
projectAttendanceCountVos.add(projectAttendanceCountVo);
}
return R.ok(projectAttendanceCountVos);
}
}

View File

@ -11,13 +11,13 @@ import org.dromara.ctr.domain.CtrExpensesContract;
import org.dromara.ctr.domain.CtrIncomeContract; import org.dromara.ctr.domain.CtrIncomeContract;
import org.dromara.ctr.service.ICtrExpensesContractService; import org.dromara.ctr.service.ICtrExpensesContractService;
import org.dromara.ctr.service.ICtrIncomeContractService; import org.dromara.ctr.service.ICtrIncomeContractService;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.dromara.out.domain.OutSettlementValueOwner; import org.dromara.out.domain.OutSettlementValueOwner;
import org.dromara.out.domain.OutSettlementValueSubcontract; import org.dromara.out.domain.OutSettlementValueSubcontract;
import org.dromara.out.service.IOutSettlementValueOwnerService; import org.dromara.out.service.IOutSettlementValueOwnerService;
import org.dromara.out.service.IOutSettlementValueSubcontractService; import org.dromara.out.service.IOutSettlementValueSubcontractService;
import org.dromara.project.domain.vo.project.BusProjectGisVo; import org.dromara.project.domain.vo.project.BusProjectGisVo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo; 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.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
@ -114,7 +114,7 @@ public class MoneyBigScreenController {
.eq(CtrIncomeContract::getProjectId, projectId) .eq(CtrIncomeContract::getProjectId, projectId)
.last("limit 1") .last("limit 1")
); );
if (contract != null && contract.getPayRatio()!= null) { if (contract != null && contract.getPayRatio() != null) {
actualAmount = actualAmount.add(projectMonthlyAmountMap.get(projectId).multiply(contract.getPayRatio()).divide(HUNDRED)); actualAmount = actualAmount.add(projectMonthlyAmountMap.get(projectId).multiply(contract.getPayRatio()).divide(HUNDRED));
} }
@ -169,7 +169,7 @@ public class MoneyBigScreenController {
.last("limit 1") .last("limit 1")
); );
if (contract != null && contract.getPayRatio()!= null) { if (contract != null && contract.getPayRatio() != null) {
actualAmount = actualAmount.add(projectAmountMap.get(contractCode).multiply(contract.getPayRatio()).divide(HUNDRED)); actualAmount = actualAmount.add(projectAmountMap.get(contractCode).multiply(contract.getPayRatio()).divide(HUNDRED));
} }
@ -243,7 +243,7 @@ public class MoneyBigScreenController {
.filter(contract -> contract.getAmount() != null && contract.getAmount().compareTo(THIRD_PHASE) >= 0) .filter(contract -> contract.getAmount() != null && contract.getAmount().compareTo(THIRD_PHASE) >= 0)
.count(); .count();
return R.ok(new MoneyContractCountVo(4, 4, 6, 6)); return R.ok(new MoneyContractCountVo(4, 4, 6, 6));
// return R.ok(new MoneyContractCountVo(lessThan1M, between1MAnd5M, between5MAnd10M, greaterThanOrEqualTo10M)); // return R.ok(new MoneyContractCountVo(lessThan1M, between1MAnd5M, between5MAnd10M, greaterThanOrEqualTo10M));
} }
@ -350,7 +350,7 @@ public class MoneyBigScreenController {
.eq(CtrIncomeContract::getProjectId, projectId) .eq(CtrIncomeContract::getProjectId, projectId)
.last("limit 1") .last("limit 1")
); );
if (contract != null && contract.getPayRatio()!= null) { if (contract != null && contract.getPayRatio() != null) {
incomeAmount = incomeAmount.add(incomeGroupedByProject.get(projectId).multiply(contract.getPayRatio()).divide(HUNDRED)); incomeAmount = incomeAmount.add(incomeGroupedByProject.get(projectId).multiply(contract.getPayRatio()).divide(HUNDRED));
} }
} }
@ -380,7 +380,7 @@ public class MoneyBigScreenController {
.last("limit 1") .last("limit 1")
); );
if (contract != null && contract.getPayRatio()!= null) { if (contract != null && contract.getPayRatio() != null) {
expensesAmount = expensesAmount.add(expenseGroupedByContract.get(contractCode).multiply(contract.getPayRatio()).divide(HUNDRED)); expensesAmount = expensesAmount.add(expenseGroupedByContract.get(contractCode).multiply(contract.getPayRatio()).divide(HUNDRED));
} }
} }
@ -448,7 +448,7 @@ public class MoneyBigScreenController {
.eq(CtrIncomeContract::getProjectId, projectId) .eq(CtrIncomeContract::getProjectId, projectId)
.last("limit 1") .last("limit 1")
); );
if (contract != null && contract.getPayRatio()!= null) { if (contract != null && contract.getPayRatio() != null) {
incomeAmount = incomeAmount.add(incomeGroupedByProject.get(projectId).multiply(contract.getPayRatio()).divide(HUNDRED)); incomeAmount = incomeAmount.add(incomeGroupedByProject.get(projectId).multiply(contract.getPayRatio()).divide(HUNDRED));
} }
} }
@ -478,7 +478,7 @@ public class MoneyBigScreenController {
.last("limit 1") .last("limit 1")
); );
if (contract != null && contract.getPayRatio()!= null) { if (contract != null && contract.getPayRatio() != null) {
expensesAmount = expensesAmount.add(expenseGroupedByContract.get(contractCode).multiply(contract.getPayRatio()).divide(HUNDRED)); expensesAmount = expensesAmount.add(expenseGroupedByContract.get(contractCode).multiply(contract.getPayRatio()).divide(HUNDRED));
} }
} }
@ -511,7 +511,7 @@ public class MoneyBigScreenController {
.filter(java.util.Objects::nonNull) // 过滤掉 null 值 .filter(java.util.Objects::nonNull) // 过滤掉 null 值
.reduce(BigDecimal.ZERO, BigDecimal::add); .reduce(BigDecimal.ZERO, BigDecimal::add);
List<OutSettlementValueSubcontract> subcontractList = settlementValueSubcontractService.list(); List<OutSettlementValueSubcontract> subcontractList = settlementValueSubcontractService.list();
BigDecimal expensesCash = subcontractList.stream() BigDecimal expensesCash = subcontractList.stream()
.map(OutSettlementValueSubcontract::getSettlementValue) .map(OutSettlementValueSubcontract::getSettlementValue)
@ -526,8 +526,6 @@ public class MoneyBigScreenController {
} }
/** /**
* 获取当前月份的开始时间和结束时间 * 获取当前月份的开始时间和结束时间
* *
@ -548,8 +546,8 @@ public class MoneyBigScreenController {
*/ */
@SaCheckPermission("project:bigScreen:weather") @SaCheckPermission("project:bigScreen:weather")
@GetMapping("/weather/{projectId}") @GetMapping("/weather/{projectId}")
public R<List<BusProjectWeatherVo>> getProjectWeather(@NotNull(message = "主键不能为空") public R<List<WeatherVo>> getProjectWeather(@NotNull(message = "主键不能为空")
@PathVariable Long projectId) { @PathVariable Long projectId) {
return R.ok(moneyBigScreenService.getProjectWeather(projectId)); return R.ok(moneyBigScreenService.getProjectWeather(projectId));
} }

View File

@ -11,21 +11,27 @@ import org.dromara.bigscreen.domain.vo.ProjectPeopleVo;
import org.dromara.bigscreen.domain.vo.ProjectSafetyInspectionVo; import org.dromara.bigscreen.domain.vo.ProjectSafetyInspectionVo;
import org.dromara.bigscreen.service.ProjectBigScreenService; import org.dromara.bigscreen.service.ProjectBigScreenService;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.gps.domain.bo.GpsEquipmentBo;
import org.dromara.gps.domain.vo.GpsEquipmentSonVo;
import org.dromara.gps.service.IGpsEquipmentService;
import org.dromara.land.domain.BusLandBlock; import org.dromara.land.domain.BusLandBlock;
import org.dromara.land.domain.BusLandTransferLedger; import org.dromara.land.domain.BusLandTransferLedger;
import org.dromara.land.service.IBusLandBlockService; import org.dromara.land.service.IBusLandBlockService;
import org.dromara.land.service.IBusLandTransferLedgerService; 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.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo; import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -49,6 +55,10 @@ public class ProjectBigScreenController {
private final IBusLandBlockService busLandBlockService; private final IBusLandBlockService busLandBlockService;
private final IGpsEquipmentService gpsEquipmentService;
private final IOthYs7DeviceService othYs7DeviceService;
/** /**
* 查询项目土地统计 * 查询项目土地统计
*/ */
@ -103,8 +113,8 @@ public class ProjectBigScreenController {
*/ */
@SaCheckPermission("project:bigScreen:weather") @SaCheckPermission("project:bigScreen:weather")
@GetMapping("/weather/{projectId}") @GetMapping("/weather/{projectId}")
public R<List<BusProjectWeatherVo>> getProjectWeather(@NotNull(message = "主键不能为空") public R<List<WeatherVo>> getProjectWeather(@NotNull(message = "主键不能为空")
@PathVariable Long projectId) { @PathVariable Long projectId) {
return R.ok(projectBigScreenService.getProjectWeather(projectId)); return R.ok(projectBigScreenService.getProjectWeather(projectId));
} }
@ -167,4 +177,179 @@ public class ProjectBigScreenController {
@PathVariable Long projectId) { @PathVariable Long projectId) {
return R.ok(projectBigScreenService.getProjectGeneralize(projectId)); return R.ok(projectBigScreenService.getProjectGeneralize(projectId));
} }
/**
* 查询设备列表
*/
@SaCheckPermission("project:bigScreen:getClientList")
@GetMapping("/getClientList/{projectId}")
public R<List<Map<String,Object>>> getClientList(@NotNull(message = "主键不能为空")
@PathVariable Long projectId) {
List<GpsEquipmentSonVo> voList = gpsEquipmentService.getClientList(projectId);
// List<OthYs7Device> othYs7DeviceList = othYs7DeviceService.lambdaQuery()
// .eq(OthYs7Device::getProjectId, projectId)
// .list();
List<Map<String, Object>> maps = new ArrayList<>();
Map<String, Object> gpsMap = new HashMap<>();
Map<String, Object> wrjMap = new HashMap<>();
Map<String, Object> sxtMap = new HashMap<>();
List<Map<String, Object>> gpsChildrenMap = new ArrayList<>();
// List<Map<String, Object>> wrjChildrenMap = new ArrayList<>();
// List<Map<String, Object>> sxtChildrenMap = new ArrayList<>();
if (voList != null && !voList.isEmpty()) {
for (GpsEquipmentSonVo item : voList) {
Map<String, Object> gps = new HashMap<>();
gps.put("id", item.getClientId());
gps.put("label", item.getClientId());
gps.put("name", item.getDeviceName());
gps.put("type", "positioningDevice");
gps.put("lat", item.getLocLatitude());
gps.put("lng", item.getLocLongitude());
gps.put("alt", item.getLocAltitude());
gpsChildrenMap.add(gps);
}
}
// if (othYs7DeviceList != null && !othYs7DeviceList.isEmpty()) {
// for (OthYs7Device item : othYs7DeviceList) {
// Map<String, Object> sxt = new HashMap<>();
// sxt.put("id", item.getDeviceSerial());
// sxt.put("label", item.getDeviceSerial());
// sxt.put("name", item.getDeviceName());
// sxt.put("type", "shexiangtou");
//// sxt.put("lat", item.getLocLatitude());
//// sxt.put("lng", item.getLocLongitude());
//// sxt.put("alt", item.getLocAltitude());
// sxtChildrenMap.add(sxt);
// }
// }
List<Map<String, Object>> maps1 = setSxt();
List<Map<String, Object>> maps2 = setWrj();
gpsMap.put("id",1);
gpsMap.put("label","定位设备");
gpsMap.put("children",gpsChildrenMap);
sxtMap.put("id",2);
sxtMap.put("label","摄像头");
// sxtMap.put("children",sxtChildrenMap);
sxtMap.put("children",maps1);
wrjMap.put("id",3);
wrjMap.put("label","无人机");
// wrjMap.put("children",wrjChildrenMap);
wrjMap.put("children",maps2);
maps.add(gpsMap);
maps.add(wrjMap);
maps.add(sxtMap);
return R.ok(maps);
}
/**
* 查询GPS设备用户列表
*/
@SaCheckPermission("project:bigScreen:getList")
@GetMapping("/getList")
public R<List<String>> getList(Long projectId) {
return R.ok(projectBigScreenService.getList(projectId));
}
/**
* 新增GPS设备详细
*/
@SaCheckPermission("project:bigScreen:setList")
@Log(title = "GPS设备详细", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/setList")
public void setList(@RequestBody GpsEquipmentBo bo) {
projectBigScreenService.setList(bo);
}
public List<Map<String, Object>> setSxt(){
List<Map<String, Object>> sxtChildrenMap = new ArrayList<>();
HashMap<String, Object> map1 = new HashMap<>();
map1.put("id", "55");
map1.put("label", "1222222");
map1.put("name", "22");
map1.put("type", "camera");
map1.put("lng", 106.48349615411811);
map1.put("lat", 29.54856374364732);
map1.put("alt", 0);
HashMap<String, Object> map2 = new HashMap<>();
map2.put("id", "56");
map2.put("label", "1222223");
map2.put("name", "23");
map2.put("type", "camera");
map2.put("lng", 106.48442273257676);
map2.put("lat", 29.53841670498476);
map2.put("alt", 0);
HashMap<String, Object> map3 = new HashMap<>();
map3.put("id", "57");
map3.put("label", "1222224");
map3.put("name", "24");
map3.put("type", "camera");
map3.put("lng", 106.49197896482423);
map3.put("lat", 29.52931974282576);
map3.put("alt", 0);
HashMap<String, Object> map4 = new HashMap<>();
map4.put("id", "58");
map4.put("label", "1222225");
map4.put("name", "25");
map4.put("type", "camera");
map4.put("lng", 106.50293584930655);
map4.put("lat", 29.533025743929034);
map4.put("alt", 0);
sxtChildrenMap.add(map1);
sxtChildrenMap.add(map2);
sxtChildrenMap.add(map3);
sxtChildrenMap.add(map4);
return sxtChildrenMap;
}
public List<Map<String, Object>> setWrj(){
List<Map<String, Object>> sxtChildrenMap = new ArrayList<>();
HashMap<String, Object> map1 = new HashMap<>();
map1.put("id", "65");
map1.put("label", "6222222");
map1.put("name", "32");
map1.put("type", "drone");
map1.put("lng", 106.49556855602525);
map1.put("lat", 29.534393226355515);
map1.put("alt", 0);
HashMap<String, Object> map2 = new HashMap<>();
map2.put("id", "66");
map2.put("label", "2222223");
map2.put("name", "33");
map2.put("type", "drone");
map2.put("lng", 106.49142431645038);
map2.put("lat", 29.534472802500083);
map2.put("alt", 0);
HashMap<String, Object> map3 = new HashMap<>();
map3.put("id", "67");
map3.put("label", "2222224");
map3.put("name", "34");
map3.put("type", "drone");
map3.put("lng", 106.49142125177437);
map3.put("lat", 29.541881138875755);
map3.put("alt", 0);
HashMap<String, Object> map4 = new HashMap<>();
map4.put("id", "68");
map4.put("label", "2222225");
map4.put("name", "35");
map4.put("type", "drone");
map4.put("lng", 106.50256649933792);
map4.put("lat", 29.54260793685717);
map4.put("alt", 0);
sxtChildrenMap.add(map1);
sxtChildrenMap.add(map2);
sxtChildrenMap.add(map3);
sxtChildrenMap.add(map4);
return sxtChildrenMap;
}
} }

View File

@ -0,0 +1,31 @@
package org.dromara.bigscreen.domain.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @date 2025-09-09 15:16
*/
@Data
public class WeatherQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -2550570761981859666L;
/**
* 经度
*/
@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,22 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
@Data
public class PeopleCountVo {
/**
* 施工人员
*/
private Long constructionPersonnelCount;
/**
* 分包人员
*/
private Long SubcontractorsCount;
/**
* 管理人员
*/
private Long managersCount;
}

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,29 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
@Data
public class ProjectAttendanceCountVo {
/**
* 项目id
*/
private Long projectId;
/**
* 项目名称
*/
private String projectName;
/**
* 考勤人数
*/
private Long attendanceCount;
/**
* 考勤率
*/
private Double attendanceRate;
}

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

@ -0,0 +1,48 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
/**
* @author lilemy
* @date 2025-09-09 20:04
*/
@Data
public class RiskEarlyWarningVo implements Serializable {
@Serial
private static final long serialVersionUID = 5250172770638676715L;
/**
* 时间
*/
private LocalDate date;
/**
* 风险类型
*/
private String riskType;
/**
* 报警内容
*/
private String alarmContent;
/**
* 威胁等级
*/
private String dangerLevel;
/**
* 来源
*/
private String source;
/**
* 告警等级
*/
private String alarmLevel;
}

View File

@ -0,0 +1,19 @@
package org.dromara.bigscreen.domain.vo;
import lombok.Data;
@Data
public class TodayAttendanceCountVo {
/**
* 考勤人员数量
*/
private Long attendanceCount;
/**
* 出勤率
*/
private Double attendanceRate;
}

View File

@ -0,0 +1,53 @@
package org.dromara.bigscreen.service;
import org.dromara.bigscreen.domain.dto.WeatherQueryReq;
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.RiskEarlyWarningVo;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import java.util.List;
/**
* @author lilemy
* @date 2025-09-09 15:31
*/
public interface EnterpriseBigScreenService {
/**
* 获取关键指标
*
* @return 关键指标
*/
EnterpriseKeyIndexVo getEnterpriseKeyIndex();
/**
* 获取项目进度分析
*
* @return 项目进度分析
*/
ProjectProgressAnalysisVo getProjectProgressAnalysis();
/**
* 获取项目产值对比
*
* @return 项目产值对比
*/
List<OutputValueComparisonVo> getProjectOutputValueComparison();
/**
* 获取风险预警
*
* @return 风险预警
*/
List<RiskEarlyWarningVo> getRiskEarlyWarning();
/**
* 获取3天的天气列表
*
* @param req 查询参数
* @return 天气列表
*/
List<WeatherVo> getWeather3DaysList(WeatherQueryReq req);
}

View File

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

View File

@ -3,8 +3,9 @@ package org.dromara.bigscreen.service;
import org.dromara.bigscreen.domain.vo.ProjectImageProgressVo; import org.dromara.bigscreen.domain.vo.ProjectImageProgressVo;
import org.dromara.bigscreen.domain.vo.ProjectPeopleVo; import org.dromara.bigscreen.domain.vo.ProjectPeopleVo;
import org.dromara.bigscreen.domain.vo.ProjectSafetyInspectionVo; 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.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo; import org.dromara.project.domain.vo.projectnews.BusProjectNewsVo;
import java.util.List; import java.util.List;
@ -21,7 +22,7 @@ public interface ProjectBigScreenService {
* @param projectId 项目id * @param projectId 项目id
* @return 项目天气 * @return 项目天气
*/ */
List<BusProjectWeatherVo> getProjectWeather(Long projectId); List<WeatherVo> getProjectWeather(Long projectId);
/** /**
* 获取项目安全天数 * 获取项目安全天数
@ -70,4 +71,8 @@ public interface ProjectBigScreenService {
* @return 项目概括 * @return 项目概括
*/ */
String getProjectGeneralize(Long projectId); String getProjectGeneralize(Long projectId);
List<String> getList(Long projectId);
void setList(GpsEquipmentBo bo);
} }

View File

@ -0,0 +1,383 @@
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.*;
import org.dromara.bigscreen.service.EnterpriseBigScreenService;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.utils.DateUtils;
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.BusProcurement;
import org.dromara.out.domain.OutConstructionValue;
import org.dromara.out.domain.OutMonthPlanAudit;
import org.dromara.out.domain.OutValueAllocation;
import org.dromara.out.service.IBusProcurementService;
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.dromara.safety.domain.HseRecognizeRecord;
import org.dromara.safety.domain.HseViolationLevel;
import org.dromara.safety.domain.HseViolationRecord;
import org.dromara.safety.service.IHseRecognizeRecordService;
import org.dromara.safety.service.IHseViolationLevelService;
import org.dromara.safety.service.IHseViolationRecordService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author lilemy
* @date 2025-09-09 15:32
*/
@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;
@Resource
private IHseViolationRecordService hseViolationRecordService;
@Resource
private IHseViolationLevelService hseViolationLevelService;
@Resource
private IBusProcurementService busProcurementService;
@Resource
private IHseRecognizeRecordService hseRecognizeRecordService;
/**
* 获取关键指标
*
* @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));
// 并网容量 =(完工产值/计划总产值)* 计划容量
List<OutputValueComparisonVo> list = getProjectOutputValueComparison();
BigDecimal actualValue = list.stream()
.map(OutputValueComparisonVo::getActualValue)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal planValue = list.stream()
.map(OutputValueComparisonVo::getPlanValue)
.filter(Objects::nonNull)
.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);
BigDecimal gridConnectedCapacity = BigDecimal.ZERO;
if (planValue.compareTo(BigDecimal.ZERO) != 0) {
gridConnectedCapacity = plannedCapacity.multiply(actualValue.divide(planValue, 2, RoundingMode.HALF_UP));
}
vo.setGridConnectedCapacity(gridConnectedCapacity);
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<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<BusProcurement> purchaseValueList = busProcurementService.lambdaQuery()
.select(BusProcurement::getProjectId, BusProcurement::getAcceptedQuantity, BusProcurement::getUnitPrice)
.list();
// 设计产值
List<OutMonthPlanAudit> designValueList = outMonthPlanAuditService.lambdaQuery()
.select(OutMonthPlanAudit::getProjectId, OutMonthPlanAudit::getDesignValue)
.eq(OutMonthPlanAudit::getType, "1")
.list();
// 封装数据
return projectList.stream().map(project -> {
OutputValueComparisonVo vo = new OutputValueComparisonVo();
vo.setProjectId(project.getId());
vo.setProjectName(project.getProjectName());
vo.setPlanValue(planMap.getOrDefault(project.getId(), BigDecimal.ZERO));
BigDecimal actualValue = BigDecimal.ZERO;
// 设计产值
List<OutMonthPlanAudit> designValue = designValueList.stream()
.filter(design -> design.getProjectId().equals(project.getId()))
.toList();
if (CollUtil.isNotEmpty(designValue)) {
BigDecimal dValue = designValue.stream()
.filter(Objects::nonNull)
.map(OutMonthPlanAudit::getDesignValue)
.reduce(BigDecimal.ZERO, BigDecimal::add);
actualValue = actualValue.add(dValue);
}
// 施工产值
List<OutConstructionValue> constructionValue = constructionValueList.stream()
.filter(construction -> construction.getProjectId().equals(project.getId()))
.toList();
if (CollUtil.isNotEmpty(constructionValue)) {
BigDecimal cValue = constructionValue.stream()
.filter(Objects::nonNull)
.map(OutConstructionValue::getOwnerValue)
.reduce(BigDecimal.ZERO, BigDecimal::add);
actualValue = actualValue.add(cValue);
}
// 采购产值
List<BusProcurement> purchaseValue = purchaseValueList.stream()
.filter(purchase -> purchase.getProjectId().equals(project.getId()))
.toList();
if (CollUtil.isNotEmpty(purchaseValue)) {
BigDecimal pValue = purchaseValue.stream()
.filter(Objects::nonNull)
.filter(purchase -> purchase.getAcceptedQuantity() != null && purchase.getUnitPrice() != null)
.map(purchase -> purchase.getAcceptedQuantity().multiply(purchase.getUnitPrice()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
actualValue = actualValue.add(pValue);
}
vo.setActualValue(actualValue);
return vo;
}).filter(vo -> vo.getActualValue().compareTo(BigDecimal.ZERO) > 0)
.toList();
}
/**
* 获取风险预警
*
* @return 风险预警
*/
@Override
public List<RiskEarlyWarningVo> getRiskEarlyWarning() {
List<HseViolationRecord> recordList = hseViolationRecordService.lambdaQuery()
.last("limit 10")
.list();
recordList = recordList.stream()
.filter(record -> record.getReviewType() == null || record.getReviewType().equals("2"))
.toList();
if (CollUtil.isEmpty(recordList)) {
return Collections.emptyList();
}
// 项目映射
Set<Long> projectIds = recordList.stream()
.map(HseViolationRecord::getProjectId)
.collect(Collectors.toSet());
List<BusProject> projectList = projectService.lambdaQuery()
.select(BusProject::getId, BusProject::getProjectName)
.in(BusProject::getId, projectIds)
.list();
Map<Long, String> projectMap = projectList.stream()
.collect(Collectors.toMap(BusProject::getId, BusProject::getProjectName));
// 风险映射
Set<Long> levelIds = recordList.stream()
.map(HseViolationRecord::getLevelId)
.collect(Collectors.toSet());
List<HseViolationLevel> levelList = hseViolationLevelService.lambdaQuery()
.select(HseViolationLevel::getId, HseViolationLevel::getRiskType, HseViolationLevel::getViolationLevel)
.in(HseViolationLevel::getId, levelIds)
.list();
Map<Long, HseViolationLevel> levelMap = levelList.stream()
.collect(Collectors.toMap(HseViolationLevel::getId, level -> level));
// 识别记录映射
Set<Long> recognizeIds = recordList.stream()
.map(HseViolationRecord::getRecognizeId)
.collect(Collectors.toSet());
List<HseRecognizeRecord> recognizeRecordList = hseRecognizeRecordService.lambdaQuery()
.in(HseRecognizeRecord::getId, recognizeIds)
.list();
Map<Long, HseRecognizeRecord> recognizeRecordMap = recognizeRecordList.stream()
.collect(Collectors.toMap(HseRecognizeRecord::getId, recognize -> recognize));
return recordList.stream().map(record -> {
RiskEarlyWarningVo vo = new RiskEarlyWarningVo();
Date violationTime = record.getViolationTime() != null ? record.getViolationTime() : record.getCreateTime();
vo.setDate(DateUtils.toLocalDate(violationTime));
vo.setSource(projectMap.getOrDefault(record.getProjectId(), "未知项目"));
vo.setRiskType(record.getViolationType());
if (levelMap.containsKey(record.getLevelId())) {
HseViolationLevel level = levelMap.get(record.getLevelId());
vo.setAlarmLevel(level.getRiskType());
vo.setDangerLevel(level.getViolationLevel());
}
if (recognizeRecordMap.containsKey(record.getRecognizeId())) {
HseRecognizeRecord hseRecognizeRecord = recognizeRecordMap.get(record.getRecognizeId());
vo.setAlarmContent(hseRecognizeRecord.getDescription());
}
return vo;
}).toList();
}
/**
* 获取3天的天气列表
*
* @param req 查询参数
* @return 天气列表
*/
@Override
public List<WeatherVo> getWeather3DaysList(WeatherQueryReq req) {
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.bigscreen.service.MoneyBigScreenService;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException; 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.BusProject;
import org.dromara.project.domain.vo.project.BusProjectGisVo; import org.dromara.project.domain.vo.project.BusProjectGisVo;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo; import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo;
import org.dromara.project.domain.vo.project.BusProjectWeatherVo;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -40,7 +40,7 @@ public class MoneyBigScreenServiceImpl implements MoneyBigScreenService {
* @return 项目天气 * @return 项目天气
*/ */
@Override @Override
public List<BusProjectWeatherVo> getProjectWeather(Long projectId) { public List<WeatherVo> getProjectWeather(Long projectId) {
checkProject(projectId); checkProject(projectId);
return projectService.getWeather(projectId); return projectService.getWeather(projectId);
} }

View File

@ -1,6 +1,8 @@
package org.dromara.bigscreen.service.impl; package org.dromara.bigscreen.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.dromara.bigscreen.domain.vo.ProjectImageProgressVo; import org.dromara.bigscreen.domain.vo.ProjectImageProgressVo;
import org.dromara.bigscreen.domain.vo.ProjectPeopleVo; import org.dromara.bigscreen.domain.vo.ProjectPeopleVo;
@ -9,9 +11,12 @@ import org.dromara.bigscreen.domain.vo.ProjectTeamAttendanceVo;
import org.dromara.bigscreen.service.ProjectBigScreenService; import org.dromara.bigscreen.service.ProjectBigScreenService;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.utils.BigDecimalUtil; import org.dromara.common.utils.BigDecimalUtil;
import org.dromara.contractor.domain.SubConstructionUser; import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.contractor.service.ISubConstructionUserService; 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.PgsProgressCategory;
import org.dromara.progress.domain.enums.PgsProgressUnitTypeEnum; import org.dromara.progress.domain.enums.PgsProgressUnitTypeEnum;
import org.dromara.progress.service.IPgsProgressCategoryService; import org.dromara.progress.service.IPgsProgressCategoryService;
@ -19,7 +24,6 @@ import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.BusProjectTeam; import org.dromara.project.domain.BusProjectTeam;
import org.dromara.project.domain.BusProjectTeamMember; import org.dromara.project.domain.BusProjectTeamMember;
import org.dromara.project.domain.vo.project.BusProjectSafetyDayVo; 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.domain.vo.projectnews.BusProjectNewsVo;
import org.dromara.project.service.*; import org.dromara.project.service.*;
import org.dromara.safety.domain.HseRecognizeRecord; import org.dromara.safety.domain.HseRecognizeRecord;
@ -71,7 +75,7 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
* @return 项目天气 * @return 项目天气
*/ */
@Override @Override
public List<BusProjectWeatherVo> getProjectWeather(Long projectId) { public List<WeatherVo> getProjectWeather(Long projectId) {
checkProject(projectId); checkProject(projectId);
return projectService.getWeather(projectId); return projectService.getWeather(projectId);
} }
@ -359,4 +363,25 @@ public class ProjectBigScreenServiceImpl implements ProjectBigScreenService {
} }
} }
@Override
public List<String> getList(Long projectId) {
if (projectId == null){
throw new ServiceException("项目id不能为空");
}
Object object = RedisUtils.getCacheObject("xmjdp:" + projectId);
if (object == null) {
return null;
}
JSONArray objects = JSONUtil.parseArray(object);
return objects.toList(String.class);
}
@Override
public void setList(GpsEquipmentBo bo) {
if (bo.getProjectId() == null){
throw new ServiceException("项目id不能为空");
}
RedisUtils.setCacheObject("xmjdp:"+bo.getProjectId(), bo.getIdList());
}
} }

View File

@ -224,6 +224,21 @@ public class PdfBoxQrCodeGenerator {
// 二维码大小比例页面宽高中较小值的20% // 二维码大小比例页面宽高中较小值的20%
private static final float QR_SIZE_RATIO = 0.2f; private static final float QR_SIZE_RATIO = 0.2f;
// 二维码大小比例页面宽高中较小值的20%
private static final float QR_SIZE = 60.0f;
// 竖坐标
private static final float V_QR_X = 232.0f;
// 竖坐标
private static final float V_QR_Y = 679.5f;
// 横坐标
private static final float H_QR_X = 1116.5f;
// 横坐标
private static final float H_QR_Y = 34.0f;
public static ByteArrayOutputStream addQRCodeToPDFOnAllPages(String srcPdf, byte[] qrCodeBytes, boolean isChangeFile) public static ByteArrayOutputStream addQRCodeToPDFOnAllPages(String srcPdf, byte[] qrCodeBytes, boolean isChangeFile)
throws IOException { throws IOException {
@ -256,6 +271,10 @@ public class PdfBoxQrCodeGenerator {
int numberOfPages = pdfDoc.getNumberOfPages(); int numberOfPages = pdfDoc.getNumberOfPages();
for (int pageNum = 1; pageNum <= numberOfPages; pageNum++) { for (int pageNum = 1; pageNum <= numberOfPages; pageNum++) {
if (pageNum == 1 && isChangeFile) {
continue;
}
PdfPage page = pdfDoc.getPage(pageNum); PdfPage page = pdfDoc.getPage(pageNum);
// 获取页面的所有边界框信息 // 获取页面的所有边界框信息
@ -266,25 +285,33 @@ public class PdfBoxQrCodeGenerator {
Rectangle visibleArea = (cropBox != null) ? cropBox : mediaBox; Rectangle visibleArea = (cropBox != null) ? cropBox : mediaBox;
// 计算页面宽高中较小的值 // 计算页面宽高中较小的值
float minDimension = Math.min(visibleArea.getWidth(), visibleArea.getHeight()); // float minDimension = Math.min(visibleArea.getWidth(), visibleArea.getHeight());
// 动态计算二维码大小页面宽高中较小值的20% // 动态计算二维码大小页面宽高中较小值的20%
float qrSize = minDimension * QR_SIZE_RATIO; // float qrSize = minDimension * QR_SIZE_RATIO;
// 输出页面尺寸信息 // 输出页面尺寸信息
System.out.println("页面 " + pageNum + " 尺寸: " + visibleArea.getWidth() + "x" + visibleArea.getHeight()); // System.out.println("页面 " + pageNum + " 尺寸: " + visibleArea.getWidth() + "x" + visibleArea.getHeight());
System.out.println("页面 " + pageNum + " 二维码大小 (点): " + qrSize); // System.out.println("页面 " + pageNum + " 二维码大小 (点): " + qrSize);
// 计算左上角的位置PDF坐标系原点在左下角 // 计算左上角的位置PDF坐标系原点在左下角
float qrX = visibleArea.getLeft() + MARGIN; // float qrX = visibleArea.getLeft() + MARGIN;
float qrY = visibleArea.getTop() - qrSize - MARGIN; // float qrY = visibleArea.getTop() - qrSize - MARGIN;
// 打印二维码位置信息 // 打印二维码位置信息
System.out.println("页面 " + pageNum + " 左上角二维码位置: x=" + qrX + ", y=" + qrY); // System.out.println("页面 " + pageNum + " 左上角二维码位置: x=" + qrX + ", y=" + qrY);
float qrX;
float qrY;
if (visibleArea.getWidth() > visibleArea.getHeight()) {
qrX = H_QR_X;
qrY = H_QR_Y;
} else {
qrX = V_QR_X;
qrY = V_QR_Y;
}
try { try {
// 使用Canvas API添加左上角二维码 // 使用Canvas API添加左上角二维码
addQRCodeWithCanvas(pdfDoc, page, qrCodeBytes, qrX, qrY, qrSize); addQRCodeWithCanvas(pdfDoc, page, qrCodeBytes, qrX, qrY, QR_SIZE);
} catch (Exception e) { } catch (Exception e) {
System.err.println("在页面 " + pageNum + " 添加二维码时出错: " + e.getMessage()); System.err.println("在页面 " + pageNum + " 添加二维码时出错: " + e.getMessage());

View File

@ -2,6 +2,7 @@ package org.dromara.common.utils.baiduUtil;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.utils.baiduUtil.entity.face.ComparisonRes; import org.dromara.common.utils.baiduUtil.entity.face.ComparisonRes;
import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceReq; import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceReq;
import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceRes; import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceRes;
@ -23,6 +24,7 @@ import java.util.List;
* @Version 1.0 * @Version 1.0
* 处理百度人脸相关逻辑:人脸检测、人脸对比 * 处理百度人脸相关逻辑:人脸检测、人脸对比
*/ */
@Slf4j
@Service @Service
public class BaiDuFace { public class BaiDuFace {
@ -92,7 +94,8 @@ public class BaiDuFace {
// 7. 处理API返回错误 // 7. 处理API返回错误
if (faceRep.getErrorCode() != 0) { if (faceRep.getErrorCode() != 0) {
throw new RuntimeException("错误码说明:" + faceRep.getErrorMsg()); log.warn("百度人脸API返回错误码{}", faceRep.getErrorCode());
throw new RuntimeException("未检测到有效人脸信息");
} }
// 8. 验证人脸信息(无人脸时抛出异常) // 8. 验证人脸信息(无人脸时抛出异常)

View File

@ -17,10 +17,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController; import org.dromara.common.web.core.BaseController;
import org.dromara.contractor.domain.dto.constructionuser.*; import org.dromara.contractor.domain.dto.constructionuser.*;
import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo; import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo;
import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserAttendanceMonthVo; import org.dromara.contractor.domain.vo.constructionuser.*;
import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserAttendanceTotalVo;
import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserGisVo;
import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo;
import org.dromara.contractor.service.ISubConstructionUserService; import org.dromara.contractor.service.ISubConstructionUserService;
import org.dromara.project.domain.dto.project.BusProjectQueryReq; import org.dromara.project.domain.dto.project.BusProjectQueryReq;
import org.dromara.project.domain.dto.projectteam.BusProjectTeamQueryReq; import org.dromara.project.domain.dto.projectteam.BusProjectTeamQueryReq;
@ -30,8 +27,10 @@ import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
import org.dromara.project.service.IBusProjectTeamMemberService; import org.dromara.project.service.IBusProjectTeamMemberService;
import org.dromara.project.service.IBusProjectTeamService; import org.dromara.project.service.IBusProjectTeamService;
import org.dromara.system.domain.vo.SysOssVo;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
@ -233,7 +232,34 @@ public class SubConstructionUserController extends BaseController {
return R.ok(busProjectTeamMemberService.insertByBo(req)); return R.ok(busProjectTeamMemberService.insertByBo(req));
} }
/**
* 根据身份证图片获取身份证信息
*/
@SaCheckPermission("contractor:constructionUser:add")
@Log(title = "施工人员", businessType = BusinessType.OTHER)
@PostMapping("/idCard")
public R<SubConstructionUserOrcIdCardVo> getIdCardMessage(@RequestParam("file") MultipartFile file, String idCardSide) {
return R.ok(constructionUserService.getIdCardMessageByPic(file, idCardSide));
}
/**
* 根据银行卡图片获取银行卡信息
*/
@SaCheckPermission("contractor:constructionUser:add")
@Log(title = "施工人员", businessType = BusinessType.OTHER)
@PostMapping("/bankCard")
public R<SubConstructionUserOrcBankVo> getBankCardMessage(@RequestParam("file") MultipartFile file) {
return R.ok(constructionUserService.getBankCardMessageByPic(file));
}
/**
* 人脸识别
*/
@SaCheckPermission("contractor:constructionUser:add")
@Log(title = "施工人员", businessType = BusinessType.OTHER)
@PostMapping("/face/recognize")
public R<SysOssVo> faceRecognize(@RequestParam("file") MultipartFile file) {
return R.ok(constructionUserService.faceRecognize(file));
}
} }

View File

@ -1,8 +1,11 @@
package org.dromara.contractor.controller.app; package org.dromara.contractor.controller.app;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log; import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType; import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
@ -11,10 +14,14 @@ import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.contractor.domain.SubConstructionUser; import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.contractor.domain.dto.constructionuser.SubConstructionUserAuthenticationReq; import org.dromara.contractor.domain.dto.constructionuser.SubConstructionUserAuthenticationReq;
import org.dromara.contractor.domain.dto.constructionuser.SubConstructionUserQueryReq; import org.dromara.contractor.domain.dto.constructionuser.SubConstructionUserQueryReq;
import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserAppVo;
import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserOrcBankVo; import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserOrcBankVo;
import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserOrcIdCardVo; import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserOrcIdCardVo;
import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo; import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo;
import org.dromara.contractor.service.ISubConstructionUserService; import org.dromara.contractor.service.ISubConstructionUserService;
import org.dromara.project.domain.dto.projectteammember.BusProjectTeamMemberCreateReq;
import org.dromara.project.service.IBusProjectTeamMemberService;
import org.dromara.system.domain.vo.SysOssVo;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -33,6 +40,9 @@ public class SubConstructionUserAppController {
@Resource @Resource
private ISubConstructionUserService constructionUserService; private ISubConstructionUserService constructionUserService;
@Resource
private IBusProjectTeamMemberService busProjectTeamMemberService;
/** /**
* 查询施工人员列表 * 查询施工人员列表
*/ */
@ -111,6 +121,15 @@ public class SubConstructionUserAppController {
return R.ok(constructionUserService.insertByAuthentication(req)); return R.ok(constructionUserService.insertByAuthentication(req));
} }
/**
* 人脸识别
*/
@Log(title = "施工人员", businessType = BusinessType.OTHER)
@PostMapping("/face/recognize")
public R<SysOssVo> faceRecognize(@RequestParam("file") MultipartFile file) {
return R.ok(constructionUserService.faceRecognize(file));
}
/** /**
* 施工人员人脸比对 * 施工人员人脸比对
*/ */
@ -120,4 +139,21 @@ public class SubConstructionUserAppController {
return R.ok(constructionUserService.faceComparison(file)); return R.ok(constructionUserService.faceComparison(file));
} }
/**
* 查询未分配施工人员列表
*/
@GetMapping("/undistributedList")
public TableDataInfo<SubConstructionUserAppVo> queryUndistributedList(SubConstructionUserQueryReq req, PageQuery pageQuery) {
return constructionUserService.queryUndistributedList(req, pageQuery);
}
/**
* 添加项目班组
*/
@RepeatSubmit()
@PostMapping("/addTeam")
public R<Long> add(@Validated(AddGroup.class) @RequestBody BusProjectTeamMemberCreateReq req) {
return R.ok(busProjectTeamMemberService.insertByBo(req));
}
} }

View File

@ -0,0 +1,85 @@
package org.dromara.contractor.domain.vo.constructionuser;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.contractor.domain.SubConstructionUser;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
/**
* 施工人员视图对象 bus_construction_user
*
* @author lilemy
* @date 2025-03-07
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = SubConstructionUser.class)
public class SubConstructionUserAppVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 人员姓名
*/
@ExcelProperty(value = "人员姓名")
private String userName;
/**
* 联系电话
*/
@ExcelProperty(value = "联系电话")
private String phone;
/**
* 工种
*/
@ExcelProperty(value = "工种", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "type_of_work")
private String typeOfWork;
/**
* 工种名
*/
@Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "typeOfWork",other = "type_of_work")
private String typeOfWorkName;
/**
* 用户Id
*/
private Long sysUserId;
/**
* 用户头像
*/
private String avatar;
/**
* 入驻天数
*/
private Long days;
/**
* 用户性别0男 1女 2未知
*/
private String sex;
}

View File

@ -9,6 +9,7 @@ import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.contractor.domain.dto.constructionuser.*; import org.dromara.contractor.domain.dto.constructionuser.*;
import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo; import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo;
import org.dromara.contractor.domain.vo.constructionuser.*; import org.dromara.contractor.domain.vo.constructionuser.*;
import org.dromara.system.domain.vo.SysOssVo;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.util.Collection; import java.util.Collection;
@ -198,6 +199,14 @@ public interface ISubConstructionUserService extends IService<SubConstructionUse
*/ */
Long insertByAuthentication(SubConstructionUserAuthenticationReq req); Long insertByAuthentication(SubConstructionUserAuthenticationReq req);
/**
* 人脸识别
*
* @param file 图片文件
* @return 人脸识别结果
*/
SysOssVo faceRecognize(MultipartFile file);
/** /**
* 人脸识别 * 人脸识别
* *
@ -214,4 +223,7 @@ public interface ISubConstructionUserService extends IService<SubConstructionUse
*/ */
SubConstructionUser getBySysUserId(Long sysUserId); SubConstructionUser getBySysUserId(Long sysUserId);
TableDataInfo<SubConstructionUserAppVo> queryUndistributedList(SubConstructionUserQueryReq req, PageQuery pageQuery);
} }

View File

@ -6,7 +6,6 @@ import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil; import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -320,8 +319,6 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl<SubConstruct
throw new ServiceException("施工人员不存在", HttpStatus.NOT_FOUND); throw new ServiceException("施工人员不存在", HttpStatus.NOT_FOUND);
} }
// 2. 查询当前用户的所有文件记录(一次性查询,避免多次访问数据库) // 2. 查询当前用户的所有文件记录(一次性查询,避免多次访问数据库)
LambdaQueryWrapper<SubConstructionUserFile> lqw = Wrappers.lambdaQuery(SubConstructionUserFile.class)
.eq(SubConstructionUserFile::getUserId, userId);
List<SubConstructionUserFile> constructionUserFileList = this.lambdaQuery() List<SubConstructionUserFile> constructionUserFileList = this.lambdaQuery()
.eq(SubConstructionUserFile::getUserId, userId) .eq(SubConstructionUserFile::getUserId, userId)
.list(); .list();

View File

@ -66,10 +66,8 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.*;
import java.time.LocalDateTime; import java.time.temporal.ChronoUnit;
import java.time.Period;
import java.time.YearMonth;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -645,9 +643,12 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
// 批量删除施工人员下的文件信息 // 批量删除施工人员下的文件信息
LambdaQueryWrapper<SubConstructionUserFile> constructionUserFileLqw = Wrappers.lambdaQuery(SubConstructionUserFile.class) LambdaQueryWrapper<SubConstructionUserFile> constructionUserFileLqw = Wrappers.lambdaQuery(SubConstructionUserFile.class)
.in(SubConstructionUserFile::getUserId, ids); .in(SubConstructionUserFile::getUserId, ids);
boolean removeFile = constructionUserFileService.remove(constructionUserFileLqw); List<SubConstructionUserFile> fileList = constructionUserFileService.list(constructionUserFileLqw);
if (!removeFile) { if (CollUtil.isNotEmpty(fileList)) {
throw new ServiceException("删除施工人员信息失败,施工人员文件信息删除失败", HttpStatus.ERROR); boolean removeFile = constructionUserFileService.remove(constructionUserFileLqw);
if (!removeFile) {
throw new ServiceException("删除施工人员信息失败,施工人员文件信息删除失败", HttpStatus.ERROR);
}
} }
// 批量删除施工人员信息 // 批量删除施工人员信息
return this.removeBatchByIds(ids); return this.removeBatchByIds(ids);
@ -676,7 +677,10 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
// 关联查询分包公司信息信息 // 关联查询分包公司信息信息
Long contractorId = constructionUser.getContractorId(); Long contractorId = constructionUser.getContractorId();
if (contractorId != null) { if (contractorId != null) {
constructionUserVo.setContractorName(contractorService.getById(contractorId).getName()); SubContractor contractor = contractorService.getById(contractorId);
if (contractor != null) {
constructionUserVo.setContractorName(contractor.getName());
}
} }
// 关联查询用户头像url // 关联查询用户头像url
String facePic = constructionUser.getFacePic(); String facePic = constructionUser.getFacePic();
@ -1195,6 +1199,22 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
return user.getId(); return user.getId();
} }
/**
* 人脸识别
*
* @param file 图片文件
* @return 人脸识别结果
*/
@Override
public SysOssVo faceRecognize(MultipartFile file) {
String reqBase64 = this.getPicBase64(file);
HumanFaceReq faceReq = new HumanFaceReq();
faceReq.setImage(reqBase64);
// 调用人脸识别接口
baiDuFace.humanFace(faceReq);
return ossService.upload(file);
}
/** /**
* 人脸识别 * 人脸识别
* *
@ -1203,18 +1223,7 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
*/ */
@Override @Override
public Boolean faceComparison(MultipartFile file) { public Boolean faceComparison(MultipartFile file) {
if (file == null) { String reqBase64 = this.getPicBase64(file);
throw new ServiceException("请上传图片", HttpStatus.BAD_REQUEST);
}
String reqBase64;
try {
// 获取文件字节数组
byte[] bytes = file.getBytes();
// Base64 编码
reqBase64 = Base64.getEncoder().encodeToString(bytes);
} catch (IOException e) {
throw new ServiceException("图片转换失败,请重新上传");
}
HumanFaceReq request = new HumanFaceReq(); HumanFaceReq request = new HumanFaceReq();
request.setImage(reqBase64); request.setImage(reqBase64);
Long userId = LoginHelper.getUserId(); Long userId = LoginHelper.getUserId();
@ -1264,4 +1273,64 @@ public class SubConstructionUserServiceImpl extends ServiceImpl<SubConstructionU
return constructionUser; return constructionUser;
} }
/**
* 获取图片的Base64编码
*
* @param file 图片文件
* @return 图片的Base64编码
*/
private String getPicBase64(MultipartFile file) {
if (file == null) {
throw new ServiceException("请上传图片", HttpStatus.BAD_REQUEST);
}
String reqBase64;
try {
// 获取文件字节数组
byte[] bytes = file.getBytes();
// Base64 编码
reqBase64 = Base64.getEncoder().encodeToString(bytes);
} catch (IOException e) {
throw new ServiceException("图片转换失败,请重新上传");
}
return reqBase64;
}
@Override
public TableDataInfo<SubConstructionUserAppVo> queryUndistributedList(SubConstructionUserQueryReq req, PageQuery pageQuery) {
LambdaQueryWrapper<SubConstructionUser> lqw = Wrappers.lambdaQuery();
String userName = req.getUserName();
String typeOfWork = req.getTypeOfWork();
lqw.like(StringUtils.isNotBlank(userName), SubConstructionUser::getUserName, userName);
lqw.eq(ObjectUtils.isNotEmpty(typeOfWork), SubConstructionUser::getTypeOfWork, typeOfWork);
lqw.isNull(SubConstructionUser::getProjectId);
lqw.isNull(SubConstructionUser::getTeamId);
Page<SubConstructionUser> result = this.page(pageQuery.build(), lqw);
ArrayList<SubConstructionUserAppVo> list = new ArrayList<>();
for ( SubConstructionUser constructionUser : result.getRecords()){
SubConstructionUserAppVo subConstructionUserAppVo = new SubConstructionUserAppVo();
BeanUtils.copyProperties(constructionUser, subConstructionUserAppVo);
SysUserVo sysUserVo = userService.selectUserById(subConstructionUserAppVo.getSysUserId());
if(sysUserVo.getAvatar() != null)
subConstructionUserAppVo.setAvatar(ossService.getById(sysUserVo.getAvatar()).getUrl());
//计算日期
Date createTime = sysUserVo.getCreateTime();
Instant createInstant = createTime.toInstant();
Instant nowInstant = Instant.now();
long days = ChronoUnit.DAYS.between(
createInstant.atZone(ZoneId.systemDefault()).toLocalDateTime(),
nowInstant.atZone(ZoneId.systemDefault()).toLocalDateTime()
);
subConstructionUserAppVo.setDays(days);
subConstructionUserAppVo.setSex(sysUserVo.getSex());
list.add(subConstructionUserAppVo);
}
return new TableDataInfo<>(list,result.getTotal());
}
} }

View File

@ -40,6 +40,11 @@ public class BusBillofquantitiesVersions extends BaseEntity {
*/ */
private String versions; private String versions;
/**
* 版本号名称
*/
private String versionsName;
/** /**
* exlce文件 * exlce文件
*/ */

View File

@ -39,4 +39,11 @@ public class BusBillofquantitiesVersionsBo extends BaseEntity {
private String versions; private String versions;
/**
* 版本号名称
*/
private String versionsName;
} }

View File

@ -40,4 +40,7 @@ public class DesVolumeCatalogQueryReq implements Serializable {
private String type; private String type;
private String isUpload;
} }

View File

@ -48,6 +48,13 @@ public class BusBillofquantitiesVersionsVo implements Serializable {
private String versions; private String versions;
/**
* 版本号名称
*/
private String versionsName;
/** /**
* Excel文件 * Excel文件
*/ */

View File

@ -191,8 +191,22 @@ public class BusBillofquantitiesVersionsServiceImpl extends ServiceImpl<BusBillo
throw new ServiceException("上传文件失败"); throw new ServiceException("上传文件失败");
} }
String banBen = BatchNumberGenerator.generateBatchNumber("GCLBB-"); String banBen = BatchNumberGenerator.generateBatchNumber("GCLBB-");
String[] split = StringUtils.split(wordEntity.getFileName(),".xlsx");
String vName = "";
switch (bo.getWorkOrderType()){
case "0":
vName = "投标工程量清单-"+split[0];
case "1":
vName = "限价工程量清单-"+split[0];
case "2":
vName = "招采工程量清单-"+split[0];
case "3":
vName = "物资设备清单-"+split[0];
}
int insert = baseMapper.insert(new BusBillofquantitiesVersions(). int insert = baseMapper.insert(new BusBillofquantitiesVersions().
setWorkOrderType(bo.getWorkOrderType()). setWorkOrderType(bo.getWorkOrderType()).
setVersionsName(vName).
setVersions(banBen). setVersions(banBen).
setProjectId(bo.getProjectId()). setProjectId(bo.getProjectId()).
setExcelFile(wordEntity.getUrl())); setExcelFile(wordEntity.getUrl()));

View File

@ -334,12 +334,17 @@ public class DesVolumeCatalogServiceImpl extends ServiceImpl<DesVolumeCatalogMap
String volumeNumber = req.getVolumeNumber(); String volumeNumber = req.getVolumeNumber();
String documentName = req.getDocumentName(); String documentName = req.getDocumentName();
String auditStatus = req.getAuditStatus(); String auditStatus = req.getAuditStatus();
String isUpload = req.getIsUpload();
// lqw.orderByDesc(DesVolumeCatalog::getCreateTime); // lqw.orderByDesc(DesVolumeCatalog::getCreateTime);
lqw.orderByAsc(DesVolumeCatalog::getSerialNumber); lqw.orderByAsc(DesVolumeCatalog::getSerialNumber);
lqw.like(StringUtils.isNotBlank(documentName), DesVolumeCatalog::getDocumentName, documentName); lqw.like(StringUtils.isNotBlank(documentName), DesVolumeCatalog::getDocumentName, documentName);
lqw.eq(StringUtils.isNotBlank(volumeNumber), DesVolumeCatalog::getVolumeNumber, volumeNumber); lqw.eq(StringUtils.isNotBlank(volumeNumber), DesVolumeCatalog::getVolumeNumber, volumeNumber);
lqw.eq(ObjectUtils.isNotEmpty(projectId), DesVolumeCatalog::getProjectId, projectId); lqw.eq(ObjectUtils.isNotEmpty(projectId), DesVolumeCatalog::getProjectId, projectId);
lqw.eq(StringUtils.isNotBlank(auditStatus), DesVolumeCatalog::getAuditStatus, auditStatus); lqw.eq(StringUtils.isNotBlank(auditStatus), DesVolumeCatalog::getAuditStatus, auditStatus);
lqw.exists("1".equals(isUpload),"SELECT 1 FROM des_volume_file WHERE volume_catalog_id = des_volume_catalog.design");
lqw.notExists("0".equals(isUpload),"SELECT 1 FROM des_volume_file WHERE volume_catalog_id = des_volume_catalog.design");
return lqw; return lqw;
} }

View File

@ -94,7 +94,9 @@ public class DesVolumeFileServiceImpl extends ServiceImpl<DesVolumeFileMapper, D
Page<DesVolumeFileVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); Page<DesVolumeFileVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
for (DesVolumeFileVo vo : result.getRecords()) { for (DesVolumeFileVo vo : result.getRecords()) {
SysOssVo ossVo = ossService.getById(vo.getFileId()); SysOssVo ossVo = ossService.getById(vo.getFileId());
vo.setFileUrl(ossVo.getUrl()); if (ossVo != null) {
vo.setFileUrl(ossVo.getUrl());
}
} }
return TableDataInfo.build(result); return TableDataInfo.build(result);
} }
@ -269,18 +271,18 @@ public class DesVolumeFileServiceImpl extends ServiceImpl<DesVolumeFileMapper, D
} }
} }
// 过程文件 // 过程文件
if (CollectionUtil.isNotEmpty(req.getCancellationIds())) { // if (CollectionUtil.isNotEmpty(req.getCancellationIds())) {
List<DesVolumeFile> existingFiles = baseMapper.selectList(new LambdaQueryWrapper<DesVolumeFile>() // List<DesVolumeFile> existingFiles = baseMapper.selectList(new LambdaQueryWrapper<DesVolumeFile>()
.eq(DesVolumeFile::getVolumeCatalogId, req.getVolumeCatalogId()) // .eq(DesVolumeFile::getVolumeCatalogId, req.getVolumeCatalogId())
.eq(DesVolumeFile::getType, DesVolumeFile.PROCESS) // .eq(DesVolumeFile::getType, DesVolumeFile.PROCESS)
.orderByDesc(DesVolumeFile::getVersion)); // .orderByDesc(DesVolumeFile::getVersion));
if (!existingFiles.isEmpty()) { // if (!existingFiles.isEmpty()) {
DesVolumeFile first = existingFiles.getFirst(); // DesVolumeFile first = existingFiles.getFirst();
if (!BusinessStatusEnum.FINISH.getStatus().equals(first.getAuditStatus())) { // if (!BusinessStatusEnum.FINISH.getStatus().equals(first.getAuditStatus())) {
throw new ServiceException("文件尚未审核完成,请勿重复上传"); // throw new ServiceException("文件尚未审核完成,请勿重复上传");
} // }
} // }
} // }
} }

View File

@ -13,6 +13,7 @@ import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.utils.JSTUtil;
import org.dromara.facility.constant.FacRedisKeyConstant; import org.dromara.facility.constant.FacRedisKeyConstant;
import org.dromara.facility.domain.*; import org.dromara.facility.domain.*;
import org.dromara.facility.domain.dto.geojson.*; import org.dromara.facility.domain.dto.geojson.*;
@ -27,7 +28,6 @@ import org.dromara.facility.service.*;
import org.dromara.progress.service.IPgsProgressCategoryService; import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.project.domain.BusProject; import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
import org.dromara.common.utils.JSTUtil;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
@ -659,7 +659,7 @@ public class FacMatrixServiceImpl extends ServiceImpl<FacMatrixMapper, FacMatrix
FacPhotovoltaicPanel::getStatus FacPhotovoltaicPanel::getStatus
) )
.eq(FacPhotovoltaicPanel::getProjectId, projectId) .eq(FacPhotovoltaicPanel::getProjectId, projectId)
.eq(FacPhotovoltaicPanel::getProgressCategoryName, "光伏板") .eq(FacPhotovoltaicPanel::getProgressCategoryName, "组件安装")
.in(CollUtil.isNotEmpty(matrixIdList), FacPhotovoltaicPanel::getMatrixId, matrixIdList) .in(CollUtil.isNotEmpty(matrixIdList), FacPhotovoltaicPanel::getMatrixId, matrixIdList)
.list(); .list();
List<FacFacilityPositionGisVo> panelVoList = panelList.stream().map(obj -> List<FacFacilityPositionGisVo> panelVoList = panelList.stream().map(obj ->

View File

@ -277,7 +277,7 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
String name = nameProperties.getText(); String name = nameProperties.getText();
// ① 获取名称 // ① 获取名称
if (StringUtils.isBlank(name)) return Collections.emptyList(); if (StringUtils.isBlank(name)) return Collections.emptyList();
if (!name.startsWith("G")) return Collections.emptyList(); // if (!name.startsWith("G")) return Collections.emptyList();
List<FacPhotovoltaicPanel> panelList = new ArrayList<>(); List<FacPhotovoltaicPanel> panelList = new ArrayList<>();
// ② 找到该点对应的 polygon优先包含否则最近 // ② 找到该点对应的 polygon优先包含否则最近
FacFeatureByPlane matchedPolygon = JSTUtil.findNearestOrContainingPolygon(nameFeature, locationFeatures); FacFeatureByPlane matchedPolygon = JSTUtil.findNearestOrContainingPolygon(nameFeature, locationFeatures);

View File

@ -1,6 +1,7 @@
package org.dromara.gps.controller; package org.dromara.gps.controller;
import java.util.List; import java.util.List;
import java.util.Map;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@ -16,9 +17,7 @@ import org.dromara.contractor.domain.dto.constructionuser.SubConstructionUserQue
import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo; import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo;
import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo; import org.dromara.contractor.domain.vo.constructionuser.SubConstructionUserVo;
import org.dromara.contractor.service.ISubConstructionUserService; import org.dromara.contractor.service.ISubConstructionUserService;
import org.dromara.gps.domain.vo.ConstructionUser; import org.dromara.gps.domain.vo.*;
import org.dromara.gps.domain.vo.GpsProjectVo;
import org.dromara.gps.domain.vo.GpsUserVo;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
import org.dromara.system.domain.SysUser; import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
@ -33,7 +32,6 @@ import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup; import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType; import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.gps.domain.vo.GpsEquipmentVo;
import org.dromara.gps.domain.bo.GpsEquipmentBo; import org.dromara.gps.domain.bo.GpsEquipmentBo;
import org.dromara.gps.service.IGpsEquipmentService; import org.dromara.gps.service.IGpsEquipmentService;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
@ -59,6 +57,19 @@ public class GpsEquipmentController extends BaseController {
private final IBusProjectService projectService; private final IBusProjectService projectService;
/**
* 接收设备数据
* @param jsonData
* @return
*/
@PostMapping("/setData")
public R<Void> setData(@RequestBody String jsonData) {
log.info("接收设备数据:{}", jsonData);
gpsEquipmentService.setData(jsonData);
return toAjax(true);
}
/** /**
* 接收设备数据 * 接收设备数据
* @param jsonData * @param jsonData

View File

@ -9,6 +9,8 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
import java.util.List;
/** /**
* GPS设备详细业务对象 gps_equipment * GPS设备详细业务对象 gps_equipment
* *
@ -78,4 +80,6 @@ public class GpsEquipmentBo extends BaseEntity {
private Integer type; private Integer type;
private List<String> idList;
} }

View File

@ -1,9 +1,13 @@
package org.dromara.gps.mapper; package org.dromara.gps.mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.dromara.gps.domain.GpsEquipmentSon; import org.dromara.gps.domain.GpsEquipmentSon;
import org.dromara.gps.domain.vo.GpsEquipmentSonVo; import org.dromara.gps.domain.vo.GpsEquipmentSonVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/** /**
* GPS设备定位信息Mapper接口 * GPS设备定位信息Mapper接口
* *
@ -12,4 +16,20 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
*/ */
public interface GpsEquipmentSonMapper extends BaseMapperPlus<GpsEquipmentSon, GpsEquipmentSonVo> { public interface GpsEquipmentSonMapper extends BaseMapperPlus<GpsEquipmentSon, GpsEquipmentSonVo> {
@Select("WITH RankedData AS (\n" +
" SELECT\n" +
" *,\n" +
" ROW_NUMBER() OVER (PARTITION BY client_id ORDER BY create_time DESC) AS rn\n" +
" FROM\n" +
" gps_equipment_son \n" +
"WHERE \n" +
"project_id = #{projectId}\n" +
")\n" +
"SELECT\n" +
" *\n" +
"FROM\n" +
" RankedData\n" +
"WHERE\n" +
" rn = 1;")
List<GpsEquipmentSonVo> getClientList(@Param("projectId") Long projectId);
} }

View File

@ -1,5 +1,6 @@
package org.dromara.gps.service; package org.dromara.gps.service;
import org.dromara.gps.domain.vo.GpsEquipmentSonVo;
import org.dromara.gps.domain.vo.GpsEquipmentVo; import org.dromara.gps.domain.vo.GpsEquipmentVo;
import org.dromara.gps.domain.bo.GpsEquipmentBo; import org.dromara.gps.domain.bo.GpsEquipmentBo;
import org.dromara.gps.domain.GpsEquipment; import org.dromara.gps.domain.GpsEquipment;
@ -94,4 +95,8 @@ public interface IGpsEquipmentService extends IService<GpsEquipment>{
List<GpsUserVo> getUserList(GpsEquipmentBo bo); List<GpsUserVo> getUserList(GpsEquipmentBo bo);
List<GpsProjectVo> getProjectList(); List<GpsProjectVo> getProjectList();
List<GpsEquipmentSonVo> getClientList(Long projectId);
void setData(String jsonData);
} }

View File

@ -67,4 +67,6 @@ public interface IGpsEquipmentSonService extends IService<GpsEquipmentSon>{
* @return 是否删除成功 * @return 是否删除成功
*/ */
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
List<GpsEquipmentSonVo> getClientList(Long projectId);
} }

View File

@ -1,6 +1,7 @@
package org.dromara.gps.service.impl; package org.dromara.gps.service.impl;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@ -20,6 +21,7 @@ import org.dromara.common.websocket.dto.WebSocketMessageDto;
import org.dromara.common.websocket.utils.WebSocketUtils; import org.dromara.common.websocket.utils.WebSocketUtils;
import org.dromara.gps.domain.GpsManmachine; import org.dromara.gps.domain.GpsManmachine;
import org.dromara.gps.domain.bo.GpsEquipmentSonBo; import org.dromara.gps.domain.bo.GpsEquipmentSonBo;
import org.dromara.gps.domain.vo.GpsEquipmentSonVo;
import org.dromara.gps.domain.vo.GpsProjectVo; import org.dromara.gps.domain.vo.GpsProjectVo;
import org.dromara.gps.domain.vo.GpsUserVo; import org.dromara.gps.domain.vo.GpsUserVo;
import org.dromara.gps.mapper.GpsManmachineMapper; import org.dromara.gps.mapper.GpsManmachineMapper;
@ -44,7 +46,6 @@ import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.Duration; import java.time.Duration;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* GPS设备详细Service业务层处理 * GPS设备详细Service业务层处理
@ -246,11 +247,11 @@ public class GpsEquipmentServiceImpl extends ServiceImpl<GpsEquipmentMapper, Gps
// WebSocketUtils.publishAll(pushContent); // WebSocketUtils.publishAll(pushContent);
// 2. 发布消息根据是否有用户ID决定发送给指定用户或广播 // 2. 发布消息根据是否有用户ID决定发送给指定用户或广播
if (equipment != null && equipment.getUserId() != null) { if (equipment != null && equipment.getProjectId() != null) {
// 发送给指定用户equipment.getUserId() // 发送给指定用户equipment.getUserId()
WebSocketMessageDto messageDto = new WebSocketMessageDto(); WebSocketMessageDto messageDto = new WebSocketMessageDto();
messageDto.setMessage(pushContent); messageDto.setMessage(pushContent);
messageDto.setSessionKeys(Collections.singletonList(equipment.getUserId())); messageDto.setSessionKeys(Collections.singletonList(equipment.getProjectId()));
WebSocketUtils.publishMessage(messageDto); WebSocketUtils.publishMessage(messageDto);
} else { } else {
// 无用户ID则广播给所有在线客户端 // 无用户ID则广播给所有在线客户端
@ -427,4 +428,24 @@ public class GpsEquipmentServiceImpl extends ServiceImpl<GpsEquipmentMapper, Gps
}); });
return list; return list;
} }
@Override
public List<GpsEquipmentSonVo> getClientList(Long projectId) {
return gpsEquipmentSonService.getClientList(projectId);
}
@Override
public void setData(String jsonData) {
// 发送给指定用户equipment.getUserId()
WebSocketMessageDto messageDto = new WebSocketMessageDto();
messageDto.setMessage(jsonData);
messageDto.setSessionKeys(Collections.singletonList(1897160897167638522L));
WebSocketUtils.publishMessage(messageDto);
// WebSocketUtils.publishAll(jsonData);
}
} }

View File

@ -130,4 +130,9 @@ public class GpsEquipmentSonServiceImpl extends ServiceImpl<GpsEquipmentSonMappe
} }
return baseMapper.deleteByIds(ids) > 0; return baseMapper.deleteByIds(ids) > 0;
} }
@Override
public List<GpsEquipmentSonVo> getClientList(Long projectId) {
return baseMapper.getClientList(projectId);
}
} }

View File

@ -0,0 +1,182 @@
package org.dromara.job.attendance;
import com.aizuda.snailjob.client.job.core.enums.AllocationAlgorithmEnum;
import com.aizuda.snailjob.client.job.core.enums.TriggerTypeEnum;
import com.aizuda.snailjob.client.job.core.openapi.SnailJobOpenApi;
import com.aizuda.snailjob.common.core.enums.BlockStrategyEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.project.domain.BusAttendanceRule;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusAttendanceRuleService;
import org.dromara.project.service.IBusProjectService;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.time.LocalTime;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Slf4j
@Component
public class AttendanceJobUtil {
public static final String CLOCK_IN_REMINDER = "clockInReminder";
public static final String CLOCK_OUT_REMINDER = "clockOutReminder";
@Resource
private IBusProjectService projectService;
@Resource
@Lazy
private IBusAttendanceRuleService attendanceRuleService;
@Async
public void addClusterJob(BusAttendanceRule rule) {
BusProject project = projectService.getById(rule.getProjectId());
String projectName = project.getProjectName();
String jobName1 = projectName + "上班打卡提醒";
LocalTime clockInTime = rule.getClockInTime();
//提前10分钟
LocalTime clockInReminderTime = clockInTime.minusMinutes(10);
String dailyCron1 = toDailyCron(clockInReminderTime);
Long execute1 = SnailJobOpenApi.addClusterJob()
.setRouteKey(AllocationAlgorithmEnum.RANDOM)
.setJobName(jobName1)
.setExecutorInfo(CLOCK_IN_REMINDER)
.setExecutorTimeout(30)
.setDescription("add")
.setBlockStrategy(BlockStrategyEnum.DISCARD)
.setMaxRetryTimes(1)
.setTriggerType(TriggerTypeEnum.CRON)
.setTriggerInterval(dailyCron1)
.addArgsStr("projectId", rule.getProjectId())
.setRetryInterval(3)
.execute();
rule.setClockInJobId(execute1);
String jobName2 = projectName + "下班打卡提醒";
LocalTime clockOutTime = rule.getClockOutTime();
//后延10分钟
LocalTime clockOutReminderTime = clockOutTime.plusMinutes(10);
String dailyCron2 = toDailyCron(clockOutReminderTime);
Long execute = SnailJobOpenApi.addClusterJob()
.setRouteKey(AllocationAlgorithmEnum.RANDOM)
.setJobName(jobName2)
.setExecutorInfo(CLOCK_OUT_REMINDER)
.setExecutorTimeout(30)
.setDescription("add")
.setBlockStrategy(BlockStrategyEnum.DISCARD)
.setMaxRetryTimes(1)
.setTriggerType(TriggerTypeEnum.CRON)
.setTriggerInterval(dailyCron2)
.addArgsStr("projectId", rule.getProjectId())
.setRetryInterval(3)
.execute();
rule.setClockOutJobId(execute);
attendanceRuleService.updateById(rule);
}
@Async
public void updateClusterJob(Long id) {
BusAttendanceRule rule = attendanceRuleService.getById(id);
BusProject project = projectService.getById(rule.getProjectId());
String projectName = project.getProjectName();
LocalTime clockInTime = rule.getClockInTime();
//提前10分钟
LocalTime clockInReminderTime = clockInTime.minusMinutes(10);
String dailyCron1 = toDailyCron(clockInReminderTime);
if (rule.getClockInJobId() != null) {
SnailJobOpenApi.updateClusterJob(rule.getClockInJobId())
.setTriggerType(TriggerTypeEnum.CRON)
.setTriggerInterval(dailyCron1)
.execute();
} else {
String jobName1 = projectName + "上班打卡提醒";
Long execute = SnailJobOpenApi.addClusterJob()
.setRouteKey(AllocationAlgorithmEnum.RANDOM)
.setJobName(jobName1)
.setExecutorInfo(CLOCK_IN_REMINDER)
.setExecutorTimeout(30)
.setDescription("add")
.setBlockStrategy(BlockStrategyEnum.DISCARD)
.setMaxRetryTimes(1)
.setTriggerType(TriggerTypeEnum.CRON)
.setTriggerInterval(dailyCron1)
.addArgsStr("projectId", rule.getProjectId())
.setRetryInterval(3)
.execute();
rule.setClockInJobId(execute);
}
LocalTime clockOutTime = rule.getClockOutTime();
//后延10分钟
LocalTime clockOutReminderTime = clockOutTime.plusMinutes(10);
String dailyCron2 = toDailyCron(clockOutReminderTime);
if (rule.getClockOutJobId() != null) {
SnailJobOpenApi.updateClusterJob(rule.getClockOutJobId())
.setTriggerType(TriggerTypeEnum.CRON)
.setTriggerInterval(dailyCron2)
.execute();
} else {
String jobName2 = projectName + "下班打卡提醒";
Long execute = SnailJobOpenApi.addClusterJob()
.setRouteKey(AllocationAlgorithmEnum.RANDOM)
.setJobName(jobName2)
.setExecutorInfo(CLOCK_OUT_REMINDER)
.setExecutorTimeout(30)
.setDescription("add")
.setBlockStrategy(BlockStrategyEnum.DISCARD)
.setMaxRetryTimes(1)
.setTriggerType(TriggerTypeEnum.CRON)
.setTriggerInterval(dailyCron2)
.addArgsStr("projectId", rule.getProjectId())
.setRetryInterval(3)
.execute();
rule.setClockOutJobId(execute);
}
attendanceRuleService.updateById(rule);
}
@Async
public void deleteClusterJob(List<BusAttendanceRule> rules) {
Set<Long> jobIds = rules.stream()
.flatMap(rule -> Stream.of(rule.getClockInJobId(), rule.getClockOutJobId())) // 提取两个 JobId
.filter(Objects::nonNull) // 过滤掉 null 值
.collect(Collectors.toSet()); // 收集
rules.stream().map(BusAttendanceRule::getClockInJobId).filter(Objects::nonNull).forEach(jobIds::add);
SnailJobOpenApi.deleteJob(jobIds).execute();
}
/**
* 将LocalTime转换为每天执行的Cron表达式
*
* @param time 时间
* @return 每天在指定时间执行的Cron表达式
*/
public String toDailyCron(LocalTime time) {
int hour = time.getHour();
int minute = time.getMinute();
// Cron格式: 秒 分 时 日 月 周 年(可选)
return String.format("0 %d %d * * ?", minute, hour);
}
}

View File

@ -0,0 +1,109 @@
package org.dromara.job.attendance;
import cn.hutool.json.JSONUtil;
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
import com.aizuda.snailjob.client.job.core.dto.JobArgs;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.contractor.service.ISubConstructionUserService;
import org.dromara.project.domain.BusAttendanceRule;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.BusUserProjectRelevancy;
import org.dromara.project.service.IBusAttendanceRuleService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.project.service.IBusUserProjectRelevancyService;
import org.dromara.websocket.ChatServerHandler;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j
@Component
public class AttendanceReminderJob {
@Resource
private IBusUserProjectRelevancyService userProjectRelevancyService;
@Resource
private ChatServerHandler chatServerHandler;
@Resource
private IBusProjectService projectService;
@Resource
private IBusAttendanceRuleService attendanceRuleService;
@Resource
private ISubConstructionUserService constructionUserService;
@JobExecutor(name = "clockInReminder")
public void clockInReminder(JobArgs jobArgs) {
Long projectId = JSONUtil.parseObj(jobArgs.getJobParams()).getLong("projectId");
log.info("项目ID:{},开始执行打卡提醒任务", projectId);
BusProject project = projectService.getById(projectId);
BusAttendanceRule rule = attendanceRuleService.getOne(Wrappers.<BusAttendanceRule>lambdaQuery()
.eq(BusAttendanceRule::getProjectId, projectId)
.last("limit 1")
);
if (rule == null || project == null) {
return;
}
//查询项目下的关联人员
List<BusUserProjectRelevancy> relevancyList = userProjectRelevancyService.list(Wrappers.lambdaQuery(BusUserProjectRelevancy.class)
.eq(BusUserProjectRelevancy::getProjectId, projectId));
String message = String.format("【%s项目】上班打卡提醒请在 %s 前完成打卡。",
project.getProjectName(), rule.getClockInTime().toString());
Set<Long> collect = relevancyList.stream().map(BusUserProjectRelevancy::getUserId).collect(Collectors.toSet());
List<SubConstructionUser> list = constructionUserService.list(Wrappers.lambdaQuery(SubConstructionUser.class)
.in(SubConstructionUser::getSysUserId, collect));
Set<Long> list1 = list.stream().map(SubConstructionUser::getSysUserId).collect(Collectors.toSet());
for (Long userId : list1) {
chatServerHandler.sendSystemMessageToUser(userId, message);
}
}
@JobExecutor(name = "clockOutReminder")
public void clockOutReminder(JobArgs jobArgs) {
Long projectId = JSONUtil.parseObj(jobArgs.getJobParams()).getLong("projectId");
log.info("项目ID:{},开始执行打卡提醒任务", projectId);
BusProject project = projectService.getById(projectId);
BusAttendanceRule rule = attendanceRuleService.getOne(Wrappers.<BusAttendanceRule>lambdaQuery()
.eq(BusAttendanceRule::getProjectId, projectId)
.last("limit 1")
);
if (rule == null || project == null) {
return;
}
//查询项目下的关联人员
List<BusUserProjectRelevancy> relevancyList = userProjectRelevancyService.list(Wrappers.lambdaQuery(BusUserProjectRelevancy.class)
.eq(BusUserProjectRelevancy::getProjectId, projectId));
String message = String.format("【%s项目】下班打卡提醒请记得完成打卡。",
project.getProjectName());
Set<Long> collect = relevancyList.stream().map(BusUserProjectRelevancy::getUserId).collect(Collectors.toSet());
List<SubConstructionUser> list = constructionUserService.list(Wrappers.lambdaQuery(SubConstructionUser.class)
.in(SubConstructionUser::getSysUserId, collect));
Set<Long> list1 = list.stream().map(SubConstructionUser::getSysUserId).collect(Collectors.toSet());
for (Long userId : list1) {
chatServerHandler.sendSystemMessageToUser(userId, message);
}
}
}

View File

@ -127,6 +127,7 @@ public class BusLandTransferLedgerServiceImpl extends ServiceImpl<BusLandTransfe
String transferStatus = son.getTransferStatus(); String transferStatus = son.getTransferStatus();
//0是未流转1已流转2是不流转 //0是未流转1已流转2是不流转
switch (transferStatus) { switch (transferStatus) {
case "1": case "1":
if (son.getAreaValue() != null) { if (son.getAreaValue() != null) {
transferArea = transferArea.add(son.getAreaValue()); transferArea = transferArea.add(son.getAreaValue());
@ -138,17 +139,21 @@ public class BusLandTransferLedgerServiceImpl extends ServiceImpl<BusLandTransfe
noTrans = noTrans.add(son.getAreaValue()); noTrans = noTrans.add(son.getAreaValue());
} }
break; break;
default: default:
break; break;
} }
//土地租金(元) //土地租金(元)
if (son.getLandRent() != null) { if (son.getLandRent() != null) {
landRentAll = landRentAll.add(son.getLandRent()); landRentAll = landRentAll.add(son.getLandRent());
} }
//青苗赔偿(元) //青苗赔偿(元)
if (son.getSeedlingCompensation()!=null) { if (son.getSeedlingCompensation()!=null) {
seedlingCompensationAll = seedlingCompensationAll.add(son.getSeedlingCompensation()); seedlingCompensationAll = seedlingCompensationAll.add(son.getSeedlingCompensation());
} }
//总金额(元) //总金额(元)
if (son.getTotalAmount()!=null) { if (son.getTotalAmount()!=null) {
totalAmountAll = totalAmountAll.add(son.getTotalAmount()); totalAmountAll = totalAmountAll.add(son.getTotalAmount());

View File

@ -1,11 +1,17 @@
package org.dromara.manager.weathermanager; 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.HttpRequest;
import cn.hutool.http.HttpResponse; 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 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.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.manager.weathermanager.vo.WeatherVo;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -16,7 +22,10 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Base64; import java.util.Base64;
import java.util.List;
import java.util.Map;
/** /**
* @author lilemy * @author lilemy
@ -58,6 +67,67 @@ public class WeatherManager {
return body; 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 * 获取天气预报 Url
* *

View File

@ -1,4 +1,4 @@
package org.dromara.project.domain.vo.project; package org.dromara.manager.weathermanager.vo;
import lombok.Data; import lombok.Data;
@ -7,13 +7,13 @@ import java.io.Serializable;
/** /**
* @author lilemy * @author lilemy
* @date 2025/5/13 9:29 * @date 2025-09-09 15:14
*/ */
@Data @Data
public class BusProjectWeatherVo implements Serializable { public class WeatherVo implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 4173514725591666698L; private static final long serialVersionUID = 6518020416043269221L;
/** /**
* 日期 * 日期
@ -64,5 +64,4 @@ public class BusProjectWeatherVo implements Serializable {
* 晚上天气图标 * 晚上天气图标
*/ */
private String nightIcon; private String nightIcon;
} }

View File

@ -123,6 +123,16 @@ public class MatMaterialReceive extends BaseEntity {
*/ */
private String licenseCountFileId; private String licenseCountFileId;
/**
* 附件地址
*/
private String attachmentUrl;
/**
* 附件名称
*/
private String attachmentName;
/** /**
* 设备材料入库/移交 * 设备材料入库/移交
*/ */

View File

@ -94,6 +94,16 @@ public class MatMaterialReceiveCreateReq implements Serializable {
*/ */
private String licenseCountFileId; private String licenseCountFileId;
private String attachmentId;
/**
* 附件地址
*/
private String attachmentUrl;
/**
* 附件名称
*/
private String attachmentName;
/** /**
* 设备材料入库/移交 * 设备材料入库/移交
*/ */

View File

@ -87,6 +87,10 @@ public class MatMaterialReceiveUpdateReq implements Serializable {
*/ */
private String licenseCountFileId; private String licenseCountFileId;
/**
* 附件id
*/
private String attachmentId;
/** /**
* 设备材料入库/移交 * 设备材料入库/移交
*/ */

View File

@ -134,6 +134,15 @@ public class MatMaterialReceiveVo implements Serializable {
*/ */
private List<SysOssVo> licenseCountFile; private List<SysOssVo> licenseCountFile;
/**
* 附件地址
*/
private String attachmentUrl;
/**
* 附件名称
*/
private String attachmentName;
/** /**
* 设备材料入库/移交 * 设备材料入库/移交
*/ */

View File

@ -241,7 +241,8 @@ public class MatMaterialReceiveServiceImpl extends ServiceImpl<MatMaterialReceiv
req.getLicenseCountFileId(), req.getLicenseCountFileId(),
req.getReportCountFileId(), req.getReportCountFileId(),
req.getTechDocCountFileId(), req.getTechDocCountFileId(),
req.getCertCountFileId()); req.getCertCountFileId(),
req.getAttachmentId());
boolean save = this.save(materialReceive); boolean save = this.save(materialReceive);
if (!save) { if (!save) {
throw new ServiceException("物料接收单新增失败", HttpStatus.ERROR); throw new ServiceException("物料接收单新增失败", HttpStatus.ERROR);
@ -305,7 +306,8 @@ public class MatMaterialReceiveServiceImpl extends ServiceImpl<MatMaterialReceiv
req.getLicenseCountFileId(), req.getLicenseCountFileId(),
req.getReportCountFileId(), req.getReportCountFileId(),
req.getTechDocCountFileId(), req.getTechDocCountFileId(),
req.getCertCountFileId()); req.getCertCountFileId(),
req.getAttachmentId());
boolean update = this.updateById(materialReceive); boolean update = this.updateById(materialReceive);
if (!update) { if (!update) {
throw new ServiceException("物料接收单修改失败", HttpStatus.ERROR); throw new ServiceException("物料接收单修改失败", HttpStatus.ERROR);
@ -482,9 +484,10 @@ public class MatMaterialReceiveServiceImpl extends ServiceImpl<MatMaterialReceiv
* @param reportCountFileId 报表文件id * @param reportCountFileId 报表文件id
* @param techDocCountFileId 技术文档文件id * @param techDocCountFileId 技术文档文件id
* @param certCountFileId 证书文件id * @param certCountFileId 证书文件id
* @param attachmentId
*/ */
private void getFileSize(MatMaterialReceive materialReceive, String licenseCountFileId, private void getFileSize(MatMaterialReceive materialReceive, String licenseCountFileId,
String reportCountFileId, String techDocCountFileId, String certCountFileId) { String reportCountFileId, String techDocCountFileId, String certCountFileId, String attachmentId) {
if (StringUtils.isNotBlank(licenseCountFileId)) { if (StringUtils.isNotBlank(licenseCountFileId)) {
int size = Arrays.stream(licenseCountFileId.split(",")).map(Long::parseLong).toList().size(); int size = Arrays.stream(licenseCountFileId.split(",")).map(Long::parseLong).toList().size();
materialReceive.setLicenseCount(size); materialReceive.setLicenseCount(size);
@ -501,6 +504,11 @@ public class MatMaterialReceiveServiceImpl extends ServiceImpl<MatMaterialReceiv
int size = Arrays.stream(certCountFileId.split(",")).map(Long::parseLong).toList().size(); int size = Arrays.stream(certCountFileId.split(",")).map(Long::parseLong).toList().size();
materialReceive.setCertCount(size); materialReceive.setCertCount(size);
} }
if (StringUtils.isNotBlank(attachmentId)) {
SysOssVo ossVo = ossService.getById(Long.valueOf(attachmentId));
materialReceive.setAttachmentUrl(ossVo.getUrl());
materialReceive.setAttachmentName(ossVo.getOriginalName());
}
} }
/** /**

View File

@ -4,6 +4,8 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data; import lombok.Data;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.other.domain.OthYs7Device; import org.dromara.other.domain.OthYs7Device;
import java.io.Serial; import java.io.Serial;
@ -40,6 +42,7 @@ public class OthYs7DeviceVo implements Serializable {
/** /**
* 项目名称 * 项目名称
*/ */
@Translation(type = TransConstant.PROJECT_ID_TO_NAME, mapper = "projectId")
private String projectName; private String projectName;
/** /**

View File

@ -262,11 +262,6 @@ public class OthYs7DeviceServiceImpl extends ServiceImpl<OthYs7DeviceMapper, Oth
return ys7DeviceVo; return ys7DeviceVo;
} }
BeanUtils.copyProperties(ys7Device, ys7DeviceVo); BeanUtils.copyProperties(ys7Device, ys7DeviceVo);
Long projectId = ys7Device.getProjectId();
if (projectId != null && !projectId.equals(0L)) {
BusProject project = projectService.getById(projectId);
ys7DeviceVo.setProjectName(project.getProjectName());
}
return ys7DeviceVo; return ys7DeviceVo;
} }
@ -315,22 +310,10 @@ public class OthYs7DeviceServiceImpl extends ServiceImpl<OthYs7DeviceMapper, Oth
if (CollUtil.isEmpty(ys7DeviceList)) { if (CollUtil.isEmpty(ys7DeviceList)) {
return ys7DeviceVoPage; return ys7DeviceVoPage;
} }
// 获取项目列表
Set<Long> projectIdList = ys7DeviceList.stream().map(OthYs7Device::getProjectId).collect(Collectors.toSet());
List<BusProject> projectList = projectService.lambdaQuery()
.select(BusProject::getId, BusProject::getProjectName)
.in(BusProject::getId, projectIdList)
.list();
Map<Long, BusProject> projectMap = projectList.stream().collect(Collectors.toMap(BusProject::getId, project -> project));
// 对象列表 => 封装对象列表 // 对象列表 => 封装对象列表
List<OthYs7DeviceVo> ys7DeviceVoList = ys7DeviceList.stream().map(ys7Device -> { List<OthYs7DeviceVo> ys7DeviceVoList = ys7DeviceList.stream().map(ys7Device -> {
OthYs7DeviceVo ys7DeviceVo = new OthYs7DeviceVo(); OthYs7DeviceVo ys7DeviceVo = new OthYs7DeviceVo();
BeanUtils.copyProperties(ys7Device, ys7DeviceVo); BeanUtils.copyProperties(ys7Device, ys7DeviceVo);
Long projectId = ys7Device.getProjectId();
if (projectId != null && !projectId.equals(0L)) {
BusProject project = projectMap.get(projectId);
ys7DeviceVo.setProjectName(project.getProjectName());
}
return ys7DeviceVo; return ys7DeviceVo;
}).toList(); }).toList();
ys7DeviceVoPage.setRecords(ys7DeviceVoList); ys7DeviceVoPage.setRecords(ys7DeviceVoList);

View File

@ -19,10 +19,7 @@ import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType; import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.web.core.BaseController; import org.dromara.common.web.core.BaseController;
import org.dromara.progress.domain.PgsProgressCategory; import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreatePriceReq; import org.dromara.progress.domain.dto.progresscategory.*;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreateReq;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryQueryReq;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryUpdateReq;
import org.dromara.progress.domain.vo.progresscategory.*; import org.dromara.progress.domain.vo.progresscategory.*;
import org.dromara.progress.service.IPgsProgressCategoryService; import org.dromara.progress.service.IPgsProgressCategoryService;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -65,10 +62,9 @@ public class PgsProgressCategoryController extends BaseController {
* 根据进度父级查询进度类别列表 * 根据进度父级查询进度类别列表
*/ */
@SaCheckPermission("progress:progressCategory:listByParent") @SaCheckPermission("progress:progressCategory:listByParent")
@GetMapping("/listByParent/{parentId}") @GetMapping("/listByParent")
public R<List<PgsProgressCategoryVo>> listByParent(@NotNull(message = "项目id不能为空") public R<List<PgsProgressCategoryVo>> listByParent(PgsProgressCategoryQueryByParentReq req) {
@PathVariable Long parentId) { List<PgsProgressCategoryVo> list = pgsProgressCategoryService.queryListByParent(req);
List<PgsProgressCategoryVo> list = pgsProgressCategoryService.queryListByParent(parentId);
return R.ok(list); return R.ok(list);
} }

View File

@ -14,6 +14,7 @@ import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController; import org.dromara.common.web.core.BaseController;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateCreateReq; import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateCreateReq;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryByParentReq;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryReq; import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryReq;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateUpdateReq; import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateUpdateReq;
import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo; import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo;
@ -60,10 +61,9 @@ public class PgsProgressCategoryTemplateController extends BaseController {
* 根据进度父级查询进度类别模版列表 * 根据进度父级查询进度类别模版列表
*/ */
@SaCheckPermission("progress:progressCategoryTemplate:listByParent") @SaCheckPermission("progress:progressCategoryTemplate:listByParent")
@GetMapping("/listByParent/{parentId}") @GetMapping("/listByParent")
public R<List<PgsProgressCategoryTemplateVo>> listByParent(@NotNull(message = "父级类别主键不能为空") public R<List<PgsProgressCategoryTemplateVo>> listByParent(PgsProgressCategoryTemplateQueryByParentReq req) {
@PathVariable Long parentId) { List<PgsProgressCategoryTemplateVo> list = pgsProgressCategoryTemplateService.queryListByParent(req);
List<PgsProgressCategoryTemplateVo> list = pgsProgressCategoryTemplateService.queryListByParent(parentId);
return R.ok(list); return R.ok(list);
} }

View File

@ -6,7 +6,6 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log; import org.dromara.common.log.annotation.Log;
@ -76,20 +75,20 @@ public class PgsProgressPlanController extends BaseController {
@Log(title = "进度计划", businessType = BusinessType.INSERT) @Log(title = "进度计划", businessType = BusinessType.INSERT)
@RepeatSubmit() @RepeatSubmit()
@PostMapping() @PostMapping()
public R<Long> add(@Validated(AddGroup.class) @RequestBody PgsProgressPlanCreateReq req) { public R<Long> add(@Validated @RequestBody PgsProgressPlanCreateReq req) {
return R.ok(pgsProgressPlanService.insertByBo(req)); return R.ok(pgsProgressPlanService.insertByBo(req));
} }
/** /**
* 删除进度计划 * 删除进度计划
* *
* @param id 主键 * @param ids 主键
*/ */
@SaCheckPermission("progress:progressPlan:remove") @SaCheckPermission("progress:progressPlan:remove")
@Log(title = "进度计划", businessType = BusinessType.DELETE) @Log(title = "进度计划", businessType = BusinessType.DELETE)
@DeleteMapping("/{id}") @DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long id) { @PathVariable Long[] ids) {
return toAjax(pgsProgressPlanService.deleteById(id)); return toAjax(pgsProgressPlanService.deleteByIds(List.of(ids)));
} }
} }

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

View File

@ -4,7 +4,10 @@ import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryQueryByParentReq;
import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryLastTimeVo;
import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryTopVo; import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryTopVo;
import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryVo;
import org.dromara.progress.service.IPgsProgressCategoryService; import org.dromara.progress.service.IPgsProgressCategoryService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -12,6 +15,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
/** /**
@ -39,4 +43,35 @@ public class PgsProgressCategoryAppController {
return R.ok(list); return R.ok(list);
} }
/**
* 根据进度父级查询进度类别列表
*/
@GetMapping("/listByParent")
public R<List<PgsProgressCategoryVo>> listByParent(PgsProgressCategoryQueryByParentReq req) {
List<PgsProgressCategoryVo> list = progressCategoryService.queryListByParent(req);
return R.ok(list);
}
/**
* 获取进度类别最后一次进度信息
*
* @param id 主键
*/
@GetMapping("/lastTime/{id}")
public R<PgsProgressCategoryLastTimeVo> getLastTimeInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(progressCategoryService.queryLastTimeById(id));
}
/**
* 获取进度类别未完成数量
*
* @param id 主键
*/
@GetMapping("/unfinishNumber/{id}")
public R<BigDecimal> getUnFinishNumber(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(progressCategoryService.getUnFinishNumber(id));
}
} }

View File

@ -1,9 +1,23 @@
package org.dromara.progress.controller.app; package org.dromara.progress.controller.app;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
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.common.web.core.BaseController;
import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanCreateReq;
import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanQueryReq;
import org.dromara.progress.domain.dto.progressplan.PgsProgressPlanRemoveReq;
import org.dromara.progress.domain.vo.progressplan.PgsProgressPlanVo;
import org.dromara.progress.service.IPgsProgressPlanService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/** /**
* 进度计划 app 接口 * 进度计划 app 接口
@ -15,4 +29,47 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("/app/progress/progressPlan") @RequestMapping("/app/progress/progressPlan")
public class PgsProgressPlanAppController extends BaseController { public class PgsProgressPlanAppController extends BaseController {
@Resource
private IPgsProgressPlanService progressPlanService;
/**
* 查询进度计划列表
*/
@GetMapping("/list")
public TableDataInfo<PgsProgressPlanVo> list(PgsProgressPlanQueryReq req, PageQuery pageQuery) {
return progressPlanService.queryPageList(req, pageQuery);
}
/**
* 获取进度计划详细信息
*
* @param id 主键
*/
@GetMapping("/{id}")
public R<PgsProgressPlanVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(progressPlanService.queryById(id));
}
/**
* 新增进度计划
*/
@Log(title = "进度计划", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Long> add(@Validated @RequestBody PgsProgressPlanCreateReq req) {
return R.ok(progressPlanService.insertByBo(req));
}
/**
* 删除进度计划
*/
@Log(title = "进度计划", businessType = BusinessType.DELETE)
@PostMapping("/remove")
public R<Void> remove(@Validated @RequestBody PgsProgressPlanRemoveReq req) {
List<Long> ids = req.getIds();
return toAjax(progressPlanService.deleteByIds(ids));
}
} }

View File

@ -1,9 +1,24 @@
package org.dromara.progress.controller.app; package org.dromara.progress.controller.app;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R;
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.common.web.core.BaseController;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailQueryReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNumVo;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailUnFinishVo;
import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/** /**
* 进度计划详情 app 接口 * 进度计划详情 app 接口
@ -15,4 +30,67 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("/app/progress/progressPlanDetail") @RequestMapping("/app/progress/progressPlanDetail")
public class PgsProgressPlanDetailAppController extends BaseController { public class PgsProgressPlanDetailAppController extends BaseController {
@Resource
private IPgsProgressPlanDetailService progressPlanDetailService;
/**
* 查询进度计划详情列表
*/
@GetMapping("/list")
public R<List<PgsProgressPlanDetailNumVo>> list(PgsProgressPlanDetailQueryReq req) {
return R.ok(progressPlanDetailService.queryNumberList(req));
}
/**
* 新增进度计划详情(普通设施)
*/
@RepeatSubmit()
@PostMapping("/insert/detail")
public R<Void> insertFinishedDetail(@Validated @RequestBody PgsProgressPlanDetailFinishedCreateReq req) {
return toAjax(progressPlanDetailService.insertFinishedDetail(req));
}
/**
* 新增进度计划详情(百分比、数量设施)
*/
@RepeatSubmit()
@PostMapping("/insert")
public R<Void> insertDetail(@Validated @RequestBody PgsProgressPlanDetailCreateReq req) {
return toAjax(progressPlanDetailService.insertPercentageNumberDetail(req));
}
/**
* 获取进度计划详情已完成设施详细信息
*
* @param id 主键
*/
@GetMapping("/detail/finished/{id}")
public TableDataInfo<PgsProgressPlanDetailFinishedVo> getFinishedDetail(@NotNull(message = "主键不能为空")
@PathVariable Long id,
PageQuery pageQuery) {
return progressPlanDetailService.queryFinishedById(id, pageQuery);
}
/**
* 获取进度计划详情未完成设施详细信息
*
* @param id 主键
*/
@GetMapping("/detail/unFinish/{id}")
public TableDataInfo<PgsProgressPlanDetailUnFinishVo> getUnFinishDetail(@NotNull(message = "主键不能为空")
@PathVariable Long id,
PageQuery pageQuery) {
return progressPlanDetailService.queryUnFinishById(id, pageQuery);
}
/**
* 删除进度计划详情
*/
@RepeatSubmit()
@DeleteMapping("/remove/detail")
public R<Void> removeDetail(@Validated PgsProgressPlanDetailRemoveReq req) {
return toAjax(progressPlanDetailService.removeDetail(req));
}
} }

View File

@ -8,7 +8,7 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial; import java.io.Serial;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.time.LocalDate;
/** /**
* 进度计划对象 pgs_progress_plan * 进度计划对象 pgs_progress_plan
@ -58,12 +58,12 @@ public class PgsProgressPlan extends BaseEntity {
/** /**
* 计划开始时间 * 计划开始时间
*/ */
private Date startDate; private LocalDate startDate;
/** /**
* 计划结束时间 * 计划结束时间
*/ */
private Date endDate; private LocalDate endDate;
/** /**
* 计划数量/百分比 * 计划数量/百分比

View File

@ -0,0 +1,27 @@
package org.dromara.progress.domain.dto.progresscategory;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @date 2025-09-08 16:14
*/
@Data
public class PgsProgressCategoryQueryByParentReq implements Serializable {
@Serial
private static final long serialVersionUID = 9086069361042762679L;
/**
* 父级id
*/
private Long parentId;
/**
* 类别名称
*/
private String name;
}

View File

@ -0,0 +1,27 @@
package org.dromara.progress.domain.dto.progresscategorytemplate;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lilemy
* @date 2025-09-08 16:21
*/
@Data
public class PgsProgressCategoryTemplateQueryByParentReq implements Serializable {
@Serial
private static final long serialVersionUID = -8113409205840032942L;
/**
* 父类别id
*/
private Long parentId;
/**
* 类别名称
*/
private String name;
}

View File

@ -1,13 +1,13 @@
package org.dromara.progress.domain.dto.progressplan; package org.dromara.progress.domain.dto.progressplan;
import com.fasterxml.jackson.annotation.JsonFormat; import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailCreateDto; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailCreateDto;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.time.LocalDate;
import java.util.List; import java.util.List;
/** /**
@ -23,6 +23,7 @@ public class PgsProgressPlanCreateReq implements Serializable {
/** /**
* 项目id * 项目id
*/ */
@NotNull(message = "项目id不能为空")
private Long projectId; private Long projectId;
/** /**
@ -33,28 +34,31 @@ public class PgsProgressPlanCreateReq implements Serializable {
/** /**
* 进度类型id * 进度类型id
*/ */
@NotNull(message = "进度类型id不能为空")
private Long progressCategoryId; private Long progressCategoryId;
/** /**
* 计划开始时间 * 计划开始时间
*/ */
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") @NotNull(message = "计划开始时间不能为空")
private Date startDate; private LocalDate startDate;
/** /**
* 计划结束时间 * 计划结束时间
*/ */
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") @NotNull(message = "计划结束时间不能为空")
private Date endDate; private LocalDate endDate;
/** /**
* 计划数量/百分比 * 计划数量/百分比
*/ */
@NotNull(message = "计划数量/百分比不能为空")
private BigDecimal planNumber; private BigDecimal planNumber;
/** /**
* 计划详情列表 * 计划详情列表
*/ */
@NotNull(message = "计划详情列表不能为空")
List<PgsProgressPlanDetailCreateDto> detailList; List<PgsProgressPlanDetailCreateDto> detailList;
} }

View File

@ -1,11 +1,10 @@
package org.dromara.progress.domain.dto.progressplan; package org.dromara.progress.domain.dto.progressplan;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data; import lombok.Data;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.time.LocalDate;
/** /**
* @author lilemy * @author lilemy
@ -35,13 +34,11 @@ public class PgsProgressPlanQueryReq implements Serializable {
/** /**
* 计划开始时间 * 计划开始时间
*/ */
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") private LocalDate startDate;
private Date startDate;
/** /**
* 计划结束时间 * 计划结束时间
*/ */
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") private LocalDate endDate;
private Date endDate;
} }

View File

@ -0,0 +1,25 @@
package org.dromara.progress.domain.dto.progressplan;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author lilemy
* @date 2025-09-10 17:28
*/
@Data
public class PgsProgressPlanRemoveReq implements Serializable {
@Serial
private static final long serialVersionUID = -4690448781757278592L;
/**
* 主键串
*/
@NotNull(message = "主键不能为空")
private List<Long> ids;
}

View File

@ -11,7 +11,7 @@ import java.math.BigDecimal;
* @date 2025/5/28 16:06 * @date 2025/5/28 16:06
*/ */
@Data @Data
public class PgsProgressPlanDetailPercentageCreateReq implements Serializable { public class PgsProgressPlanDetailCreateReq implements Serializable {
@Serial @Serial
private static final long serialVersionUID = -2987044313320050949L; private static final long serialVersionUID = -2987044313320050949L;

View File

@ -1,12 +1,11 @@
package org.dromara.progress.domain.vo.progresscategory; package org.dromara.progress.domain.vo.progresscategory;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data; import lombok.Data;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.time.LocalDate;
/** /**
* @author lilemy * @author lilemy
@ -21,8 +20,7 @@ public class PgsProgressCategoryLastTimeVo implements Serializable {
/** /**
* 计划结束时间 * 计划结束时间
*/ */
@JsonFormat(pattern = "yyyy-MM-dd") private LocalDate endDate;
private Date endDate;
/** /**
* 剩余数量 * 剩余数量

View File

@ -15,5 +15,19 @@ public class PgsProgressCategorySecondVo implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 5297363236416903392L; private static final long serialVersionUID = 5297363236416903392L;
/**
* 关联结构(1子项目 2方阵)
*/
private String relevancyStructure;
/**
* 主键id
*/
private Long id;
/**
* 类别名称
*/
private String name;
} }

View File

@ -2,7 +2,6 @@ package org.dromara.progress.domain.vo.progressplan;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data; import lombok.Data;
import org.dromara.progress.domain.PgsProgressPlan; import org.dromara.progress.domain.PgsProgressPlan;
@ -11,7 +10,7 @@ import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailNu
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.time.LocalDate;
import java.util.List; import java.util.List;
@ -35,6 +34,21 @@ public class PgsProgressPlanVo implements Serializable {
@ExcelProperty(value = "主键id") @ExcelProperty(value = "主键id")
private Long id; private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 方阵id
*/
private Long matrixId;
/**
* 方阵名称
*/
private String matrixName;
/** /**
* 进度类型id * 进度类型id
*/ */
@ -50,16 +64,14 @@ public class PgsProgressPlanVo implements Serializable {
/** /**
* 计划开始时间 * 计划开始时间
*/ */
@JsonFormat(pattern = "yyyy-MM-dd")
@ExcelProperty(value = "计划开始时间") @ExcelProperty(value = "计划开始时间")
private Date startDate; private LocalDate startDate;
/** /**
* 计划结束时间 * 计划结束时间
*/ */
@JsonFormat(pattern = "yyyy-MM-dd")
@ExcelProperty(value = "计划结束时间") @ExcelProperty(value = "计划结束时间")
private Date endDate; private LocalDate endDate;
/** /**
* 计划数量/百分比 * 计划数量/百分比
@ -84,6 +96,21 @@ public class PgsProgressPlanVo implements Serializable {
*/ */
private BigDecimal aiFill; private BigDecimal aiFill;
/**
* 计量方式0无 1数量 2百分比
*/
private String unitType;
/**
* 工作类型
*/
private String workType;
/**
* 关联结构(1子项目 2方阵)
*/
private String relevancyStructure;
/** /**
* 进度计划详情 * 进度计划详情
*/ */

View File

@ -41,4 +41,19 @@ public class PgsProgressPlanDetailNumVo {
*/ */
private BigDecimal aiFill; private BigDecimal aiFill;
/**
* 计量方式0无 1数量 2百分比
*/
private String unitType;
/**
* 工作类型
*/
private String workType;
/**
* 关联结构(1子项目 2方阵)
*/
private String relevancyStructure;
} }

View File

@ -4,10 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.facility.domain.FacMatrix; import org.dromara.facility.domain.FacMatrix;
import org.dromara.progress.domain.PgsProgressCategory; import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreatePriceReq; import org.dromara.progress.domain.dto.progresscategory.*;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreateReq;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryQueryReq;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryUpdateReq;
import org.dromara.progress.domain.vo.progresscategory.*; import org.dromara.progress.domain.vo.progresscategory.*;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -42,10 +39,10 @@ public interface IPgsProgressCategoryService extends IService<PgsProgressCategor
/** /**
* 根据进度父级id查询符合条件的进度类别列表 * 根据进度父级id查询符合条件的进度类别列表
* *
* @param parentId 父级id * @param req 查询条件
* @return 进度类别列表 * @return 进度类别列表
*/ */
List<PgsProgressCategoryVo> queryListByParent(Long parentId); List<PgsProgressCategoryVo> queryListByParent(PgsProgressCategoryQueryByParentReq req);
/** /**
* 查询设施剩余数量 * 查询设施剩余数量
@ -176,6 +173,14 @@ public interface IPgsProgressCategoryService extends IService<PgsProgressCategor
*/ */
List<PgsProgressCategory> getLeafNodesByTopIds(List<Long> topIds); List<PgsProgressCategory> getLeafNodesByTopIds(List<Long> topIds);
/**
* 获取子节点支持多个顶级id
*
* @param topIds 顶级节点id集合
* @return 子节点
*/
List<PgsProgressCategory> getChildrenNodeByTopIds(List<Long> topIds);
/** /**
* 获取项目进度百分比 * 获取项目进度百分比
* *
@ -183,4 +188,12 @@ public interface IPgsProgressCategoryService extends IService<PgsProgressCategor
* @return 项目进度百分比 * @return 项目进度百分比
*/ */
BigDecimal getCompletedPercentage(List<PgsProgressCategory> categoryList); BigDecimal getCompletedPercentage(List<PgsProgressCategory> categoryList);
/**
* 获取项目进度类别未完成数量
*
* @param id 主键
* @return 未完成数量
*/
BigDecimal getUnFinishNumber(Long id);
} }

View File

@ -7,6 +7,7 @@ import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.progress.domain.PgsProgressCategoryTemplate; import org.dromara.progress.domain.PgsProgressCategoryTemplate;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateCreateReq; import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateCreateReq;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryByParentReq;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryReq; import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryReq;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateUpdateReq; import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateUpdateReq;
import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo; import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo;
@ -50,10 +51,10 @@ public interface IPgsProgressCategoryTemplateService extends IService<PgsProgres
/** /**
* 根据父级id获取进度类别模版列表 * 根据父级id获取进度类别模版列表
* *
* @param parentId 父级id * @param req 查询条件
* @return 类别模版列表 * @return 类别模版列表
*/ */
List<PgsProgressCategoryTemplateVo> queryListByParent(Long parentId); List<PgsProgressCategoryTemplateVo> queryListByParent(PgsProgressCategoryTemplateQueryByParentReq req);
/** /**
* 新增进度类别模版 * 新增进度类别模版

View File

@ -7,7 +7,7 @@ import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.progress.domain.PgsProgressPlanDetail; import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailPercentageCreateReq; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailQueryReq; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailQueryReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq;
import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo; import org.dromara.progress.domain.vo.progressplandetail.PgsProgressPlanDetailFinishedVo;
@ -49,7 +49,15 @@ public interface IPgsProgressPlanDetailService extends IService<PgsProgressPlanD
* @param req 插入进度计划详情设施参数 * @param req 插入进度计划详情设施参数
* @return 是否插入成功 * @return 是否插入成功
*/ */
Boolean insertPercentageDetail(PgsProgressPlanDetailPercentageCreateReq req); Boolean insertPercentageNumberDetail(PgsProgressPlanDetailCreateReq req);
/**
* 插入进度计划详情设施
*
* @param req 插入进度计划详情设施参数
* @return 是否插入成功
*/
// Boolean insertNumberDetail(PgsProgressPlanDetailNumberCreateReq req);
/** /**
* 分页查询进度计划详情已完成设施列表 * 分页查询进度计划详情已完成设施列表
@ -123,4 +131,11 @@ public interface IPgsProgressPlanDetailService extends IService<PgsProgressPlanD
*/ */
Boolean syncPlanDetail2ConstructionValue(LocalDate localDate, Long projectId); Boolean syncPlanDetail2ConstructionValue(LocalDate localDate, Long projectId);
/**
* 查询计划详情设施数量
*
* @param req 查询条件
* @return 计划详情设施数量
*/
List<PgsProgressPlanDetailNumVo> queryNumberList(PgsProgressPlanDetailQueryReq req);
} }

View File

@ -58,10 +58,10 @@ public interface IPgsProgressPlanService extends IService<PgsProgressPlan> {
/** /**
* 删除进度计划信息 * 删除进度计划信息
* *
* @param id 待删除的主键 * @param ids 待删除的主键
* @return 是否删除成功 * @return 是否删除成功
*/ */
Boolean deleteById(Long id); Boolean deleteByIds(List<Long> ids);
/** /**
* 获取进度计划视图对象 * 获取进度计划视图对象

View File

@ -12,7 +12,6 @@ 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.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.ObjectUtils; import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.utils.BigDecimalUtil; import org.dromara.common.utils.BigDecimalUtil;
@ -24,10 +23,7 @@ import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.PgsProgressCategoryTemplate; import org.dromara.progress.domain.PgsProgressCategoryTemplate;
import org.dromara.progress.domain.PgsProgressPlan; import org.dromara.progress.domain.PgsProgressPlan;
import org.dromara.progress.domain.PgsProgressPlanDetail; import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreatePriceReq; import org.dromara.progress.domain.dto.progresscategory.*;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreateReq;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryQueryReq;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryUpdateReq;
import org.dromara.progress.domain.enums.PgsCoordinateTypeEnum; import org.dromara.progress.domain.enums.PgsCoordinateTypeEnum;
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;
@ -51,6 +47,7 @@ import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -139,13 +136,16 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
/** /**
* 根据进度父级id查询符合条件的进度类别列表 * 根据进度父级id查询符合条件的进度类别列表
* *
* @param parentId 父级id * @param req 查询条件
* @return 进度类别列表 * @return 进度类别列表
*/ */
@Override @Override
public List<PgsProgressCategoryVo> queryListByParent(Long parentId) { public List<PgsProgressCategoryVo> queryListByParent(PgsProgressCategoryQueryByParentReq req) {
Long parentId = req.getParentId();
String name = req.getName();
QueryWrapper<PgsProgressCategory> queryWrapper = new QueryWrapper<>(); QueryWrapper<PgsProgressCategory> queryWrapper = new QueryWrapper<>();
queryWrapper.apply("FIND_IN_SET({0}, ancestors)", parentId); queryWrapper.apply(parentId != null, "FIND_IN_SET({0}, ancestors)", parentId);
queryWrapper.like(StringUtils.isNotBlank(name), "name", name);
return this.getVoList(this.list(queryWrapper)); return this.getVoList(this.list(queryWrapper));
} }
@ -174,15 +174,14 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
.orderByDesc(PgsProgressPlan::getEndDate) .orderByDesc(PgsProgressPlan::getEndDate)
.last("limit 1") .last("limit 1")
.one(); .one();
LocalDate now = LocalDate.now(); /* LocalDate now = LocalDate.now();
Date date = DateUtils.toDate(now); if (progressPlan != null && progressPlan.getEndDate().isAfter(now)) {
if (progressPlan != null && progressPlan.getEndDate().after(date)) {
lastTimeVo.setEndDate(progressPlan.getEndDate()); lastTimeVo.setEndDate(progressPlan.getEndDate());
} else { } else {
LocalDate yesterday = now.minusDays(1); LocalDate yesterday = now.minusDays(1);
Date y = DateUtils.toDate(yesterday); lastTimeVo.setEndDate(yesterday);
lastTimeVo.setEndDate(y); }*/
} lastTimeVo.setEndDate(LocalDate.of(2024, 1, 1));
return lastTimeVo; return lastTimeVo;
} }
@ -190,77 +189,153 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
* 根据子项目id获取顶级进度类别模版 * 根据子项目id获取顶级进度类别模版
* *
* @param subProjectId 子项目id * @param subProjectId 子项目id
* @return 顶级进度类别模版 * @return 顶级进度类别模版列表
*/ */
@Override @Override
public List<PgsProgressCategoryTopVo> getTopListByProjectId(Long subProjectId) { public List<PgsProgressCategoryTopVo> getTopListByProjectId(Long subProjectId) {
// 查询该子项目下的顶级进度类别父ID为0
List<PgsProgressCategory> list = this.lambdaQuery() List<PgsProgressCategory> list = this.lambdaQuery()
.eq(PgsProgressCategory::getProjectId, subProjectId) .eq(PgsProgressCategory::getProjectId, subProjectId)
.eq(PgsProgressCategory::getParentId, PgsProgressCategoryConstant.TOP_PARENT_ID) .eq(PgsProgressCategory::getParentId, PgsProgressCategoryConstant.TOP_PARENT_ID)
.list(); .list();
// 如果没有查询到顶级进度类别,直接返回空集合
if (CollUtil.isEmpty(list)) { if (CollUtil.isEmpty(list)) {
return List.of(); return List.of();
} }
List<PgsProgressCategoryTopVo> topList = new ArrayList<>(); List<PgsProgressCategoryTopVo> topList = new ArrayList<>();
// 获取关联子项的数据 // 获取这些顶级类别的所有子节点
List<Long> ids = list.stream().map(PgsProgressCategory::getId).distinct().toList();
List<PgsProgressCategory> childrenNodes = this.getChildrenNodeByTopIds(ids);
// ============================= 处理关联子项目的数据 =============================
// 筛选出关联子项目的顶级类别
List<PgsProgressCategory> subList = list.stream() List<PgsProgressCategory> subList = list.stream()
.filter(category -> .filter(category ->
category.getRelevancyStructure().equals(PgsRelevancyStructureEnum.SUB_PROJECT.getValue())) category.getRelevancyStructure().equals(PgsRelevancyStructureEnum.SUB_PROJECT.getValue()))
.toList(); .toList();
if (CollUtil.isNotEmpty(subList)) { if (CollUtil.isNotEmpty(subList)) {
List<Long> topIds = subList.stream().map(PgsProgressCategory::getId).distinct().toList(); // 将子项目类别转换为VO对象
List<PgsProgressCategory> leafNodesByTopIds = this.getLeafNodesByTopIds(topIds);
List<PgsProgressCategoryTopVo> subVoList = subList.stream().map(category -> { List<PgsProgressCategoryTopVo> subVoList = subList.stream().map(category -> {
PgsProgressCategoryTopVo vo = new PgsProgressCategoryTopVo(); PgsProgressCategoryTopVo topVo = new PgsProgressCategoryTopVo();
BeanUtils.copyProperties(category, vo); // 属性拷贝
List<PgsProgressCategory> children = leafNodesByTopIds.stream() BeanUtils.copyProperties(category, topVo);
// 统计深度
AtomicInteger count = new AtomicInteger(1);
// 找出当前类别对应的所有叶子节点(根据 ancestors 字段包含关系)
List<PgsProgressCategory> children = childrenNodes.stream()
.filter(node -> { .filter(node -> {
Set<Long> ancestorSet = Arrays.stream(node.getAncestors().split(",")).map(Long::parseLong).collect(Collectors.toSet()); Set<Long> ancestorSet = Arrays.stream(node.getAncestors().split(","))
return ancestorSet.contains(category.getId()); .map(Long::parseLong)
}) .collect(Collectors.toSet());
.toList(); boolean result = ancestorSet.contains(category.getId());
if (result) {
count.set(Math.max(ancestorSet.size(), count.get()));
}
return result;
}).toList();
// 如果有子级,统计总进度和状态;否则初始化为未完成
if (CollUtil.isNotEmpty(children)) { if (CollUtil.isNotEmpty(children)) {
vo.setProgressTotal(this.getCompletedPercentage(children)); topVo.setProgressTotal(this.getCompletedPercentage(children));
vo.setStatus(this.getParentStatus(children)); topVo.setStatus(this.getParentStatus(children));
if (count.get() == 2) {
topVo.setType("1");
} else if (count.get() == 3) {
topVo.setType("2");
List<PgsProgressCategorySecondVo> second = children.stream()
.filter(node -> {
Set<Long> ancestorSet = Arrays.stream(node.getAncestors().split(","))
.map(Long::parseLong)
.collect(Collectors.toSet());
return ancestorSet.size() == 2;
}).map(node -> {
PgsProgressCategorySecondVo vo = new PgsProgressCategorySecondVo();
BeanUtils.copyProperties(node, vo);
return vo;
})
.toList();
topVo.setCategorySecondList(second);
}
} else { } else {
vo.setProgressTotal(BigDecimal.ZERO); topVo.setProgressTotal(BigDecimal.ZERO);
topVo.setStatus(PgsFinishStatusEnum.UNFINISH.getValue());
topVo.setType("1");
} }
return vo; return topVo;
}).toList(); }).toList();
// 将处理好的子项目VO加入结果集
topList.addAll(subVoList); topList.addAll(subVoList);
} }
// 获取关联方阵数据 // ============================= 处理关联方阵数据 =============================
// 筛选出关联方阵的顶级类别
List<PgsProgressCategory> matrixList = list.stream() List<PgsProgressCategory> matrixList = list.stream()
.filter(category -> .filter(category ->
category.getRelevancyStructure().equals(PgsRelevancyStructureEnum.MATRIX.getValue())) category.getRelevancyStructure().equals(PgsRelevancyStructureEnum.MATRIX.getValue()))
.toList(); .toList();
if (CollUtil.isNotEmpty(matrixList)) { if (CollUtil.isNotEmpty(matrixList)) {
// 按名称分组(同名的放在一起)
Map<String, List<PgsProgressCategory>> matrixMap = matrixList.stream() Map<String, List<PgsProgressCategory>> matrixMap = matrixList.stream()
.collect(Collectors.groupingBy(PgsProgressCategory::getName)); .collect(Collectors.groupingBy(PgsProgressCategory::getName));
for (Map.Entry<String, List<PgsProgressCategory>> entry : matrixMap.entrySet()) { for (Map.Entry<String, List<PgsProgressCategory>> entry : matrixMap.entrySet()) {
PgsProgressCategoryTopVo topVo = new PgsProgressCategoryTopVo(); PgsProgressCategoryTopVo topVo = new PgsProgressCategoryTopVo();
topVo.setName(entry.getKey()); topVo.setName(entry.getKey());
topVo.setRelevancyStructure(PgsRelevancyStructureEnum.MATRIX.getValue()); topVo.setRelevancyStructure(PgsRelevancyStructureEnum.MATRIX.getValue());
// 取分组中的第一条记录的排序字段作为当前VO的排序值
List<PgsProgressCategory> value = entry.getValue(); List<PgsProgressCategory> value = entry.getValue();
topVo.setSort(value.getFirst().getSort()); topVo.setSort(value.getFirst().getSort());
// 转换为方阵结构的VO列表
List<PgsProgressCategoryMatrixStructureTopVo> matrixVoList = value.stream().map(category -> { List<PgsProgressCategoryMatrixStructureTopVo> matrixVoList = value.stream().map(category -> {
PgsProgressCategoryMatrixStructureTopVo vo = new PgsProgressCategoryMatrixStructureTopVo(); PgsProgressCategoryMatrixStructureTopVo vo = new PgsProgressCategoryMatrixStructureTopVo();
BeanUtils.copyProperties(category, vo); BeanUtils.copyProperties(category, vo);
return vo; return vo;
}).toList(); }).toList();
topVo.setMatrixStructureList(matrixVoList); topVo.setMatrixStructureList(matrixVoList);
// 获取所有子级,并进行统计 // 统计深度
AtomicInteger count = new AtomicInteger(1);
// 获取这些类别下的所有叶子节点
List<Long> topIds = value.stream().map(PgsProgressCategory::getId).distinct().toList(); List<Long> topIds = value.stream().map(PgsProgressCategory::getId).distinct().toList();
List<PgsProgressCategory> leafNodesByTopIds = this.getLeafNodesByTopIds(topIds); List<PgsProgressCategory> leafNodesByTopIds = childrenNodes.stream()
.filter(node -> {
Set<Long> ancestorSet = Arrays.stream(node.getAncestors().split(","))
.map(Long::parseLong)
.collect(Collectors.toSet());
boolean result = topIds.stream().anyMatch(ancestorSet::contains);
if (result) {
count.set(Math.max(ancestorSet.size(), count.get()));
}
return result;
}).toList();
// 如果有叶子节点,统计进度和状态;否则初始化为未完成
if (CollUtil.isNotEmpty(leafNodesByTopIds)) { if (CollUtil.isNotEmpty(leafNodesByTopIds)) {
topVo.setProgressTotal(this.getCompletedPercentage(leafNodesByTopIds)); topVo.setProgressTotal(this.getCompletedPercentage(leafNodesByTopIds));
topVo.setStatus(this.getParentStatus(leafNodesByTopIds)); topVo.setStatus(this.getParentStatus(leafNodesByTopIds));
if (count.get() == 2) {
topVo.setType("3");
} else if (count.get() == 3) {
topVo.setType("4");
List<PgsProgressCategorySecondVo> second = leafNodesByTopIds.stream()
.filter(node -> {
Set<Long> ancestorSet = Arrays.stream(node.getAncestors().split(","))
.map(Long::parseLong)
.collect(Collectors.toSet());
return ancestorSet.size() == 2;
}).map(node -> {
PgsProgressCategorySecondVo vo = new PgsProgressCategorySecondVo();
BeanUtils.copyProperties(node, vo);
return vo;
})
.toList();
topVo.setCategorySecondList(second);
}
} else { } else {
topVo.setProgressTotal(BigDecimal.ZERO); topVo.setProgressTotal(BigDecimal.ZERO);
topVo.setStatus(PgsFinishStatusEnum.UNFINISH.getValue());
topVo.setType("3");
} }
// 加入结果集
topList.add(topVo); topList.add(topVo);
} }
} }
// ============================= 排序 & 返回结果 =============================
// 按 sort 字段升序排序
topList.sort(Comparator.comparing(PgsProgressCategoryTopVo::getSort)); topList.sort(Comparator.comparing(PgsProgressCategoryTopVo::getSort));
return topList; return topList;
} }
@ -377,8 +452,8 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
} }
BigDecimal ownerPrice = req.getOwnerPrice(); BigDecimal ownerPrice = req.getOwnerPrice();
BigDecimal constructionPrice = req.getConstructionPrice(); BigDecimal constructionPrice = req.getConstructionPrice();
BigDecimal ownerOutputValue = BigDecimal.ZERO; BigDecimal ownerOutputValue;
BigDecimal constructionOutputValue = BigDecimal.ZERO; BigDecimal constructionOutputValue;
if (unitType.equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue()) || if (unitType.equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue()) ||
progressCategory.getUnitType().equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue())) { progressCategory.getUnitType().equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue())) {
progressCategory.setTotal(req.getTotal()); progressCategory.setTotal(req.getTotal());
@ -393,8 +468,7 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
} }
ownerOutputValue = total.multiply(ownerPrice); ownerOutputValue = total.multiply(ownerPrice);
constructionOutputValue = total.multiply(constructionPrice); constructionOutputValue = total.multiply(constructionPrice);
} else if (unitType.equals(PgsProgressUnitTypeEnum.NUMBER.getValue()) || } else {
progressCategory.getUnitType().equals(PgsProgressUnitTypeEnum.NUMBER.getValue())) {
BigDecimal total = req.getTotal(); BigDecimal total = req.getTotal();
if (total == null || total.compareTo(BigDecimal.ZERO) <= 0) { if (total == null || total.compareTo(BigDecimal.ZERO) <= 0) {
total = progressCategory.getTotal(); total = progressCategory.getTotal();
@ -402,6 +476,7 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
if (total == null || total.compareTo(BigDecimal.ZERO) <= 0) { if (total == null || total.compareTo(BigDecimal.ZERO) <= 0) {
throw new ServiceException("请输入分项工程数量", HttpStatus.BAD_REQUEST); throw new ServiceException("请输入分项工程数量", HttpStatus.BAD_REQUEST);
} }
progressCategory.setTotal(total);
ownerOutputValue = total.multiply(ownerPrice); ownerOutputValue = total.multiply(ownerPrice);
constructionOutputValue = total.multiply(constructionPrice); constructionOutputValue = total.multiply(constructionPrice);
} }
@ -1214,12 +1289,32 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
*/ */
@Override @Override
public List<PgsProgressCategory> getLeafNodesByTopIds(List<Long> topIds) { public List<PgsProgressCategory> getLeafNodesByTopIds(List<Long> topIds) {
if (topIds == null || topIds.isEmpty()) { List<PgsProgressCategory> allChildren = this.getChildrenNodeByTopIds(topIds);
if (allChildren.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
// 过滤掉那些还有子节点的,只保留最底层
Set<Long> parentIds = allChildren.stream()
.map(PgsProgressCategory::getParentId)
.collect(Collectors.toSet());
return allChildren.stream()
.filter(item -> !parentIds.contains(item.getId())) // 没有被当作别人父id的就是叶子节点
.toList();
}
// 1. 查出所有属于这些顶级节点的子孙节点 /**
List<PgsProgressCategory> allChildren = this.list( * 获取子节点支持多个顶级id
*
* @param topIds 顶级节点id集合
* @return 子节点
*/
@Override
public List<PgsProgressCategory> getChildrenNodeByTopIds(List<Long> topIds) {
if (CollUtil.isEmpty(topIds)) {
return Collections.emptyList();
}
// 查出所有属于这些顶级节点的子孙节点
return this.list(
Wrappers.<PgsProgressCategory>lambdaQuery() Wrappers.<PgsProgressCategory>lambdaQuery()
.and(wrapper -> { .and(wrapper -> {
for (Long topId : topIds) { for (Long topId : topIds) {
@ -1228,19 +1323,6 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
} }
}) })
); );
if (allChildren.isEmpty()) {
return Collections.emptyList();
}
// 2. 过滤掉那些还有子节点的,只保留最底层
Set<Long> parentIds = allChildren.stream()
.map(PgsProgressCategory::getParentId)
.collect(Collectors.toSet());
return allChildren.stream()
.filter(item -> !parentIds.contains(item.getId())) // 没有被当作别人父id的就是叶子节点
.toList();
} }
/** /**
@ -1266,4 +1348,27 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
return BigDecimalUtil.toPercentage(completedTotal, allTotal); return BigDecimalUtil.toPercentage(completedTotal, allTotal);
} }
/**
* 获取项目进度类别未完成数量
*
* @param id 主键
* @return 未完成数量
*/
@Override
public BigDecimal getUnFinishNumber(Long id) {
PgsProgressCategory category = this.getById(id);
if (category == null) {
return BigDecimal.ZERO;
}
BigDecimal total = category.getTotal();
BigDecimal completed = category.getCompleted();
// 如果是百分比,需要转换为数值
if (PgsProgressUnitTypeEnum.PERCENTAGE.getValue().equals(category.getUnitType())) {
completed = completed
.divide(BigDecimal.valueOf(100L), 2, RoundingMode.HALF_UP)
.multiply(total);
}
return total.subtract(completed);
}
} }

View File

@ -18,6 +18,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.progress.constant.PgsProgressCategoryConstant; import org.dromara.progress.constant.PgsProgressCategoryConstant;
import org.dromara.progress.domain.PgsProgressCategoryTemplate; import org.dromara.progress.domain.PgsProgressCategoryTemplate;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateCreateReq; import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateCreateReq;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryByParentReq;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryReq; import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateQueryReq;
import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateUpdateReq; import org.dromara.progress.domain.dto.progresscategorytemplate.PgsProgressCategoryTemplateUpdateReq;
import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo; import org.dromara.progress.domain.vo.progresscategorytemplate.PgsProgressCategoryTemplateVo;
@ -89,13 +90,16 @@ public class PgsProgressCategoryTemplateServiceImpl extends ServiceImpl<PgsProgr
/** /**
* 根据父级id获取进度类别模版列表 * 根据父级id获取进度类别模版列表
* *
* @param parentId 父级id * @param req 查询条件
* @return 类别模版列表 * @return 类别模版列表
*/ */
@Override @Override
public List<PgsProgressCategoryTemplateVo> queryListByParent(Long parentId) { public List<PgsProgressCategoryTemplateVo> queryListByParent(PgsProgressCategoryTemplateQueryByParentReq req) {
Long parentId = req.getParentId();
String name = req.getName();
QueryWrapper<PgsProgressCategoryTemplate> queryWrapper = new QueryWrapper<>(); QueryWrapper<PgsProgressCategoryTemplate> queryWrapper = new QueryWrapper<>();
queryWrapper.apply("FIND_IN_SET({0}, ancestors)", parentId); queryWrapper.apply(parentId != null, "FIND_IN_SET({0}, ancestors)", parentId);
queryWrapper.like(StringUtils.isNotBlank(name), "name", name);
return this.list(queryWrapper).stream().map(this::getVo).toList(); return this.list(queryWrapper).stream().map(this::getVo).toList();
} }

View File

@ -26,8 +26,8 @@ import org.dromara.progress.constant.PgsProgressCategoryConstant;
import org.dromara.progress.domain.PgsProgressCategory; import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.PgsProgressPlan; import org.dromara.progress.domain.PgsProgressPlan;
import org.dromara.progress.domain.PgsProgressPlanDetail; import org.dromara.progress.domain.PgsProgressPlanDetail;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailCreateReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailFinishedCreateReq; 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.PgsProgressPlanDetailQueryReq;
import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq; import org.dromara.progress.domain.dto.progressplandetail.PgsProgressPlanDetailRemoveReq;
import org.dromara.progress.domain.enums.PgsFinishStatusEnum; import org.dromara.progress.domain.enums.PgsFinishStatusEnum;
@ -133,11 +133,11 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
throw new ServiceException("进度计划信息不存在", HttpStatus.NOT_FOUND); throw new ServiceException("进度计划信息不存在", HttpStatus.NOT_FOUND);
} }
BigDecimal oldFinishedNumber = progressPlan.getFinishedNumber(); BigDecimal oldFinishedNumber = progressPlan.getFinishedNumber();
// todo 判断完成时间是否大于当前时间 // 判断完成时间是否大于当前时间
LocalDate planDate = progressPlanDetail.getDate(); LocalDate planDate = progressPlanDetail.getDate();
/* if (planDate.after(new Date())) { if (planDate.isAfter(LocalDate.now())) {
throw new ServiceException("完成时间不能大于当前时间", HttpStatus.BAD_REQUEST); throw new ServiceException("完成时间不能大于当前时间", HttpStatus.BAD_REQUEST);
}*/ }
Long projectId = progressPlanDetail.getProjectId(); Long projectId = progressPlanDetail.getProjectId();
Long progressCategoryId = progressPlanDetail.getProgressCategoryId(); Long progressCategoryId = progressPlanDetail.getProgressCategoryId();
PgsProgressCategory progressCategory = progressCategoryService.getById(progressCategoryId); PgsProgressCategory progressCategory = progressCategoryService.getById(progressCategoryId);
@ -305,28 +305,25 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Boolean insertPercentageDetail(PgsProgressPlanDetailPercentageCreateReq req) { public Boolean insertPercentageNumberDetail(PgsProgressPlanDetailCreateReq req) {
// 校验 // 校验
BigDecimal finishedNumber = req.getFinishedNumber(); BigDecimal finishedNumber = req.getFinishedNumber();
if (finishedNumber == null) { if (finishedNumber == null) {
throw new ServiceException("完成百分比不能为空", HttpStatus.BAD_REQUEST); throw new ServiceException("完成不能为空", HttpStatus.BAD_REQUEST);
} }
// 判断是否小于 0 // 判断是否小于 0
if (finishedNumber.compareTo(BigDecimal.ZERO) < 0) { if (finishedNumber.compareTo(BigDecimal.ZERO) < 0) {
throw new ServiceException("完成百分比不能小于0", HttpStatus.BAD_REQUEST); throw new ServiceException("完成不能小于0", HttpStatus.BAD_REQUEST);
}
// 判断是否大于 100
if (finishedNumber.compareTo(BigDecimal.valueOf(100)) > 0) {
throw new ServiceException("完成百分比不能大于100", HttpStatus.BAD_REQUEST);
} }
Long id = req.getId(); Long id = req.getId();
PgsProgressPlanDetail progressPlanDetail = this.getById(id); PgsProgressPlanDetail progressPlanDetail = this.getById(id);
if (progressPlanDetail == null) { if (progressPlanDetail == null) {
throw new ServiceException("进度计划详情信息不存在", HttpStatus.NOT_FOUND); throw new ServiceException("进度计划详情信息不存在", HttpStatus.NOT_FOUND);
} }
// 判断总进度不能大于 100 // 判断完成时间是否大于当前时间
if (progressPlanDetail.getFinishedNumber().add(finishedNumber).compareTo(BigDecimal.valueOf(100)) > 0) { LocalDate date = progressPlanDetail.getDate();
throw new ServiceException("总进度不能大于100", HttpStatus.BAD_REQUEST); if (date.isAfter(LocalDate.now())) {
throw new ServiceException("完成时间不能大于当前时间", HttpStatus.BAD_REQUEST);
} }
Long progressPlanId = progressPlanDetail.getProgressPlanId(); Long progressPlanId = progressPlanDetail.getProgressPlanId();
PgsProgressPlan progressPlan = progressPlanService.getById(progressPlanId); PgsProgressPlan progressPlan = progressPlanService.getById(progressPlanId);
@ -338,28 +335,121 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
if (progressCategory == null) { if (progressCategory == null) {
throw new ServiceException("进度计划类别信息不存在", HttpStatus.NOT_FOUND); throw new ServiceException("进度计划类别信息不存在", HttpStatus.NOT_FOUND);
} }
BigDecimal number = progressPlanDetail.getFinishedNumber(); String unitType = progressCategory.getUnitType();
BigDecimal oldFinishedNumberTotal = progressPlan.getFinishedNumber(); // ---------- 数据计算 ----------
BigDecimal oldDetailNumber = progressPlanDetail.getFinishedNumber();
BigDecimal oldPlanFinished = progressPlan.getFinishedNumber();
BigDecimal newPlanFinished = oldPlanFinished.subtract(oldDetailNumber).add(finishedNumber);
// 模式特定校验
if (unitType.equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue()) && newPlanFinished.compareTo(BigDecimal.valueOf(100)) > 0) {
throw new ServiceException("总进度不能大于100", HttpStatus.BAD_REQUEST);
}
// 判断是否大于 100
if (unitType.equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue()) && finishedNumber.compareTo(BigDecimal.valueOf(100)) > 0) {
throw new ServiceException("完成百分比不能大于100", HttpStatus.BAD_REQUEST);
}
// ---------- 更新 detail ----------
progressPlanDetail.setFinishedNumber(finishedNumber);
if (!this.updateById(progressPlanDetail)) {
throw new ServiceException("更新进度计划详情异常", HttpStatus.ERROR);
}
// ---------- 更新 plan ----------
progressPlan.setFinishedNumber(newPlanFinished);
if (!progressPlanService.updateById(progressPlan)) {
throw new ServiceException("更新进度计划异常", HttpStatus.ERROR);
}
// ---------- 更新 category ----------
BigDecimal completed = progressCategory.getCompleted();
BigDecimal completedTotal = completed.subtract(oldDetailNumber).add(finishedNumber);
if (unitType.equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue()) && completedTotal.compareTo(BigDecimal.valueOf(100)) > 0) {
throw new ServiceException("完成百分比不能大于100", HttpStatus.BAD_REQUEST);
}
if (unitType.equals(PgsProgressUnitTypeEnum.NUMBER.getValue()) && completedTotal.compareTo(progressCategory.getTotal()) > 0) {
throw new ServiceException("完成数量不能超过总数量", HttpStatus.BAD_REQUEST);
}
progressCategory.setCompleted(completedTotal);
// 完成判定
if (unitType.equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue())) {
if (completedTotal.compareTo(BigDecimal.valueOf(100)) == 0) {
progressCategory.setStatus(PgsFinishStatusEnum.FINISH.getValue());
}
} else { // NUMBER
if (completedTotal.compareTo(progressCategory.getTotal()) >= 0) {
progressCategory.setStatus(PgsFinishStatusEnum.FINISH.getValue());
}
}
// 判断是否跨过计划数量阈值
if (oldPlanFinished.compareTo(progressPlan.getPlanNumber()) < 0
&& newPlanFinished.compareTo(progressPlan.getPlanNumber()) >= 0) {
progressCategory.setPlanTotal(progressCategory.getPlanTotal().subtract(progressPlan.getPlanNumber()));
}
if (!progressCategoryService.updateById(progressCategory)) {
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); progressPlanDetail.setFinishedNumber(finishedNumber);
// 更新
boolean update = this.updateById(progressPlanDetail); boolean update = this.updateById(progressPlanDetail);
if (!update) { if (!update) {
throw new ServiceException("更新进度计划详情异常", HttpStatus.ERROR); throw new ServiceException("更新进度计划详情异常", HttpStatus.ERROR);
} }
progressPlan.setFinishedNumber(oldFinishedNumberTotal.subtract(number).add(finishedNumber)); // 更新 plan
progressPlan.setFinishedNumber(newFinishedNumberTotal);
boolean result = progressPlanService.updateById(progressPlan); boolean result = progressPlanService.updateById(progressPlan);
if (!result) { if (!result) {
throw new ServiceException("更新进度计划异常", HttpStatus.ERROR); throw new ServiceException("更新进度计划异常", HttpStatus.ERROR);
} }
// 更新 category
BigDecimal completed = progressCategory.getCompleted(); BigDecimal completed = progressCategory.getCompleted();
BigDecimal completedTotal = completed.subtract(number).add(finishedNumber); BigDecimal completedTotal = completed.subtract(number).add(finishedNumber);
progressCategory.setCompleted(completedTotal); progressCategory.setCompleted(completedTotal);
if (progressCategory.getUnitType().equals(PgsProgressUnitTypeEnum.NUMBER.getValue()) // 如果完成数量 >= 总数量,标记为完成
&& completedTotal.compareTo(progressCategory.getTotal()) == 0) { if (completedTotal.compareTo(progressCategory.getTotal()) >= 0) {
progressCategory.setStatus(PgsFinishStatusEnum.FINISH.getValue());
}
if (progressCategory.getUnitType().equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue())
&& completedTotal.compareTo(BigDecimal.valueOf(100)) == 0) {
progressCategory.setStatus(PgsFinishStatusEnum.FINISH.getValue()); progressCategory.setStatus(PgsFinishStatusEnum.FINISH.getValue());
} }
// 判断当前是否已完成计划数量 // 判断当前是否已完成计划数量
@ -373,7 +463,7 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
throw new ServiceException("更新进度分类异常", HttpStatus.ERROR); throw new ServiceException("更新进度分类异常", HttpStatus.ERROR);
} }
return true; return true;
} }*/
/** /**
* 分页查询进度计划详情设施列表 * 分页查询进度计划详情设施列表
@ -522,9 +612,20 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
*/ */
@Override @Override
public List<PgsProgressPlanDetailNumVo> getNumVoList(List<PgsProgressPlanDetail> progressPlanDetailList) { public List<PgsProgressPlanDetailNumVo> getNumVoList(List<PgsProgressPlanDetail> progressPlanDetailList) {
List<Long> categoryIds = progressPlanDetailList.stream()
.map(PgsProgressPlanDetail::getProgressCategoryId).distinct().toList();
List<PgsProgressCategory> categoryList = progressCategoryService.listByIds(categoryIds);
Map<Long, PgsProgressCategory> categoryMap = categoryList.stream()
.collect(Collectors.toMap(PgsProgressCategory::getId, v -> v));
return progressPlanDetailList.stream().map(progressPlanDetail -> { return progressPlanDetailList.stream().map(progressPlanDetail -> {
PgsProgressPlanDetailNumVo progressPlanDetailNumVo = new PgsProgressPlanDetailNumVo(); PgsProgressPlanDetailNumVo progressPlanDetailNumVo = new PgsProgressPlanDetailNumVo();
BeanUtils.copyProperties(progressPlanDetail, progressPlanDetailNumVo); BeanUtils.copyProperties(progressPlanDetail, progressPlanDetailNumVo);
if (categoryMap.containsKey(progressPlanDetail.getProgressCategoryId())) {
PgsProgressCategory category = categoryMap.get(progressPlanDetail.getProgressCategoryId());
progressPlanDetailNumVo.setUnitType(category.getUnitType());
progressPlanDetailNumVo.setWorkType(category.getWorkType());
progressPlanDetailNumVo.setRelevancyStructure(category.getRelevancyStructure());
}
return progressPlanDetailNumVo; return progressPlanDetailNumVo;
}).toList(); }).toList();
} }
@ -724,7 +825,7 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
Long progressPlanId = req.getProgressPlanId(); Long progressPlanId = req.getProgressPlanId();
Long progressCategoryId = req.getProgressCategoryId(); Long progressCategoryId = req.getProgressCategoryId();
lqw.eq(ObjectUtils.isNotEmpty(projectId), PgsProgressPlanDetail::getProjectId, projectId); lqw.eq(ObjectUtils.isNotEmpty(projectId), PgsProgressPlanDetail::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(progressPlanId), PgsProgressPlanDetail::getId, progressPlanId); lqw.eq(ObjectUtils.isNotEmpty(progressPlanId), PgsProgressPlanDetail::getProgressPlanId, progressPlanId);
lqw.eq(ObjectUtils.isNotEmpty(progressCategoryId), PgsProgressPlanDetail::getProgressCategoryId, progressCategoryId); lqw.eq(ObjectUtils.isNotEmpty(progressCategoryId), PgsProgressPlanDetail::getProgressCategoryId, progressCategoryId);
return lqw; return lqw;
} }
@ -839,6 +940,19 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
return true; return true;
} }
/**
* 查询计划详情设施数量
*
* @param req 查询条件
* @return 计划详情设施数量
*/
@Override
public List<PgsProgressPlanDetailNumVo> queryNumberList(PgsProgressPlanDetailQueryReq req) {
LambdaQueryWrapper<PgsProgressPlanDetail> lqw = this.buildQueryWrapper(req);
List<PgsProgressPlanDetail> progressPlanDetailList = this.list(lqw);
return getNumVoList(progressPlanDetailList);
}
/** /**
* 分页 * 分页
* *

View File

@ -11,7 +11,6 @@ import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ObjectUtils; import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.facility.domain.FacMatrix; import org.dromara.facility.domain.FacMatrix;
import org.dromara.facility.service.IFacMatrixService; import org.dromara.facility.service.IFacMatrixService;
import org.dromara.progress.domain.PgsProgressCategory; import org.dromara.progress.domain.PgsProgressCategory;
@ -38,7 +37,6 @@ import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -119,12 +117,16 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
PgsProgressPlan progressPlan = new PgsProgressPlan(); PgsProgressPlan progressPlan = new PgsProgressPlan();
BeanUtils.copyProperties(req, progressPlan); BeanUtils.copyProperties(req, progressPlan);
// 数据校验 // 数据校验
Date startDate = req.getStartDate(); LocalDate startDate = req.getStartDate();
Date endDate = req.getEndDate(); LocalDate endDate = req.getEndDate();
// 结束日期不能早于开始日期 // 结束日期不能早于开始日期
if (endDate.before(startDate)) { if (endDate.isBefore(startDate)) {
throw new ServiceException("结束日期不能早于开始日期"); throw new ServiceException("结束日期不能早于开始日期");
} }
boolean overlap = this.hasOverlap(req.getProgressCategoryId(), startDate, endDate);
if (overlap) {
throw new ServiceException("该进度类型下,时间区间已存在重叠的数据");
}
Long projectId = progressPlan.getProjectId(); Long projectId = progressPlan.getProjectId();
if (projectService.getById(projectId) == null) { if (projectService.getById(projectId) == null) {
throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND); throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND);
@ -137,14 +139,14 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
} }
Long progressCategoryId = progressPlan.getProgressCategoryId(); Long progressCategoryId = progressPlan.getProgressCategoryId();
// 校验日期是否合法 // 校验日期是否合法
PgsProgressPlan lastProgressPlan = this.lambdaQuery() /* PgsProgressPlan lastProgressPlan = this.lambdaQuery()
.eq(PgsProgressPlan::getProgressCategoryId, progressCategoryId) .eq(PgsProgressPlan::getProgressCategoryId, progressCategoryId)
.orderByDesc(PgsProgressPlan::getEndDate) .orderByDesc(PgsProgressPlan::getEndDate)
.last("limit 1") .last("limit 1")
.one(); .one();
if (lastProgressPlan != null && startDate.before(lastProgressPlan.getEndDate())) { if (lastProgressPlan != null && startDate.isBefore(lastProgressPlan.getEndDate())) {
throw new ServiceException("开始日期不能早于上一条进度计划结束日期", HttpStatus.BAD_REQUEST); throw new ServiceException("开始日期不能早于上一条进度计划结束日期", HttpStatus.BAD_REQUEST);
} }*/
PgsProgressCategory progressCategory = progressCategoryService.getById(progressCategoryId); PgsProgressCategory progressCategory = progressCategoryService.getById(progressCategoryId);
this.validPlanNumber(req.getPlanNumber(), progressCategory); this.validPlanNumber(req.getPlanNumber(), progressCategory);
progressPlan.setProgressCategoryName(progressCategory.getName()); progressPlan.setProgressCategoryName(progressCategory.getName());
@ -187,41 +189,40 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
/** /**
* 删除进度计划信息 * 删除进度计划信息
* *
* @param id 待删除的主键 * @param ids 待删除的主键
* @return 是否删除成功 * @return 是否删除成功
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Boolean deleteById(Long id) { public Boolean deleteByIds(List<Long> ids) {
Long userId = LoginHelper.getUserId(); for (Long id : ids) {
PgsProgressPlan progressPlan = this.getById(id); PgsProgressPlan progressPlan = this.getById(id);
if (progressPlan == null) { if (progressPlan == null) {
throw new ServiceException("进度计划信息不存在", HttpStatus.NOT_FOUND); throw new ServiceException("进度计划信息不存在", HttpStatus.NOT_FOUND);
} }
Long projectId = progressPlan.getProjectId(); if (progressPlan.getPlanNumber() != null && progressPlan.getPlanNumber().compareTo(BigDecimal.ZERO) != 0) {
projectService.validAuth(projectId, userId); throw new ServiceException("已存在完成的设施,无法删除", HttpStatus.CONFLICT);
if (progressPlan.getPlanNumber() != null && progressPlan.getPlanNumber().compareTo(BigDecimal.ZERO) != 0) { }
throw new ServiceException("已存在完成的设施,无法删除", HttpStatus.CONFLICT); // 删除数据
} boolean result = this.removeById(id);
// 删除数据 if (!result) {
boolean result = this.removeById(id); throw new ServiceException("删除进度计划失败,数据库异常", HttpStatus.ERROR);
if (!result) { }
throw new ServiceException("删除进度计划失败,数据库异常", HttpStatus.ERROR); // 关联删除分类中记录的计划值
} boolean update = progressCategoryService.lambdaUpdate()
// 关联删除分类中记录的计划值 .eq(PgsProgressCategory::getId, progressPlan.getProgressCategoryId())
boolean update = progressCategoryService.lambdaUpdate() .setSql("plan_total = plan_total - " + progressPlan.getPlanNumber())
.eq(PgsProgressCategory::getId, progressPlan.getProgressCategoryId()) .update();
.setSql("plan_total = plan_total - " + progressPlan.getPlanNumber()) if (!update) {
.update(); throw new ServiceException("更新进度分类计划总数量失败,数据库操作失败", HttpStatus.ERROR);
if (!update) { }
throw new ServiceException("更新进度分类计划总数量失败,数据库操作失败", HttpStatus.ERROR); // 关联删除计划详情数据
} LambdaQueryWrapper<PgsProgressPlanDetail> lqw = new LambdaQueryWrapper<>();
// 关联删除计划详情数据 lqw.eq(PgsProgressPlanDetail::getProgressPlanId, id);
LambdaQueryWrapper<PgsProgressPlanDetail> lqw = new LambdaQueryWrapper<>(); boolean remove = progressPlanDetailService.remove(lqw);
lqw.eq(PgsProgressPlanDetail::getProgressPlanId, id); if (!remove) {
boolean remove = progressPlanDetailService.remove(lqw); throw new ServiceException("删除进度计划详情失败,数据库异常", HttpStatus.ERROR);
if (!remove) { }
throw new ServiceException("删除进度计划详情失败,数据库异常", HttpStatus.ERROR);
} }
return true; return true;
} }
@ -247,6 +248,13 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
.eq(PgsProgressPlanDetail::getProjectId, progressPlan.getProjectId()) .eq(PgsProgressPlanDetail::getProjectId, progressPlan.getProjectId())
.list(); .list();
progressPlanVo.setDetailList(progressPlanDetailService.getNumVoList(detailList)); progressPlanVo.setDetailList(progressPlanDetailService.getNumVoList(detailList));
// 获取进度类别
PgsProgressCategory progressCategory = progressCategoryService.getById(progressPlan.getProgressCategoryId());
if (progressCategory != null) {
progressPlanVo.setUnitType(progressCategory.getUnitType());
progressPlanVo.setWorkType(progressCategory.getWorkType());
progressPlanVo.setRelevancyStructure(progressCategory.getRelevancyStructure());
}
return progressPlanVo; return progressPlanVo;
} }
@ -265,8 +273,8 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
Long projectId = req.getProjectId(); Long projectId = req.getProjectId();
Long matrixId = req.getMatrixId(); Long matrixId = req.getMatrixId();
Long progressCategoryId = req.getProgressCategoryId(); Long progressCategoryId = req.getProgressCategoryId();
Date startDate = req.getStartDate(); LocalDate startDate = req.getStartDate();
Date endDate = req.getEndDate(); LocalDate endDate = req.getEndDate();
lqw.eq(ObjectUtils.isNotEmpty(projectId), PgsProgressPlan::getProjectId, projectId); lqw.eq(ObjectUtils.isNotEmpty(projectId), PgsProgressPlan::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(matrixId), PgsProgressPlan::getMatrixId, matrixId); lqw.eq(ObjectUtils.isNotEmpty(matrixId), PgsProgressPlan::getMatrixId, matrixId);
lqw.eq(ObjectUtils.isNotEmpty(progressCategoryId), PgsProgressPlan::getProgressCategoryId, progressCategoryId); lqw.eq(ObjectUtils.isNotEmpty(progressCategoryId), PgsProgressPlan::getProgressCategoryId, progressCategoryId);
@ -292,6 +300,14 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
if (CollUtil.isEmpty(progressPlanList)) { if (CollUtil.isEmpty(progressPlanList)) {
return progressPlanVoPage; return progressPlanVoPage;
} }
// 获取进度类别列表
List<Long> progressCategoryIdList = progressPlanList.stream()
.map(PgsProgressPlan::getProgressCategoryId)
.distinct()
.toList();
List<PgsProgressCategory> progressCategoryList = progressCategoryService.listByIds(progressCategoryIdList);
Map<Long, PgsProgressCategory> progressCategoryMap = progressCategoryList.stream()
.collect(Collectors.toMap(PgsProgressCategory::getId, category -> category));
// 获取详情列表 // 获取详情列表
List<Long> idList = progressPlanList.stream().map(PgsProgressPlan::getId).toList(); List<Long> idList = progressPlanList.stream().map(PgsProgressPlan::getId).toList();
List<PgsProgressPlanDetail> detailList = progressPlanDetailService.lambdaQuery() List<PgsProgressPlanDetail> detailList = progressPlanDetailService.lambdaQuery()
@ -305,6 +321,7 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
BeanUtils.copyProperties(progressPlan, progressPlanVo); BeanUtils.copyProperties(progressPlan, progressPlanVo);
// 获取详情列表 // 获取详情列表
Long id = progressPlan.getId(); Long id = progressPlan.getId();
Long progressCategoryId = progressPlan.getProgressCategoryId();
List<PgsProgressPlanDetailNumVo> numDetailList = new ArrayList<>(); List<PgsProgressPlanDetailNumVo> numDetailList = new ArrayList<>();
BigDecimal aiFill = BigDecimal.ZERO; BigDecimal aiFill = BigDecimal.ZERO;
if (detailMap.containsKey(id)) { if (detailMap.containsKey(id)) {
@ -313,6 +330,12 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
aiFill = aiFill.add(detailNumVo.getAiFill()); aiFill = aiFill.add(detailNumVo.getAiFill());
} }
} }
if (progressCategoryMap.containsKey(progressCategoryId)) {
PgsProgressCategory category = progressCategoryMap.get(progressCategoryId);
progressPlanVo.setUnitType(category.getUnitType());
progressPlanVo.setWorkType(category.getWorkType());
progressPlanVo.setRelevancyStructure(category.getRelevancyStructure());
}
progressPlanVo.setDetailList(numDetailList); progressPlanVo.setDetailList(numDetailList);
progressPlanVo.setAiFill(aiFill); progressPlanVo.setAiFill(aiFill);
return progressPlanVo; return progressPlanVo;
@ -374,13 +397,13 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
.eq(PgsProgressPlan::getProgressCategoryId, progressCategory.getId()) .eq(PgsProgressPlan::getProgressCategoryId, progressCategory.getId())
.list(); .list();
// 获取当前时间 // 获取当前时间
Date current = new Date(); LocalDate current = LocalDate.now();
// 记录当前完成的和计划的总和 // 记录当前完成的和计划的总和
BigDecimal planFinishSum = BigDecimal.ZERO; BigDecimal planFinishSum = BigDecimal.ZERO;
for (PgsProgressPlan plan : planList) { for (PgsProgressPlan plan : planList) {
Date endDate = plan.getEndDate(); LocalDate endDate = plan.getEndDate();
BigDecimal finishedNumber = plan.getFinishedNumber(); BigDecimal finishedNumber = plan.getFinishedNumber();
if (endDate.before(current)) { if (endDate.isBefore(current)) {
// 计划结束时间在当前时间之前的,统计 -> 完成数量 // 计划结束时间在当前时间之前的,统计 -> 完成数量
planFinishSum = planFinishSum.add(finishedNumber); planFinishSum = planFinishSum.add(finishedNumber);
} else { } else {
@ -457,4 +480,21 @@ public class PgsProgressPlanServiceImpl extends ServiceImpl<PgsProgressPlanMappe
} }
return true; return true;
} }
/**
* 校验是否存在时间重叠的数据
*
* @param progressCategoryId 进度类型id
* @param startDate 新增开始时间
* @param endDate 新增结束时间
*/
public boolean hasOverlap(Long progressCategoryId, LocalDate startDate, LocalDate endDate) {
return this.lambdaQuery()
.eq(PgsProgressPlan::getProgressCategoryId, progressCategoryId)
.and(wrapper -> wrapper
.le(PgsProgressPlan::getStartDate, endDate) // 数据库中的开始 <= 新增的结束
.ge(PgsProgressPlan::getEndDate, startDate) // 数据库中的结束 >= 新增的开始
)
.exists(); // 是否存在
}
} }

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

View File

@ -64,9 +64,8 @@ public class BusProjectAppController {
} }
/** /**
* 注册项目选择列表 * 项目选择列表
*/ */
@SaIgnore
@GetMapping("/register/list") @GetMapping("/register/list")
public R<List<BusProjectVo>> registerList() { public R<List<BusProjectVo>> registerList() {
BusProjectQueryReq busProjectQueryReq = new BusProjectQueryReq(); BusProjectQueryReq busProjectQueryReq = new BusProjectQueryReq();

View File

@ -4,7 +4,9 @@ import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.web.core.BaseController; import org.dromara.common.web.core.BaseController;
import org.dromara.project.domain.dto.projectteam.BusProjectTeamQueryReq;
import org.dromara.project.domain.vo.projectteam.BusProjectTeamForemanVo; import org.dromara.project.domain.vo.projectteam.BusProjectTeamForemanVo;
import org.dromara.project.domain.vo.projectteam.BusProjectTeamVo;
import org.dromara.project.service.IBusProjectTeamService; import org.dromara.project.service.IBusProjectTeamService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -12,6 +14,8 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/** /**
* 项目班组 app 接口 * 项目班组 app 接口
* *
@ -34,4 +38,15 @@ public class BusProjectTeamAppController extends BaseController {
@PathVariable Long id) { @PathVariable Long id) {
return R.ok(projectTeamService.queryForemanListById(id)); return R.ok(projectTeamService.queryForemanListById(id));
} }
/**
* 查询项目下的班组
*/
@GetMapping("/listByProject/{projectid}")
public R<List<BusProjectTeamVo>> listByProject(@NotNull(message = "项目id不能为空")
@PathVariable Long projectid) {
BusProjectTeamQueryReq busProjectTeamQueryReq = new BusProjectTeamQueryReq();
busProjectTeamQueryReq.setProjectId(projectid);
return R.ok(projectTeamService.queryList(busProjectTeamQueryReq));
}
} }

Some files were not shown because too many files have changed in this diff Show More