Merge branch 'development' of http://pms.dtyx.net:3000/cuizhibin/znpt-backend into development

This commit is contained in:
ybb 2025-08-12 11:35:20 +08:00
commit f7b877aef8
31 changed files with 1349 additions and 53 deletions

View File

@ -197,12 +197,11 @@
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- WebSocket 支持 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>

View File

@ -0,0 +1,27 @@
package com.dite.znpt.config;
import com.dite.znpt.websocket.SimpleWebSocketHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
/**
* WebSocket配置
*/
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private final SimpleWebSocketHandler simpleWebSocketHandler;
public WebSocketConfig(SimpleWebSocketHandler simpleWebSocketHandler) {
this.simpleWebSocketHandler = simpleWebSocketHandler;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(simpleWebSocketHandler, "/websocket")
.setAllowedOrigins("*"); // 在生产环境中应该限制允许的源
}
}

View File

@ -177,6 +177,9 @@ public class EquipmentEntity extends AuditableEntity implements Serializable {
@ApiModelProperty("发票状态")
private String invoiceStatus;
@ApiModelProperty("采购状态NOT_STARTED-未开始PENDING_APPROVAL-待审批APPROVED-已通过REJECTED-已拒绝COMPLETED-已完成")
private String procurementStatus;
@ApiModelProperty("附件")
private String attachments;
@ -214,4 +217,7 @@ public class EquipmentEntity extends AuditableEntity implements Serializable {
@ApiModelProperty("删除标志0代表存在 1代表删除")
@TableLogic(value = "0", delval = "1")
private String delFlag;
}
@ApiModelProperty("项目id")
private String projectId;
}

View File

@ -0,0 +1,70 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* @author Bear.G
* @date 2025/1/8/周三 18:00
* @description 设备采购申请请求VO
*/
@Data
@ApiModel(value = "EquipmentProcurementApplyReq", description = "设备采购申请请求")
public class EquipmentProcurementApplyReq {
@ApiModelProperty("设备ID")
@NotBlank(message = "设备ID不能为空")
private String equipmentId;
@ApiModelProperty("设备名称")
@NotBlank(message = "设备名称不能为空")
private String equipmentName;
@ApiModelProperty("设备类型")
@NotBlank(message = "设备类型不能为空")
private String equipmentType;
@ApiModelProperty("设备型号")
private String equipmentModel;
@ApiModelProperty("品牌")
private String brand;
@ApiModelProperty("供应商名称")
private String supplierName;
@ApiModelProperty("预算金额")
@NotNull(message = "预算金额不能为空")
private BigDecimal budgetAmount;
@ApiModelProperty("数量")
@NotNull(message = "数量不能为空")
private Integer quantity;
@ApiModelProperty("紧急程度LOW-低NORMAL-普通HIGH-高URGENT-紧急")
@NotBlank(message = "紧急程度不能为空")
private String urgencyLevel;
@ApiModelProperty("申请原因")
@NotBlank(message = "申请原因不能为空")
private String applyReason;
@ApiModelProperty("技术要求")
private String technicalRequirements;
@ApiModelProperty("业务合理性说明")
private String businessJustification;
@ApiModelProperty("预期交付日期")
private LocalDate expectedDeliveryDate;
@ApiModelProperty("采购类型NEW_PURCHASE-新采购REPLACEMENT-更换UPGRADE-升级")
@NotBlank(message = "采购类型不能为空")
private String procurementType;
}

View File

@ -154,6 +154,9 @@ public class EquipmentResp implements Serializable {
@ApiModelProperty("总价")
private BigDecimal totalPrice;
@ApiModelProperty("采购状态NOT_STARTED-未开始PENDING_APPROVAL-待审批APPROVED-已通过REJECTED-已拒绝COMPLETED-已完成")
private String procurementStatus;
// 移除备用状态字段使用现有的 location_status 字段
// @ApiModelProperty("备用状态")
// private String spareStatus;

View File

@ -0,0 +1,41 @@
package com.dite.znpt.domain.vo;
import com.dite.znpt.util.ValidationGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDate;
@Data
@ApiModel("项目初始化任务请求参数")
public class ProjectInitTaskReq {
@ApiModelProperty("任务名称")
private String taskName;
@NotBlank(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "项目任务编号不能为空")
@Size(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, max = 100, message = "项目任务编号长度不能超过100字符")
@ApiModelProperty("项目任务编号")
private String taskCode;
@NotNull(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "计划开始时间不能为空")
@ApiModelProperty("计划开始时间")
private LocalDate planStartDate;
@NotNull(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "计划结束时间不能为空")
@ApiModelProperty("计划结束时间")
private LocalDate planEndDate;
@NotBlank(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "任务组id不能为空")
@Size(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, max = 32, message = "任务组id长度不能超过32字符")
@ApiModelProperty("任务组id")
private String taskGroupId;
@NotBlank(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "任务负责人id不能为空")
@Size(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, max = 100, message = "任务负责人id长度不能超过100字符")
@ApiModelProperty("任务负责人id")
private String mainUserId;
}

View File

@ -17,20 +17,29 @@ import java.util.List;
@ApiModel(value="ProjectKanbanDataResp对象", description="项目看板数据响应")
public class ProjectKanbanDataResp {
@ApiModelProperty("待施工项目列表")
@ApiModelProperty("未开工项目列表")
private List<ProjectKanbanItem> pendingProjects;
@ApiModelProperty("施工中项目列表")
@ApiModelProperty("筹备中项目列表")
private List<ProjectKanbanItem> preparingProjects;
@ApiModelProperty("开工中项目列表")
private List<ProjectKanbanItem> inProgressProjects;
@ApiModelProperty("暂停中项目列表")
private List<ProjectKanbanItem> suspendedProjects;
@ApiModelProperty("已完工项目列表")
private List<ProjectKanbanItem> completedProjects;
@ApiModelProperty("已审核项目列表")
private List<ProjectKanbanItem> auditedProjects;
@ApiModelProperty("验收中项目列表")
private List<ProjectKanbanItem> acceptanceProjects;
@ApiModelProperty("已验收项目列表")
private List<ProjectKanbanItem> acceptedProjects;
@ApiModelProperty("回款中项目列表")
private List<ProjectKanbanItem> collectionProjects;
@ApiModelProperty("已结算项目列表")
private List<ProjectKanbanItem> settledProjects;
@Data
@ApiModel(value="ProjectKanbanItem对象", description="项目看板项目项")

View File

@ -19,17 +19,26 @@ public class ProjectKanbanStatsResp {
@ApiModelProperty("待施工项目数")
private Long pendingProjectCount;
@ApiModelProperty("施工中项目数")
@ApiModelProperty("筹备中项目数")
private Long preparingProjectCount;
@ApiModelProperty("开工中项目数")
private Long inProgressProjectCount;
@ApiModelProperty("暂停中项目数")
private Long suspendedProjectCount;
@ApiModelProperty("已完工项目数")
private Long completedProjectCount;
@ApiModelProperty("已审核项目数")
private Long auditedProjectCount;
@ApiModelProperty("验收中项目数")
private Long acceptanceProjectCount;
@ApiModelProperty("已验收项目数")
private Long acceptedProjectCount;
@ApiModelProperty("回款中项目数")
private Long collectionProjectCount;
@ApiModelProperty("已结算项目数")
private Long settledProjectCount;
@ApiModelProperty("总机组数")
private Long totalTurbineCount;

View File

@ -1,5 +1,6 @@
package com.dite.znpt.domain.vo;
import com.dite.znpt.domain.entity.ProjectTaskEntity;
import com.dite.znpt.util.ValidationGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -10,6 +11,7 @@ import javax.validation.constraints.Size;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.List;
/**
* @Author: gaoxiong
@ -31,7 +33,6 @@ public class ProjectReq implements Serializable {
@ApiModelProperty("项目来源")
private String projectOrigin;
@NotBlank(groups = {ValidationGroup.Insert.class, ValidationGroup.Update.class}, message = "项目预算不能为空")
@ApiModelProperty("项目预算")
private Integer projectBudget;
@ -127,4 +128,7 @@ public class ProjectReq implements Serializable {
@ApiModelProperty("其他杂费")
private Double othersCost;
@ApiModelProperty("项目初始任务")
private List<ProjectInitTaskReq> tasks;
}

View File

@ -0,0 +1,23 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel("项目任务详情响应实体")
public class ProjectTasksDetailResp {
private List<ProjectTaskResp> list;
@ApiModelProperty("项目名称")
private String projectName;
@ApiModelProperty("项目任务总数")
private Integer total;
@ApiModelProperty("已完成任务数")
private Integer finished;
}

View File

@ -0,0 +1,60 @@
package com.dite.znpt.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDate;
/**
* @author wangna
* @date 2025/08/05
* @Description: 团队成员更新请求类用于更新操作移除必填验证
*/
@Data
@ApiModel(value="TeamMemberUpdateReq对象", description="团队成员更新请求类")
public class TeamMemberUpdateReq implements Serializable {
@ApiModelProperty("项目ID")
private String projectId;
@ApiModelProperty("机组ID可选")
private String turbineId;
@ApiModelProperty("任务组ID可选")
private String taskGroupId;
@ApiModelProperty("任务ID可选")
private String taskId;
@ApiModelProperty("用户ID")
private String userId;
@ApiModelProperty("项目角色类型PROJECT_MANAGER-项目经理SAFETY_OFFICER-安全员QUALITY_OFFICER-质量员CONSTRUCTOR-施工人员TEAM_LEADER-施工组长")
private String roleType;
@ApiModelProperty("具体岗位代码GROUND_SERVICE-地勤DRIVER-司机ASCENDING-登高等)")
private String jobCode;
@ApiModelProperty("岗位描述")
private String jobDesc;
@ApiModelProperty("加入时间")
private LocalDate joinDate;
@ApiModelProperty("离开时间")
private LocalDate leaveDate;
@ApiModelProperty("状态ACTIVE-在职INACTIVE-离职PENDING-待入职")
private String status = "ACTIVE";
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("用户电话")
private String phone;
@ApiModelProperty("用户邮箱")
private String email;
}

View File

@ -15,11 +15,14 @@ import java.util.List;
@Getter
@AllArgsConstructor
public enum ProjectStatusEnum {
PENDING(0, "待施工"),
IN_PROGRESS(1, "施工中"),
COMPLETED(2, "已完工"),
AUDITED(3, "已审核"),
ACCEPTED(4, "已验收");
PENDING(0, "未开工"),
PREPARING(1, "筹备中"),
IN_PROGRESS(2, "开工中"),
SUSPENDED(3, "暂停中"),
COMPLETED(4, "已完工"),
IN_ACCEPTANCE(5, "验收中"),
IN_COLLECTION(6, "回款中"),
SETTLED(7, "已结算");
private final int code;
private final String desc;

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dite.znpt.domain.vo.EquipmentApprovalListReq;
import com.dite.znpt.domain.vo.EquipmentApprovalReq;
import com.dite.znpt.domain.vo.EquipmentApprovalResp;
import com.dite.znpt.domain.vo.EquipmentProcurementApplyReq;
/**
* @author Bear.G
@ -41,4 +42,19 @@ public interface EquipmentApprovalService {
* 获取审批统计信息
*/
Object getApprovalStats();
/**
* 提交采购申请
*/
void submitProcurementApplication(EquipmentProcurementApplyReq req);
/**
* 获取我的采购申请
*/
IPage<EquipmentApprovalResp> getMyProcurementApplications(EquipmentApprovalListReq req);
/**
* 撤回采购申请
*/
void withdrawProcurementApplication(String approvalId);
}

View File

@ -0,0 +1,51 @@
package com.dite.znpt.service;
/**
* 设备状态更新服务接口
* 用于处理设备审批后的状态更新避免循环依赖
*
* @author Bear.G
* @date 2025/1/8/周三 17:50
*/
public interface EquipmentStatusUpdateService {
/**
* 更新设备采购状态
*
* @param equipmentId 设备ID
* @param status 新状态
*/
void updateProcurementStatus(String equipmentId, String status);
/**
* 更新设备借用状态
*
* @param equipmentId 设备ID
* @param status 新状态
*/
void updateBorrowStatus(String equipmentId, String status);
/**
* 更新设备归还状态
*
* @param equipmentId 设备ID
* @param status 新状态
*/
void updateReturnStatus(String equipmentId, String status);
/**
* 更新设备位置状态
*
* @param equipmentId 设备ID
* @param locationStatus 新位置状态
*/
void updateLocationStatus(String equipmentId, String locationStatus);
/**
* 更新设备使用状态
*
* @param equipmentId 设备ID
* @param useStatus 新使用状态
*/
void updateUseStatus(String equipmentId, String useStatus);
}

View File

@ -27,6 +27,11 @@ public interface ProjectMemberService extends IService<ProjectMemberEntity> {
*/
ProjectMemberResp updateTeamMember(String memberId, TeamMemberReq req);
/**
* 更新团队成员信息使用更新专用请求类
*/
ProjectMemberResp updateTeamMember(String memberId, TeamMemberUpdateReq req);
/**
* 删除团队成员支持单个或批量删除
*/

View File

@ -89,5 +89,7 @@ public interface ProjectTaskService extends IService<ProjectTaskEntity> {
* @date 2025/06/25 21:16
**/
void endTask(ProjectTaskStartReq taskStartReq);
List<ProjectTaskResp> getTaskByProjectId(String projectId);
}

View File

@ -8,7 +8,11 @@ import com.dite.znpt.domain.mapper.EquipmentApprovalMapper;
import com.dite.znpt.domain.vo.EquipmentApprovalListReq;
import com.dite.znpt.domain.vo.EquipmentApprovalReq;
import com.dite.znpt.domain.vo.EquipmentApprovalResp;
import com.dite.znpt.domain.vo.EquipmentProcurementApplyReq;
import com.dite.znpt.service.EquipmentApprovalService;
import com.dite.znpt.service.EquipmentStatusUpdateService;
import com.dite.znpt.websocket.SimpleWebSocketHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@ -25,11 +29,15 @@ import java.util.stream.Collectors;
* @date 2025/1/8/周三 17:55
* @description 设备审批服务实现类
*/
@Slf4j
@Service
public class EquipmentApprovalServiceImpl implements EquipmentApprovalService {
@Resource
private EquipmentApprovalMapper equipmentApprovalMapper;
@Resource
private EquipmentStatusUpdateService equipmentStatusUpdateService;
@Override
public IPage<EquipmentApprovalResp> getPendingApprovals(EquipmentApprovalListReq req) {
@ -81,6 +89,21 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService {
entity.setApprovalComment(req.getApprovalComment());
equipmentApprovalMapper.updateById(entity);
// 审批通过后更新设备状态
try {
if ("PROCUREMENT".equals(entity.getBusinessType())) {
equipmentStatusUpdateService.updateProcurementStatus(entity.getEquipmentId(), "APPROVED");
} else if ("BORROW".equals(entity.getBusinessType())) {
equipmentStatusUpdateService.updateBorrowStatus(entity.getEquipmentId(), "APPROVED");
} else if ("RETURN".equals(entity.getBusinessType())) {
equipmentStatusUpdateService.updateReturnStatus(entity.getEquipmentId(), "APPROVED");
}
log.info("设备状态更新成功设备ID: {}, 审批ID: {}", entity.getEquipmentId(), approvalId);
} catch (Exception e) {
log.error("设备状态更新失败设备ID: {}, 审批ID: {}", entity.getEquipmentId(), approvalId, e);
// 不抛出异常避免影响审批流程
}
}
@Override
@ -97,6 +120,21 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService {
entity.setApprovalComment(req.getApprovalComment());
equipmentApprovalMapper.updateById(entity);
// 审批拒绝后更新设备状态
try {
if ("PROCUREMENT".equals(entity.getBusinessType())) {
equipmentStatusUpdateService.updateProcurementStatus(entity.getEquipmentId(), "REJECTED");
} else if ("BORROW".equals(entity.getBusinessType())) {
equipmentStatusUpdateService.updateBorrowStatus(entity.getEquipmentId(), "REJECTED");
} else if ("RETURN".equals(entity.getBusinessType())) {
equipmentStatusUpdateService.updateReturnStatus(entity.getEquipmentId(), "REJECTED");
}
log.info("设备状态更新成功设备ID: {}, 审批ID: {}", entity.getEquipmentId(), approvalId);
} catch (Exception e) {
log.error("设备状态更新失败设备ID: {}, 审批ID: {}", entity.getEquipmentId(), approvalId, e);
// 不抛出异常避免影响审批流程
}
}
@Override
@ -138,38 +176,61 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService {
* 添加查询条件
*/
private void addQueryConditions(LambdaQueryWrapper<EquipmentApprovalEntity> wrapper, EquipmentApprovalListReq req) {
log.info("开始构建查询条件,请求参数: {}", req);
// 添加搜索条件并记录日志
int conditionCount = 0;
if (StringUtils.hasText(req.getEquipmentName())) {
wrapper.like(EquipmentApprovalEntity::getEquipmentName, req.getEquipmentName());
log.info("添加设备名称查询条件: {}", req.getEquipmentName());
conditionCount++;
}
if (StringUtils.hasText(req.getApplicantName())) {
wrapper.like(EquipmentApprovalEntity::getApplicantName, req.getApplicantName());
log.info("添加申请人查询条件: {}", req.getApplicantName());
conditionCount++;
}
if (StringUtils.hasText(req.getBusinessType())) {
wrapper.eq(EquipmentApprovalEntity::getBusinessType, req.getBusinessType());
log.info("添加业务类型查询条件: {}", req.getBusinessType());
conditionCount++;
}
if (StringUtils.hasText(req.getApprovalStatus())) {
wrapper.eq(EquipmentApprovalEntity::getApprovalStatus, req.getApprovalStatus());
log.info("添加审批状态查询条件: {}", req.getApprovalStatus());
conditionCount++;
}
if (StringUtils.hasText(req.getApplyTimeStart())) {
wrapper.ge(EquipmentApprovalEntity::getApplyTime, req.getApplyTimeStart());
log.info("添加申请时间开始查询条件: {}", req.getApplyTimeStart());
conditionCount++;
}
if (StringUtils.hasText(req.getApplyTimeEnd())) {
wrapper.le(EquipmentApprovalEntity::getApplyTime, req.getApplyTimeEnd());
log.info("添加申请时间结束查询条件: {}", req.getApplyTimeEnd());
conditionCount++;
}
if (StringUtils.hasText(req.getApprovalTimeStart())) {
wrapper.ge(EquipmentApprovalEntity::getApprovalTime, req.getApprovalTimeStart());
log.info("添加审批时间开始查询条件: {}", req.getApprovalTimeStart());
conditionCount++;
}
if (StringUtils.hasText(req.getApprovalTimeEnd())) {
wrapper.le(EquipmentApprovalEntity::getApprovalTime, req.getApprovalTimeEnd());
log.info("添加审批时间结束查询条件: {}", req.getApprovalTimeEnd());
conditionCount++;
}
log.info("查询条件构建完成,共添加 {} 个条件", conditionCount);
// 排序
wrapper.orderByDesc(EquipmentApprovalEntity::getCreateTime);
}
@ -196,4 +257,279 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService {
return respPage;
}
@Override
public void submitProcurementApplication(EquipmentProcurementApplyReq req) {
log.info("开始提交采购申请,请求参数: {}", req);
// 创建审批实体
EquipmentApprovalEntity entity = new EquipmentApprovalEntity();
// 设置基本信息
entity.setEquipmentId(req.getEquipmentId()); // 添加设备ID
entity.setEquipmentName(req.getEquipmentName());
entity.setEquipmentType(req.getEquipmentType());
entity.setEquipmentModel(req.getEquipmentModel());
entity.setBrand(req.getBrand());
entity.setSupplierName(req.getSupplierName());
entity.setPurchasePrice(req.getBudgetAmount());
entity.setTotalPrice(req.getBudgetAmount().multiply(new java.math.BigDecimal(req.getQuantity())));
entity.setQuantity(req.getQuantity());
// 设置申请信息
entity.setApplicantName(getCurrentUserName()); // 获取当前用户名
entity.setApplicantId(getCurrentUserId()); // 获取当前用户ID
entity.setApplyTime(LocalDateTime.now());
entity.setApplyReason(req.getApplyReason());
// 设置业务类型和审批状态
entity.setBusinessType("PROCUREMENT");
entity.setApprovalStatus("PENDING");
// 设置扩展字段如果有的话
// entity.setProcurementType(req.getProcurementType());
// entity.setUrgencyLevel(req.getUrgencyLevel());
// entity.setTechnicalRequirements(req.getTechnicalRequirements());
// entity.setBusinessJustification(req.getBusinessJustification());
// entity.setExpectedDeliveryDate(req.getExpectedDeliveryDate());
// 保存到数据库
equipmentApprovalMapper.insert(entity);
// 更新设备采购状态 - 新增逻辑
try {
equipmentStatusUpdateService.updateProcurementStatus(req.getEquipmentId(), "PENDING_APPROVAL");
log.info("设备采购状态更新成功设备ID: {}", req.getEquipmentId());
} catch (Exception e) {
log.error("设备采购状态更新失败设备ID: {}", req.getEquipmentId(), e);
// 不抛出异常避免影响审批流程
}
// 发送通知 - 使用日志记录后续可以扩展为WebSocket通知
log.info("采购申请提交成功,设备名称: {}, 申请人: {}",
req.getEquipmentName(), getCurrentUserName());
// 发送WebSocket通知
try {
SimpleWebSocketHandler.sendProcurementNotification(
req.getEquipmentName(),
getCurrentUserName()
);
log.info("WebSocket通知发送成功");
} catch (Exception e) {
log.error("WebSocket通知发送失败", e);
}
log.info("采购申请提交成功审批ID: {}", entity.getApprovalId());
}
/**
* 更新设备采购状态
*/
private void updateEquipmentProcurementStatus(String equipmentId, String status) {
if (equipmentId == null || equipmentId.trim().isEmpty()) {
log.warn("设备ID为空跳过状态更新");
return;
}
try {
log.info("准备更新设备采购状态设备ID: {}, 新状态: {}", equipmentId, status);
// 这里可以添加具体的更新逻辑
// 例如equipmentMapper.updateProcurementStatus(equipmentId, status);
// 由于循环依赖问题建议通过事件机制或异步处理来避免循环依赖
// 暂时记录日志后续可以通过以下方式实现
// 1. 使用Spring事件机制
// 2. 使用异步处理
// 3. 重构服务架构避免循环依赖
} catch (Exception e) {
log.error("更新设备采购状态失败设备ID: {}, 状态: {}", equipmentId, status, e);
throw e;
}
}
/**
* 审批通过后更新设备状态
*/
private void updateEquipmentStatusAfterApproval(EquipmentApprovalEntity entity) {
if (entity == null || entity.getEquipmentId() == null) {
log.warn("审批实体或设备ID为空跳过状态更新");
return;
}
try {
log.info("审批通过后更新设备状态设备ID: {}, 业务类型: {}", entity.getEquipmentId(), entity.getBusinessType());
// 根据业务类型更新不同的设备状态
if ("PROCUREMENT".equals(entity.getBusinessType())) {
// 采购审批通过更新设备状态为已采购
updateEquipmentProcurementStatus(entity.getEquipmentId(), "APPROVED");
} else if ("BORROW".equals(entity.getBusinessType())) {
// 借用审批通过更新设备状态为已借用
updateEquipmentBorrowStatus(entity.getEquipmentId(), "APPROVED");
} else if ("RETURN".equals(entity.getBusinessType())) {
// 归还审批通过更新设备状态为已归还
updateEquipmentReturnStatus(entity.getEquipmentId(), "APPROVED");
}
log.info("设备状态更新成功设备ID: {}", entity.getEquipmentId());
} catch (Exception e) {
log.error("审批通过后更新设备状态失败设备ID: {}", entity.getEquipmentId(), e);
throw e;
}
}
/**
* 审批拒绝后更新设备状态
*/
private void updateEquipmentStatusAfterRejection(EquipmentApprovalEntity entity) {
if (entity == null || entity.getEquipmentId() == null) {
log.warn("审批实体或设备ID为空跳过状态更新");
return;
}
try {
log.info("审批拒绝后更新设备状态设备ID: {}, 业务类型: {}", entity.getEquipmentId(), entity.getBusinessType());
// 根据业务类型更新不同的设备状态
if ("PROCUREMENT".equals(entity.getBusinessType())) {
// 采购审批拒绝更新设备状态为审批拒绝
updateEquipmentProcurementStatus(entity.getEquipmentId(), "REJECTED");
} else if ("BORROW".equals(entity.getBusinessType())) {
// 借用审批拒绝更新设备状态为借用拒绝
updateEquipmentBorrowStatus(entity.getEquipmentId(), "REJECTED");
} else if ("RETURN".equals(entity.getBusinessType())) {
// 归还审批拒绝更新设备状态为归还拒绝
updateEquipmentReturnStatus(entity.getEquipmentId(), "REJECTED");
}
log.info("设备状态更新成功设备ID: {}", entity.getEquipmentId());
} catch (Exception e) {
log.error("审批拒绝后更新设备状态失败设备ID: {}", entity.getEquipmentId(), e);
throw e;
}
}
/**
* 更新设备借用状态
*/
private void updateEquipmentBorrowStatus(String equipmentId, String status) {
if (equipmentId == null || equipmentId.trim().isEmpty()) {
log.warn("设备ID为空跳过借用状态更新");
return;
}
try {
log.info("准备更新设备借用状态设备ID: {}, 新状态: {}", equipmentId, status);
// 这里可以添加具体的更新逻辑
// 例如equipmentMapper.updateBorrowStatus(equipmentId, status);
} catch (Exception e) {
log.error("更新设备借用状态失败设备ID: {}, 状态: {}", equipmentId, status, e);
throw e;
}
}
/**
* 更新设备归还状态
*/
private void updateEquipmentReturnStatus(String equipmentId, String status) {
if (equipmentId == null || equipmentId.trim().isEmpty()) {
log.warn("设备ID为空跳过归还状态更新");
return;
}
try {
log.info("准备更新设备归还状态设备ID: {}, 新状态: {}", equipmentId, status);
// 这里可以添加具体的更新逻辑
// 例如equipmentMapper.updateReturnStatus(equipmentId, status);
} catch (Exception e) {
log.error("更新设备归还状态失败设备ID: {}, 状态: {}", equipmentId, status, e);
throw e;
}
}
@Override
public IPage<EquipmentApprovalResp> getMyProcurementApplications(EquipmentApprovalListReq req) {
log.info("开始获取我的采购申请,请求参数: {}", req);
// 创建分页对象
Integer pageNum = req.getPage() != null ? req.getPage() : 1;
Integer pageSize = req.getPageSize() != null ? req.getPageSize() : 10;
Page<EquipmentApprovalEntity> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<EquipmentApprovalEntity> wrapper = new LambdaQueryWrapper<>();
// 只查询当前用户的申请
wrapper.eq(EquipmentApprovalEntity::getApplicantId, getCurrentUserId());
wrapper.eq(EquipmentApprovalEntity::getBusinessType, "PROCUREMENT");
// 添加查询条件
addQueryConditions(wrapper, req);
IPage<EquipmentApprovalEntity> result = equipmentApprovalMapper.selectPage(page, wrapper);
return convertToRespPage(result);
}
@Override
public void withdrawProcurementApplication(String approvalId) {
log.info("开始撤回采购申请审批ID: {}", approvalId);
EquipmentApprovalEntity entity = equipmentApprovalMapper.selectById(approvalId);
if (entity == null) {
throw new RuntimeException("审批记录不存在");
}
// 检查是否是当前用户的申请
if (!entity.getApplicantId().equals(getCurrentUserId())) {
throw new RuntimeException("只能撤回自己的申请");
}
// 检查状态是否可以撤回
if (!"PENDING".equals(entity.getApprovalStatus())) {
throw new RuntimeException("只能撤回待审批状态的申请");
}
// 更新状态为已撤回
entity.setApprovalStatus("WITHDRAWN");
equipmentApprovalMapper.updateById(entity);
log.info("采购申请撤回成功审批ID: {}", approvalId);
}
/**
* 获取当前用户名
*/
private String getCurrentUserName() {
try {
// 从Sa-Token上下文获取当前用户名
Object loginId = cn.dev33.satoken.stp.StpUtil.getLoginId();
if (loginId != null) {
return loginId.toString();
}
} catch (Exception e) {
log.warn("获取当前用户名失败: {}", e.getMessage());
}
return "未知用户";
}
/**
* 获取当前用户ID
*/
private String getCurrentUserId() {
try {
// 从Sa-Token上下文获取当前用户ID
Object loginId = cn.dev33.satoken.stp.StpUtil.getLoginId();
if (loginId != null) {
return loginId.toString();
}
} catch (Exception e) {
log.warn("获取当前用户ID失败: {}", e.getMessage());
}
return "unknown_user_id";
}
}

View File

@ -562,6 +562,9 @@ public class EquipmentServiceImpl extends ServiceImpl<EquipmentMapper, Equipment
resp.setInventoryBasis(entity.getInventoryBasis());
resp.setDynamicRecord(entity.getDynamicRecord());
// 设置采购状态字段
resp.setProcurementStatus(entity.getProcurementStatus());
// 新增字段转换
resp.setUsingDepartment(entity.getUsingDepartment());
resp.setBorrowingTime(entity.getBorrowingTime());
@ -699,6 +702,11 @@ public class EquipmentServiceImpl extends ServiceImpl<EquipmentMapper, Equipment
conditionCount++;
}
// 添加采购状态查询条件 - 确保查询有采购状态的设备
queryWrapper.isNotNull(EquipmentEntity::getProcurementStatus);
log.info("添加采购状态查询条件: 不为空");
conditionCount++;
log.info("总共添加了 {} 个查询条件", conditionCount);
// 按采购时间倒序排列

View File

@ -0,0 +1,232 @@
package com.dite.znpt.service.impl;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dite.znpt.domain.entity.EquipmentEntity;
import com.dite.znpt.mapper.EquipmentMapper;
import com.dite.znpt.service.EquipmentStatusUpdateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
/**
* 设备状态更新服务实现类
* 使用MyBatis Plus来更新设备状态避免循环依赖
*
* @author Bear.G
* @date 2025/1/8/周三 17:50
*/
@Slf4j
@Service
public class EquipmentStatusUpdateServiceImpl implements EquipmentStatusUpdateService {
@Resource
private EquipmentMapper equipmentMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void updateProcurementStatus(String equipmentId, String status) {
if (equipmentId == null || equipmentId.trim().isEmpty()) {
log.warn("设备ID为空跳过采购状态更新");
return;
}
try {
log.info("开始更新设备采购状态设备ID: {}, 新状态: {}", equipmentId, status);
// 使用MyBatis Plus的LambdaUpdateWrapper来更新设备状态
LambdaUpdateWrapper<EquipmentEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(EquipmentEntity::getEquipmentId, equipmentId);
// 根据状态设置相应的字段
if ("APPROVED".equals(status)) {
// 审批通过设置采购状态为已通过位置状态为库存中使用状态为空闲中
updateWrapper.set(EquipmentEntity::getProcurementStatus, "APPROVED");
updateWrapper.set(EquipmentEntity::getLocationStatus, "in_stock");
updateWrapper.set(EquipmentEntity::getUseStatus, "0");
updateWrapper.set(EquipmentEntity::getInStockTime, LocalDateTime.now());
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
log.info("设备采购审批通过,设置状态为已通过");
} else if ("REJECTED".equals(status)) {
// 审批拒绝设置采购状态为已拒绝位置状态为未入库使用状态为空闲中
updateWrapper.set(EquipmentEntity::getProcurementStatus, "REJECTED");
updateWrapper.set(EquipmentEntity::getLocationStatus, "not_in_stock");
updateWrapper.set(EquipmentEntity::getUseStatus, "0");
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
log.info("设备采购审批拒绝,设置状态为已拒绝");
} else if ("PENDING_APPROVAL".equals(status) || "PENDING".equals(status)) {
// 待审批设置采购状态为待审批位置状态为待审批使用状态为空闲中
updateWrapper.set(EquipmentEntity::getProcurementStatus, "PENDING_APPROVAL");
updateWrapper.set(EquipmentEntity::getLocationStatus, "pending_approval");
updateWrapper.set(EquipmentEntity::getUseStatus, "0");
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
log.info("设备采购申请提交,设置状态为待审批");
} else if ("COMPLETED".equals(status)) {
// 采购完成设置采购状态为已完成位置状态为库存中使用状态为空闲中
updateWrapper.set(EquipmentEntity::getProcurementStatus, "COMPLETED");
updateWrapper.set(EquipmentEntity::getLocationStatus, "in_stock");
updateWrapper.set(EquipmentEntity::getUseStatus, "0");
updateWrapper.set(EquipmentEntity::getInStockTime, LocalDateTime.now());
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
log.info("设备采购完成,设置状态为已完成");
}
// 执行更新
int updateCount = equipmentMapper.update(null, updateWrapper);
if (updateCount > 0) {
log.info("设备采购状态更新成功设备ID: {}, 新状态: {}, 影响行数: {}", equipmentId, status, updateCount);
} else {
log.warn("设备采购状态更新失败设备ID: {}, 新状态: {}, 可能设备不存在", equipmentId, status);
}
} catch (Exception e) {
log.error("更新设备采购状态失败设备ID: {}, 状态: {}", equipmentId, status, e);
throw e;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateBorrowStatus(String equipmentId, String status) {
if (equipmentId == null || equipmentId.trim().isEmpty()) {
log.warn("设备ID为空跳过借用状态更新");
return;
}
try {
log.info("开始更新设备借用状态设备ID: {}, 新状态: {}", equipmentId, status);
LambdaUpdateWrapper<EquipmentEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(EquipmentEntity::getEquipmentId, equipmentId);
if ("APPROVED".equals(status)) {
// 借用审批通过设置位置状态为外借中使用状态为使用中
updateWrapper.set(EquipmentEntity::getLocationStatus, "borrowed");
updateWrapper.set(EquipmentEntity::getUseStatus, "1");
updateWrapper.set(EquipmentEntity::getBorrowingTime, LocalDateTime.now());
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
log.info("设备借用审批通过,设置状态为外借中");
} else if ("REJECTED".equals(status)) {
// 借用审批拒绝保持原有状态
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
log.info("设备借用审批拒绝,保持原有状态");
}
// 执行更新
int updateCount = equipmentMapper.update(null, updateWrapper);
if (updateCount > 0) {
log.info("设备借用状态更新成功设备ID: {}, 新状态: {}, 影响行数: {}", equipmentId, status, updateCount);
} else {
log.warn("设备借用状态更新失败设备ID: {}, 新状态: {}, 可能设备不存在", equipmentId, status);
}
} catch (Exception e) {
log.error("更新设备借用状态失败设备ID: {}, 状态: {}", equipmentId, status, e);
throw e;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateReturnStatus(String equipmentId, String status) {
if (equipmentId == null || equipmentId.trim().isEmpty()) {
log.warn("设备ID为空跳过归还状态更新");
return;
}
try {
log.info("开始更新设备归还状态设备ID: {}, 新状态: {}", equipmentId, status);
LambdaUpdateWrapper<EquipmentEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(EquipmentEntity::getEquipmentId, equipmentId);
if ("APPROVED".equals(status)) {
// 归还审批通过设置位置状态为库存中使用状态为空闲中
updateWrapper.set(EquipmentEntity::getLocationStatus, "in_stock");
updateWrapper.set(EquipmentEntity::getUseStatus, "0");
updateWrapper.set(EquipmentEntity::getReturnTime, LocalDateTime.now());
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
log.info("设备归还审批通过,设置状态为库存中");
} else if ("REJECTED".equals(status)) {
// 归还审批拒绝保持原有状态
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
log.info("设备归还审批拒绝,保持原有状态");
}
// 执行更新
int updateCount = equipmentMapper.update(null, updateWrapper);
if (updateCount > 0) {
log.info("设备归还状态更新成功设备ID: {}, 新状态: {}, 影响行数: {}", equipmentId, status, updateCount);
} else {
log.warn("设备归还状态更新失败设备ID: {}, 新状态: {}, 可能设备不存在", equipmentId, status);
}
} catch (Exception e) {
log.error("更新设备归还状态失败设备ID: {}, 状态: {}", equipmentId, status, e);
throw e;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateLocationStatus(String equipmentId, String locationStatus) {
if (equipmentId == null || equipmentId.trim().isEmpty()) {
log.warn("设备ID为空跳过位置状态更新");
return;
}
try {
log.info("开始更新设备位置状态设备ID: {}, 新位置状态: {}", equipmentId, locationStatus);
LambdaUpdateWrapper<EquipmentEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(EquipmentEntity::getEquipmentId, equipmentId);
updateWrapper.set(EquipmentEntity::getLocationStatus, locationStatus);
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
// 执行更新
int updateCount = equipmentMapper.update(null, updateWrapper);
if (updateCount > 0) {
log.info("设备位置状态更新成功设备ID: {}, 新位置状态: {}, 影响行数: {}", equipmentId, locationStatus, updateCount);
} else {
log.warn("设备位置状态更新失败设备ID: {}, 新位置状态: {}, 可能设备不存在", equipmentId, locationStatus);
}
} catch (Exception e) {
log.error("更新设备位置状态失败设备ID: {}, 位置状态: {}", equipmentId, locationStatus, e);
throw e;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateUseStatus(String equipmentId, String useStatus) {
if (equipmentId == null || equipmentId.trim().isEmpty()) {
log.warn("设备ID为空跳过使用状态更新");
return;
}
try {
log.info("开始更新设备使用状态设备ID: {}, 新使用状态: {}", equipmentId, useStatus);
LambdaUpdateWrapper<EquipmentEntity> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(EquipmentEntity::getEquipmentId, equipmentId);
updateWrapper.set(EquipmentEntity::getUseStatus, useStatus);
updateWrapper.set(EquipmentEntity::getStatusChangeTime, LocalDateTime.now());
// 执行更新
int updateCount = equipmentMapper.update(null, updateWrapper);
if (updateCount > 0) {
log.info("设备使用状态更新成功设备ID: {}, 新使用状态: {}, 影响行数: {}", equipmentId, useStatus, updateCount);
} else {
log.warn("设备使用状态更新失败设备ID: {}, 新使用状态: {}, 可能设备不存在", equipmentId, useStatus);
}
} catch (Exception e) {
log.error("更新设备使用状态失败设备ID: {}, 使用状态: {}", equipmentId, useStatus, e);
throw e;
}
}
}

View File

@ -90,6 +90,7 @@ public class EquipmentUseRecordServiceImpl extends ServiceImpl<EquipmentUseRecor
this.save(equipmentUseRecordEntity);
equipment.setUseStatus("1");
equipment.setProjectId(req.getProjectId());
equipment.setUseRecordId(equipmentUseRecordEntity.getUseRecordId());
equipmentService.updateById(equipment);
@ -132,6 +133,7 @@ public class EquipmentUseRecordServiceImpl extends ServiceImpl<EquipmentUseRecor
equipment.setUseRecordId(null);
equipment.setUseStatus("0");
equipment.setProjectId(null);
equipmentService.updateById(equipment);
}
}
}

View File

@ -1,5 +1,6 @@
package com.dite.znpt.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
@ -18,6 +19,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -188,6 +190,14 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
ProjectMemberEntity entity = new ProjectMemberEntity();
BeanUtil.copyProperties(req, entity);
// 设置创建和更新信息
String currentUserId = StpUtil.getLoginIdAsString();
LocalDateTime now = LocalDateTime.now();
entity.setCreateBy(currentUserId);
entity.setCreateTime(now);
entity.setUpdateBy(currentUserId);
entity.setUpdateTime(now);
// 保存到数据库
this.save(entity);
@ -208,6 +218,85 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
// 更新成员信息
BeanUtil.copyProperties(req, existingMember);
// 设置更新信息
existingMember.setUpdateBy(StpUtil.getLoginIdAsString());
existingMember.setUpdateTime(LocalDateTime.now());
this.updateById(existingMember);
// 返回更新后的成员信息
return getTeamMemberById(memberId);
}
@Override
public ProjectMemberResp updateTeamMember(String memberId, TeamMemberUpdateReq req) {
// 验证成员是否存在
ProjectMemberEntity existingMember = this.getById(memberId);
if (existingMember == null) {
throw new ServiceException("项目成员不存在");
}
// 更新成员信息 - 只更新非空字段保留原有值
if (StrUtil.isNotBlank(req.getTurbineId())) {
existingMember.setTurbineId(req.getTurbineId());
}
if (StrUtil.isNotBlank(req.getTaskGroupId())) {
existingMember.setTaskGroupId(req.getTaskGroupId());
}
if (StrUtil.isNotBlank(req.getTaskId())) {
existingMember.setTaskId(req.getTaskId());
}
if (StrUtil.isNotBlank(req.getRoleType())) {
existingMember.setRoleType(req.getRoleType());
}
if (StrUtil.isNotBlank(req.getJobCode())) {
existingMember.setJobCode(req.getJobCode());
}
if (StrUtil.isNotBlank(req.getJobDesc())) {
existingMember.setJobDesc(req.getJobDesc());
}
if (req.getJoinDate() != null) {
existingMember.setJoinDate(req.getJoinDate());
}
if (req.getLeaveDate() != null) {
existingMember.setLeaveDate(req.getLeaveDate());
}
if (StrUtil.isNotBlank(req.getStatus())) {
existingMember.setStatus(req.getStatus());
}
if (StrUtil.isNotBlank(req.getRemark())) {
existingMember.setRemark(req.getRemark());
}
// 验证关联数据是否存在只验证非空字段
validateUpdateTeamMemberRequest(req, existingMember);
// 如果更新了用户信息电话或邮箱同时更新用户表
if (StrUtil.isNotBlank(req.getPhone()) || StrUtil.isNotBlank(req.getEmail())) {
UserEntity user = userService.getById(existingMember.getUserId());
if (user != null) {
boolean needUpdateUser = false;
if (StrUtil.isNotBlank(req.getPhone())) {
user.setMobile(req.getPhone());
needUpdateUser = true;
}
if (StrUtil.isNotBlank(req.getEmail())) {
user.setEmail(req.getEmail());
needUpdateUser = true;
}
if (needUpdateUser) {
user.setUpdateBy(StpUtil.getLoginIdAsString());
user.setUpdateTime(LocalDateTime.now());
userService.updateById(user);
}
}
}
// 设置更新信息
existingMember.setUpdateBy(StpUtil.getLoginIdAsString());
existingMember.setUpdateTime(LocalDateTime.now());
this.updateById(existingMember);
// 返回更新后的成员信息
@ -271,6 +360,64 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
}
}
/**
* 验证更新团队成员请求参数只验证非空字段
*/
private void validateUpdateTeamMemberRequest(TeamMemberReq req, ProjectMemberEntity existingMember) {
// 验证机组是否存在如果指定了机组
if (StrUtil.isNotBlank(req.getTurbineId())) {
TurbineEntity turbine = turbineService.getById(req.getTurbineId());
if (turbine == null) {
throw new ServiceException("机组不存在");
}
}
// 验证任务组是否存在如果指定了任务组
if (StrUtil.isNotBlank(req.getTaskGroupId())) {
ProjectTaskGroupEntity taskGroup = projectTaskGroupService.getById(req.getTaskGroupId());
if (taskGroup == null) {
throw new ServiceException("任务组不存在");
}
}
// 验证任务是否存在如果指定了任务
if (StrUtil.isNotBlank(req.getTaskId())) {
ProjectTaskEntity task = projectTaskService.getById(req.getTaskId());
if (task == null) {
throw new ServiceException("任务不存在");
}
}
}
/**
* 验证更新团队成员请求参数只验证非空字段
*/
private void validateUpdateTeamMemberRequest(TeamMemberUpdateReq req, ProjectMemberEntity existingMember) {
// 验证机组是否存在如果指定了机组
if (StrUtil.isNotBlank(req.getTurbineId())) {
TurbineEntity turbine = turbineService.getById(req.getTurbineId());
if (turbine == null) {
throw new ServiceException("机组不存在");
}
}
// 验证任务组是否存在如果指定了任务组
if (StrUtil.isNotBlank(req.getTaskGroupId())) {
ProjectTaskGroupEntity taskGroup = projectTaskGroupService.getById(req.getTaskGroupId());
if (taskGroup == null) {
throw new ServiceException("任务组不存在");
}
}
// 验证任务是否存在如果指定了任务
if (StrUtil.isNotBlank(req.getTaskId())) {
ProjectTaskEntity task = projectTaskService.getById(req.getTaskId());
if (task == null) {
throw new ServiceException("任务不存在");
}
}
}
/**
* 根据成员ID获取成员信息
*/
@ -286,10 +433,17 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
// 查询并返回单个成员信息
List<ProjectMemberResp> list = this.baseMapper.queryTeamMembers(query);
return list.stream()
.filter(member -> member.getMemberId().equals(memberId))
ProjectMemberResp member = list.stream()
.filter(m -> m.getMemberId().equals(memberId))
.findFirst()
.orElse(null);
if (member != null) {
// 丰富成员信息
enrichMemberInfo(CollUtil.toList(member));
}
return member;
}
// ========================== 项目看板相关方法实现 ==========================
@ -300,11 +454,14 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
// 统计项目数量
resp.setTotalProjectsCount(projectService.count());
resp.setPendingProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 0).count());
resp.setInProgressProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 1).count());
resp.setCompletedProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 2).count());
resp.setAuditedProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 3).count());
resp.setAcceptedProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 4).count());
resp.setPendingProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 0).count()); // 未开工
resp.setPreparingProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 1).count()); // 筹备中
resp.setInProgressProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 2).count()); // 开工中
resp.setSuspendedProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 3).count()); // 暂停中
resp.setCompletedProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 4).count()); // 已完工
resp.setAcceptanceProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 5).count()); // 验收中
resp.setCollectionProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 6).count()); // 回款中
resp.setSettledProjectCount(projectService.lambdaQuery().eq(ProjectEntity::getStatus, 7).count()); // 已结算
// 统计机组数量
resp.setTotalTurbineCount(turbineService.count());
@ -336,11 +493,14 @@ public class ProjectMemberServiceImpl extends ServiceImpl<ProjectMemberMapper, P
ProjectKanbanDataResp resp = new ProjectKanbanDataResp();
// 获取各状态的项目列表
resp.setPendingProjects(getProjectKanbanItems(0));
resp.setInProgressProjects(getProjectKanbanItems(1));
resp.setCompletedProjects(getProjectKanbanItems(2));
resp.setAuditedProjects(getProjectKanbanItems(3));
resp.setAcceptedProjects(getProjectKanbanItems(4));
resp.setPendingProjects(getProjectKanbanItems(0)); // 未开工
resp.setPreparingProjects(getProjectKanbanItems(1)); // 筹备中
resp.setInProgressProjects(getProjectKanbanItems(2)); // 开工中
resp.setSuspendedProjects(getProjectKanbanItems(3)); // 暂停中
resp.setCompletedProjects(getProjectKanbanItems(4)); // 已完工
resp.setAcceptanceProjects(getProjectKanbanItems(5)); // 验收中
resp.setCollectionProjects(getProjectKanbanItems(6)); // 回款中
resp.setSettledProjects(getProjectKanbanItems(7)); // 已结算
return resp;
}

View File

@ -1,12 +1,15 @@
package com.dite.znpt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dite.znpt.constant.Message;
import com.dite.znpt.converts.Converts;
import com.dite.znpt.domain.entity.ProjectEntity;
import com.dite.znpt.domain.entity.ProjectTaskEntity;
import com.dite.znpt.domain.entity.UserEntity;
import com.dite.znpt.domain.vo.ProjectInitTaskReq;
import com.dite.znpt.domain.vo.ProjectListReq;
import com.dite.znpt.domain.vo.ProjectListResp;
import com.dite.znpt.domain.vo.ProjectReq;
@ -16,6 +19,7 @@ import com.dite.znpt.exception.ServiceException;
import com.dite.znpt.mapper.ProjectMapper;
import com.dite.znpt.service.ProjectService;
import com.dite.znpt.service.UserService;
import com.dite.znpt.service.ProjectTaskService;
import com.dite.znpt.util.PageUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -40,6 +44,9 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, ProjectEntity
@Resource
private UserService userService;
@Resource
private ProjectTaskService projectTaskService;
/**
* 功能描述查询项目信息列表
*
@ -128,6 +135,11 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, ProjectEntity
public void save(ProjectReq req) {
ProjectEntity entity = Converts.INSTANCE.toProjectEntity(req);
this.save(entity);
for (ProjectInitTaskReq taskReq : req.getTasks()) {
ProjectTaskEntity taskEntity = BeanUtil.copyProperties(taskReq, ProjectTaskEntity.class);
taskEntity.setProjectId(entity.getProjectId());
projectTaskService.save(taskEntity);
}
}
/**

View File

@ -2,9 +2,11 @@ package com.dite.znpt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dite.znpt.constant.Message;
import com.dite.znpt.domain.entity.AttachInfoEntity;
@ -19,11 +21,13 @@ import com.dite.znpt.exception.ServiceException;
import com.dite.znpt.mapper.ProjectTaskGroupMapper;
import com.dite.znpt.mapper.ProjectTaskMapper;
import com.dite.znpt.service.AttachInfoService;
import com.dite.znpt.service.ProjectService;
import com.dite.znpt.service.ProjectTaskService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
@ -41,6 +45,9 @@ public class ProjectTaskServiceImpl extends ServiceImpl<ProjectTaskMapper, Proje
private final AttachInfoService attachInfoService;
private final ProjectTaskGroupMapper projectTaskGroupMapper;
@Resource
private ProjectService projectService;
/**
* 功能描述查询项目任务信息列表
*
@ -265,4 +272,17 @@ public class ProjectTaskServiceImpl extends ServiceImpl<ProjectTaskMapper, Proje
});
baseMapper.updateById(list);
}
}
@Override
public List<ProjectTaskResp> getTaskByProjectId(String projectId) {
QueryWrapper<ProjectTaskEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("project_id", projectId);
List<ProjectTaskEntity> list = baseMapper.selectList(queryWrapper);
if (CollectionUtil.isEmpty(list)) {
return Collections.emptyList(); // 返回不可修改的空集合
}
String projectName = projectService.getById(projectId).getProjectName();
List<ProjectTaskResp> respList = list.stream().map(item -> BeanUtil.copyProperties(item, ProjectTaskResp.class)).toList();
return respList;
}
}

View File

@ -206,7 +206,7 @@ public class TurbineServiceImpl extends ServiceImpl<TurbineMapper, TurbineEntity
if (turbine == null) {
return;
}
if (turbine.getStatus() == ProjectStatusEnum.AUDITED.getCode()) {
if (turbine.getStatus() == ProjectStatusEnum.PREPARING.getCode()) {
return;
}
List<TurbineStatusResp> turbineStatusList = jobService.calCrewStatus(ListUtil.of(turbineId));
@ -234,7 +234,7 @@ public class TurbineServiceImpl extends ServiceImpl<TurbineMapper, TurbineEntity
&& status4.contains(turbineStatusVo.getAntiThunderWorkStatus())
&& status4.contains(turbineStatusVo.getSummaryWorkStatus())) {
// 全部审批已审批
turbine.setStatus(ProjectStatusEnum.AUDITED.getCode());
turbine.setStatus(ProjectStatusEnum.PREPARING.getCode());
} else if (status2.contains(turbineStatusVo.getInWorkStatus())
|| status2.contains(turbineStatusVo.getOutWorkStatus())
|| status2.contains(turbineStatusVo.getAntiThunderWorkStatus())
@ -267,12 +267,12 @@ public class TurbineServiceImpl extends ServiceImpl<TurbineMapper, TurbineEntity
if (!statusList.contains(ProjectStatusEnum.PENDING.getCode()) &&
!statusList.contains(ProjectStatusEnum.IN_PROGRESS.getCode())) {
status = ProjectStatusEnum.COMPLETED.getCode();
// 如果机组列表没有状态为 待施工施工中已完工 的则项目 已审核
// 如果机组列表没有状态为 待施工施工中已完工 的则项目 筹备中
if (!statusList.contains(ProjectStatusEnum.COMPLETED.getCode())) {
status = ProjectStatusEnum.AUDITED.getCode();
// 如果机组列表没有状态为 待施工施工中已完工已审核 的则项目 已验收
if (!statusList.contains(ProjectStatusEnum.AUDITED.getCode())) {
status = ProjectStatusEnum.ACCEPTED.getCode();
status = ProjectStatusEnum.PREPARING.getCode();
// 如果机组列表没有状态为 待施工施工中已完工筹备中 的则项目 验收中
if (!statusList.contains(ProjectStatusEnum.PREPARING.getCode())) {
status = ProjectStatusEnum.IN_ACCEPTANCE.getCode();
}
}
}

View File

@ -0,0 +1,96 @@
package com.dite.znpt.websocket;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
/**
* 简单的WebSocket处理器
*/
@Component
public class SimpleWebSocketHandler implements WebSocketHandler {
// 存储所有连接的会话
private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String sessionId = session.getId();
sessions.put(sessionId, session);
System.out.println("WebSocket连接建立sessionId: " + sessionId);
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
// 处理接收到的消息
System.out.println("收到WebSocket消息: " + message.getPayload());
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.err.println("WebSocket传输错误sessionId: " + session.getId());
exception.printStackTrace();
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
String sessionId = session.getId();
sessions.remove(sessionId);
System.out.println("WebSocket连接关闭sessionId: " + sessionId);
}
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 发送简单消息给所有连接的客户端
*/
public static void sendMessageToAll(String message) {
System.out.println("准备发送WebSocket消息给 " + sessions.size() + " 个连接的客户端");
System.out.println("消息内容: " + message);
final int[] successCount = {0};
final int[] failCount = {0};
sessions.values().forEach(session -> {
try {
if (session.isOpen()) {
session.sendMessage(new TextMessage(message));
successCount[0]++;
System.out.println("成功发送消息给sessionId: " + session.getId());
} else {
System.out.println("跳过已关闭的sessionId: " + session.getId());
}
} catch (IOException e) {
failCount[0]++;
System.err.println("发送消息失败sessionId: " + session.getId());
e.printStackTrace();
}
});
System.out.println("WebSocket消息发送完成 - 成功: " + successCount[0] + ", 失败: " + failCount[0]);
}
/**
* 发送采购申请通知
*/
public static void sendProcurementNotification(String equipmentName, String applicantName) {
String notificationMessage = String.format(
"{\"type\":\"PROCUREMENT_APPLICATION\",\"title\":\"新的采购申请\",\"content\":\"收到来自 %s 的设备采购申请:%s\"}",
applicantName, equipmentName
);
System.out.println("=== 发送采购申请通知 ===");
System.out.println("设备名称: " + equipmentName);
System.out.println("申请人: " + applicantName);
System.out.println("通知消息: " + notificationMessage);
System.out.println("当前连接数: " + sessions.size());
sendMessageToAll(notificationMessage);
}
}

View File

@ -6,6 +6,7 @@ import com.dite.znpt.domain.Result;
import com.dite.znpt.domain.vo.EquipmentApprovalListReq;
import com.dite.znpt.domain.vo.EquipmentApprovalReq;
import com.dite.znpt.domain.vo.EquipmentApprovalResp;
import com.dite.znpt.domain.vo.EquipmentProcurementApplyReq;
import com.dite.znpt.service.EquipmentApprovalService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -34,6 +35,21 @@ public class EquipmentApprovalController {
@ApiOperation(value = "分页查询待审批的设备采购申请", httpMethod = "GET")
@GetMapping("/pending")
public PageResult<EquipmentApprovalResp> getPendingApprovals(EquipmentApprovalListReq req) {
log.info("=== 设备审批待审批查询接口被调用 ===");
log.info("接收到的请求参数: {}", req);
log.info("设备名称: {}", req.getEquipmentName());
log.info("申请人: {}", req.getApplicantName());
log.info("业务类型: {}", req.getBusinessType());
log.info("审批状态: {}", req.getApprovalStatus());
log.info("申请时间开始: {}", req.getApplyTimeStart());
log.info("申请时间结束: {}", req.getApplyTimeEnd());
log.info("审批时间开始: {}", req.getApprovalTimeStart());
log.info("审批时间结束: {}", req.getApprovalTimeEnd());
log.info("页码: {}", req.getPage());
log.info("每页大小: {}", req.getPageSize());
log.info("排序字段: {}", req.getOrderBy());
log.info("排序方向: {}", req.getOrderDirection());
IPage<EquipmentApprovalResp> page = equipmentApprovalService.getPendingApprovals(req);
return PageResult.ok(page.getRecords(), page.getTotal());
}
@ -41,6 +57,21 @@ public class EquipmentApprovalController {
@ApiOperation(value = "分页查询已审批的设备采购申请", httpMethod = "GET")
@GetMapping("/approved")
public PageResult<EquipmentApprovalResp> getApprovedApprovals(EquipmentApprovalListReq req) {
log.info("=== 设备审批已审批查询接口被调用 ===");
log.info("接收到的请求参数: {}", req);
log.info("设备名称: {}", req.getEquipmentName());
log.info("申请人: {}", req.getApplicantName());
log.info("业务类型: {}", req.getBusinessType());
log.info("审批状态: {}", req.getApprovalStatus());
log.info("申请时间开始: {}", req.getApplyTimeStart());
log.info("申请时间结束: {}", req.getApplyTimeEnd());
log.info("审批时间开始: {}", req.getApprovalTimeStart());
log.info("审批时间结束: {}", req.getApprovalTimeEnd());
log.info("页码: {}", req.getPage());
log.info("每页大小: {}", req.getPageSize());
log.info("排序字段: {}", req.getOrderBy());
log.info("排序方向: {}", req.getOrderDirection());
IPage<EquipmentApprovalResp> page = equipmentApprovalService.getApprovedApprovals(req);
return PageResult.ok(page.getRecords(), page.getTotal());
}
@ -70,4 +101,38 @@ public class EquipmentApprovalController {
public Result<?> getApprovalStats() {
return Result.ok(equipmentApprovalService.getApprovalStats());
}
@ApiOperation(value = "提交采购申请", httpMethod = "POST")
@PostMapping("/procurement/apply")
public Result<?> submitProcurementApplication(@Validated @RequestBody EquipmentProcurementApplyReq req) {
log.info("=== 提交采购申请接口被调用 ===");
log.info("接收到的请求参数: {}", req);
log.info("设备名称: {}", req.getEquipmentName());
log.info("设备类型: {}", req.getEquipmentType());
log.info("预算金额: {}", req.getBudgetAmount());
log.info("申请原因: {}", req.getApplyReason());
equipmentApprovalService.submitProcurementApplication(req);
return Result.ok();
}
@ApiOperation(value = "获取我的采购申请", httpMethod = "GET")
@GetMapping("/procurement/my-applications")
public PageResult<EquipmentApprovalResp> getMyProcurementApplications(EquipmentApprovalListReq req) {
log.info("=== 获取我的采购申请接口被调用 ===");
log.info("接收到的请求参数: {}", req);
IPage<EquipmentApprovalResp> page = equipmentApprovalService.getMyProcurementApplications(req);
return PageResult.ok(page.getRecords(), page.getTotal());
}
@ApiOperation(value = "撤回采购申请", httpMethod = "POST")
@PostMapping("/procurement/{approvalId}/withdraw")
public Result<?> withdrawProcurementApplication(@PathVariable String approvalId) {
log.info("=== 撤回采购申请接口被调用 ===");
log.info("审批ID: {}", approvalId);
equipmentApprovalService.withdrawProcurementApplication(approvalId);
return Result.ok();
}
}

View File

@ -2,12 +2,12 @@ package com.dite.znpt.web.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dite.znpt.constant.Constants;
import com.dite.znpt.domain.vo.ProjectListReq;
import com.dite.znpt.domain.vo.ProjectListResp;
import com.dite.znpt.domain.vo.ProjectReq;
import com.dite.znpt.domain.vo.ProjectResp;
import com.dite.znpt.domain.entity.EquipmentEntity;
import com.dite.znpt.domain.vo.*;
import com.dite.znpt.domain.entity.ProjectEntity;
import com.dite.znpt.service.EquipmentService;
import com.dite.znpt.service.ProjectService;
import com.dite.znpt.domain.Result;
import com.dite.znpt.domain.PageResult;
@ -35,6 +35,9 @@ public class ProjectController {
@Resource
private ProjectService projectService;
@Resource
private EquipmentService equipmentService;
@ApiOperation(value = "分页查询项目信息列表", httpMethod = "GET")
@GetMapping("/page")
public PageResult<ProjectListResp> page(ProjectListReq req) {
@ -100,5 +103,13 @@ public class ProjectController {
return Result.ok(projectService.list(req));
}
}
@ApiOperation(value = "查询项目下的设备列表", httpMethod = "GET")
@GetMapping("/{projectId}/equipments")
public Result<List<EquipmentEntity>> equipments(@PathVariable String projectId) {
QueryWrapper<EquipmentEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("del_flag", Constants.DEL_FLAG_0);
queryWrapper.eq("use_status", "1");
queryWrapper.eq("project_id", projectId);
return Result.ok(equipmentService.list(queryWrapper));
}
}

View File

@ -45,7 +45,7 @@ public class ProjectMemberController {
@PutMapping("/team-member/{memberId}")
public Result<ProjectMemberResp> updateTeamMember(
@PathVariable String memberId,
@Valid @RequestBody TeamMemberReq req) {
@RequestBody TeamMemberUpdateReq req) {
return Result.ok(projectMemberService.updateTeamMember(memberId, req));
}

View File

@ -2,10 +2,14 @@ package com.dite.znpt.web.controller;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dite.znpt.constant.Constants;
import com.dite.znpt.domain.PageResult;
import com.dite.znpt.domain.Result;
import com.dite.znpt.domain.entity.ProjectTaskEntity;
import com.dite.znpt.domain.vo.*;
import com.dite.znpt.service.ProjectService;
import com.dite.znpt.service.ProjectTaskService;
import com.dite.znpt.util.PageUtil;
import com.dite.znpt.util.ValidationGroup;
@ -19,6 +23,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
@ -32,6 +37,9 @@ public class ProjectTaskController {
@Resource
private ProjectTaskService projectTaskService;
@Resource
private ProjectService projectService;
@ApiOperation(value = "获取项目任务信息列表", httpMethod = "GET")
@GetMapping("/list")
public PageResult<ProjectTaskResp> list(ProjectTaskListReq projectTaskReq) {
@ -105,5 +113,15 @@ public class ProjectTaskController {
req.setUserId(StpUtil.getLoginIdAsString());
return Result.ok(projectTaskService.selectList(req));
}
}
@ApiOperation(value = "根据项目id查询任务列表", httpMethod = "GET")
@GetMapping("/{projectId}/tasks")
public Result<ProjectTasksDetailResp> getTaskByProjectId(@PathVariable String projectId) {
ProjectTasksDetailResp resp = new ProjectTasksDetailResp();
resp.setProjectName(projectService.getById(projectId).getProjectName());
resp.setList(projectTaskService.getTaskByProjectId(projectId));
resp.setTotal(resp.getList().size());
resp.setFinished((int) resp.getList().stream().filter(projectTaskResp -> projectTaskResp.getStatus() == 2).count());
return Result.ok(resp);
}
}

View File

@ -79,5 +79,13 @@ public class UserController {
userService.deleteById(userId);
return Result.ok();
}
@ApiOperation(value = "根据姓名模糊查询用户", httpMethod = "GET")
@GetMapping("/searchByName")
public PageResult<UserListResp> searchByName(@RequestParam String name) {
UserListReq req = new UserListReq();
req.setName(name);
return PageResult.ok(userService.list(req));
}
}

View File

@ -14,7 +14,7 @@ spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://39.99.201.243:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://39.99.201.243:3306/znpt_dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: BUw8YW6%@^8q
druid: