diff --git a/core/src/main/java/com/dite/znpt/domain/entity/EquipmentEntity.java b/core/src/main/java/com/dite/znpt/domain/entity/EquipmentEntity.java index 642ee6e..79afc9f 100644 --- a/core/src/main/java/com/dite/znpt/domain/entity/EquipmentEntity.java +++ b/core/src/main/java/com/dite/znpt/domain/entity/EquipmentEntity.java @@ -180,6 +180,12 @@ public class EquipmentEntity extends AuditableEntity implements Serializable { @ApiModelProperty("采购状态,NOT_STARTED-未开始,PENDING_APPROVAL-待审批,APPROVED-已通过,REJECTED-已拒绝,COMPLETED-已完成") private String procurementStatus; + @ApiModelProperty("收货状态,NOT_RECEIVED-未收货,PARTIALLY_RECEIVED-部分收货,RECEIVED-已收货") + private String receiptStatus; + + @ApiModelProperty("支付状态,NOT_PAID-未支付,PARTIALLY_PAID-部分支付,PAID-已支付") + private String paymentStatus; + @ApiModelProperty("附件") private String attachments; diff --git a/core/src/main/java/com/dite/znpt/domain/vo/EquipmentResp.java b/core/src/main/java/com/dite/znpt/domain/vo/EquipmentResp.java index 04642f2..e0529f5 100644 --- a/core/src/main/java/com/dite/znpt/domain/vo/EquipmentResp.java +++ b/core/src/main/java/com/dite/znpt/domain/vo/EquipmentResp.java @@ -157,6 +157,15 @@ public class EquipmentResp implements Serializable { @ApiModelProperty("采购状态,NOT_STARTED-未开始,PENDING_APPROVAL-待审批,APPROVED-已通过,REJECTED-已拒绝,COMPLETED-已完成") private String procurementStatus; + @ApiModelProperty("收货状态,NOT_RECEIVED-未收货,PARTIALLY_RECEIVED-部分收货,RECEIVED-已收货") + private String receiptStatus; + + @ApiModelProperty("支付状态,NOT_PAID-未支付,PARTIALLY_PAID-部分支付,PAID-已支付") + private String paymentStatus; + + @ApiModelProperty("审批状态,PENDING-待审批,APPROVED-已通过,REJECTED-已拒绝") + private String approvalStatus; + // 移除备用状态字段,使用现有的 location_status 字段 // @ApiModelProperty("备用状态") // private String spareStatus; diff --git a/core/src/main/java/com/dite/znpt/domain/vo/GanttChartReq.java b/core/src/main/java/com/dite/znpt/domain/vo/GanttChartReq.java new file mode 100644 index 0000000..7e96367 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/domain/vo/GanttChartReq.java @@ -0,0 +1,45 @@ +package com.dite.znpt.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDate; + +/** + * 甘特图查询请求类 + */ +@Data +@ApiModel(value = "GanttChartReq", description = "甘特图查询请求") +public class GanttChartReq { + + @ApiModelProperty("项目ID") + private String projectId; + + @ApiModelProperty("任务组ID") + private String taskGroupId; + + @ApiModelProperty("任务状态") + private Integer status; + + @ApiModelProperty("负责人ID") + private String mainUserId; + + @ApiModelProperty("开始时间范围-开始") + private LocalDate startDateFrom; + + @ApiModelProperty("开始时间范围-结束") + private LocalDate startDateTo; + + @ApiModelProperty("结束时间范围-开始") + private LocalDate endDateFrom; + + @ApiModelProperty("结束时间范围-结束") + private LocalDate endDateTo; + + @ApiModelProperty("是否包含已完成任务") + private Boolean includeCompleted = true; + + @ApiModelProperty("是否只显示逾期任务") + private Boolean overdueOnly = false; +} diff --git a/core/src/main/java/com/dite/znpt/domain/vo/GanttChartResp.java b/core/src/main/java/com/dite/znpt/domain/vo/GanttChartResp.java new file mode 100644 index 0000000..69e38a0 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/domain/vo/GanttChartResp.java @@ -0,0 +1,91 @@ +package com.dite.znpt.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +/** + * 甘特图数据响应类 + */ +@Data +@ApiModel(value = "GanttChartResp", description = "甘特图数据响应") +public class GanttChartResp { + + @ApiModelProperty("任务ID") + private String taskId; + + @ApiModelProperty("任务名称") + private String taskName; + + @ApiModelProperty("任务编号") + private String taskCode; + + @ApiModelProperty("上级任务ID") + private String parentTaskId; + + @ApiModelProperty("任务组ID") + private String taskGroupId; + + @ApiModelProperty("任务组名称") + private String taskGroupName; + + @ApiModelProperty("计划开始时间") + private LocalDate planStartDate; + + @ApiModelProperty("计划结束时间") + private LocalDate planEndDate; + + @ApiModelProperty("实际开始时间") + private LocalDate actualStartDate; + + @ApiModelProperty("实际结束时间") + private LocalDate actualEndDate; + + @ApiModelProperty("任务状态:0未开始,1进行中,2已结束") + private Integer status; + + @ApiModelProperty("任务状态描述") + private String statusDesc; + + @ApiModelProperty("是否逾期:0未逾期,1已逾期") + private Integer overdueStatus; + + @ApiModelProperty("任务负责人ID") + private String mainUserId; + + @ApiModelProperty("任务负责人姓名") + private String mainUserName; + + @ApiModelProperty("任务参与人") + private String userIds; + + @ApiModelProperty("任务参与人姓名列表") + private List participantNames; + + @ApiModelProperty("进度百分比") + private Integer progress; + + @ApiModelProperty("任务层级") + private Integer level; + + @ApiModelProperty("任务在时间轴上的位置(天数)") + private Integer position; + + @ApiModelProperty("任务持续时间(天数)") + private Integer duration; + + @ApiModelProperty("子任务列表") + private List children; + + @ApiModelProperty("任务备注") + private String remark; + + @ApiModelProperty("项目ID") + private String projectId; + + @ApiModelProperty("项目名称") + private String projectName; +} diff --git a/core/src/main/java/com/dite/znpt/domain/vo/ReceiptRequest.java b/core/src/main/java/com/dite/znpt/domain/vo/ReceiptRequest.java new file mode 100644 index 0000000..8892e98 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/domain/vo/ReceiptRequest.java @@ -0,0 +1,160 @@ +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; + +/** + * 收货请求参数(扩展版,包含完整设备信息) + * + * @author system + * @date 2025-01-08 + */ +@Data +@ApiModel(value = "收货请求参数", description = "收货请求参数,包含收货信息和设备信息") +public class ReceiptRequest { + + @ApiModelProperty("设备序列号(收货时自动生成)") + private String equipmentSn; + + @ApiModelProperty("库存条码(收货时自动生成)") + private String inventoryBarcode; + + // 收货特有信息 + @NotBlank(message = "收货时间不能为空") + @ApiModelProperty("收货时间") + private String receiptTime; + + @NotBlank(message = "收货人不能为空") + @ApiModelProperty("收货人") + private String receiptPerson; + + @NotNull(message = "收货数量不能为空") + @ApiModelProperty("收货数量") + private Integer receiptQuantity; + + @ApiModelProperty("收货备注") + private String receiptRemark; + + @NotBlank(message = "外观检查结果不能为空") + @ApiModelProperty("外观检查结果") + private String appearanceCheck; + + @NotBlank(message = "功能测试结果不能为空") + @ApiModelProperty("功能测试结果") + private String functionTest; + + @NotBlank(message = "包装完整性不能为空") + @ApiModelProperty("包装完整性") + private String packageIntegrity; + + @NotBlank(message = "配件完整性不能为空") + @ApiModelProperty("配件完整性") + private String accessoryIntegrity; + + @NotBlank(message = "检查结果不能为空") + @ApiModelProperty("检查结果") + private String checkResult; + + @ApiModelProperty("检查备注") + private String checkRemark; + + @NotBlank(message = "入库位置不能为空") + @ApiModelProperty("入库位置") + private String storageLocation; + + @NotBlank(message = "库管员不能为空") + @ApiModelProperty("库管员") + private String storageManager; + + // 设备基本信息(从采购数据继承) + @ApiModelProperty("设备名称") + private String equipmentName; + + @ApiModelProperty("设备型号") + private String equipmentModel; + + @ApiModelProperty("设备类型") + private String equipmentType; + + @ApiModelProperty("品牌") + private String brand; + + @ApiModelProperty("配置规格/参数") + private String specification; + + @ApiModelProperty("资产编号") + private String assetCode; + + // 采购信息(从采购数据继承) + @ApiModelProperty("采购订单号") + private String purchaseOrder; + + @ApiModelProperty("供应商名称") + private String supplierName; + + @ApiModelProperty("采购价格") + private BigDecimal purchasePrice; + + @ApiModelProperty("采购时间") + private String purchaseTime; + + @ApiModelProperty("数量") + private Integer quantity; + + @ApiModelProperty("单价") + private BigDecimal unitPrice; + + @ApiModelProperty("总价") + private BigDecimal totalPrice; + + // 入库信息 + @ApiModelProperty("入库时间") + private String inStockTime; + + @ApiModelProperty("物理位置") + private String physicalLocation; + + @ApiModelProperty("位置状态") + private String locationStatus; + + @ApiModelProperty("负责人") + private String responsiblePerson; + + // 状态信息 + @ApiModelProperty("设备状态") + private String equipmentStatus; + + @ApiModelProperty("使用状态") + private String useStatus; + + @ApiModelProperty("健康状态") + private String healthStatus; + + @ApiModelProperty("收货状态") + private String receiptStatus; + + // 其他管理信息 + @ApiModelProperty("折旧方法") + private String depreciationMethod; + + @ApiModelProperty("折旧年限") + private Integer depreciationYears; + + @ApiModelProperty("残值") + private BigDecimal salvageValue; + + @ApiModelProperty("当前净值") + private BigDecimal currentNetValue; + + // 系统字段 + @ApiModelProperty("创建时间") + private String createTime; + + @ApiModelProperty("更新时间") + private String updateTime; +} diff --git a/core/src/main/java/com/dite/znpt/enums/PaymentStatusEnum.java b/core/src/main/java/com/dite/znpt/enums/PaymentStatusEnum.java new file mode 100644 index 0000000..27a8dcf --- /dev/null +++ b/core/src/main/java/com/dite/znpt/enums/PaymentStatusEnum.java @@ -0,0 +1,52 @@ +package com.dite.znpt.enums; + +import cn.hutool.json.JSONObject; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 支付状态枚举 + * + * @author system + * @date 2025-01-08 + */ +@Getter +public enum PaymentStatusEnum { + NOT_PAID("NOT_PAID", "未支付"), + PARTIALLY_PAID("PARTIALLY_PAID", "部分支付"), + PAID("PAID", "已支付"); + + private final String code; + private final String desc; + + PaymentStatusEnum(String code, String desc) { + this.code = code; + this.desc = desc; + } + + public static PaymentStatusEnum getByCode(String code) { + for (PaymentStatusEnum e : PaymentStatusEnum.values()) { + if (e.code.equals(code)) { + return e; + } + } + return null; + } + + public static String getDescByCode(String code) { + PaymentStatusEnum e = getByCode(code); + return null == e ? null : e.desc; + } + + public static List listAll() { + List list = new ArrayList<>(PaymentStatusEnum.values().length); + for (PaymentStatusEnum e : PaymentStatusEnum.values()) { + JSONObject jsonObject = new JSONObject(); + jsonObject.set(e.code, e.desc); + list.add(jsonObject); + } + return list; + } +} diff --git a/core/src/main/java/com/dite/znpt/enums/ReceiptStatusEnum.java b/core/src/main/java/com/dite/znpt/enums/ReceiptStatusEnum.java new file mode 100644 index 0000000..b2174bc --- /dev/null +++ b/core/src/main/java/com/dite/znpt/enums/ReceiptStatusEnum.java @@ -0,0 +1,52 @@ +package com.dite.znpt.enums; + +import cn.hutool.json.JSONObject; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 收货状态枚举 + * + * @author system + * @date 2025-01-08 + */ +@Getter +public enum ReceiptStatusEnum { + NOT_RECEIVED("NOT_RECEIVED", "未收货"), + PARTIALLY_RECEIVED("PARTIALLY_RECEIVED", "部分收货"), + RECEIVED("RECEIVED", "已收货"); + + private final String code; + private final String desc; + + ReceiptStatusEnum(String code, String desc) { + this.code = code; + this.desc = desc; + } + + public static ReceiptStatusEnum getByCode(String code) { + for (ReceiptStatusEnum e : ReceiptStatusEnum.values()) { + if (e.code.equals(code)) { + return e; + } + } + return null; + } + + public static String getDescByCode(String code) { + ReceiptStatusEnum e = getByCode(code); + return null == e ? null : e.desc; + } + + public static List listAll() { + List list = new ArrayList<>(ReceiptStatusEnum.values().length); + for (ReceiptStatusEnum e : ReceiptStatusEnum.values()) { + JSONObject jsonObject = new JSONObject(); + jsonObject.set(e.code, e.desc); + list.add(jsonObject); + } + return list; + } +} diff --git a/core/src/main/java/com/dite/znpt/mapper/BusinessDataFileMapper.java b/core/src/main/java/com/dite/znpt/mapper/BusinessDataFileMapper.java index 0fa1dd8..930d70d 100644 --- a/core/src/main/java/com/dite/znpt/mapper/BusinessDataFileMapper.java +++ b/core/src/main/java/com/dite/znpt/mapper/BusinessDataFileMapper.java @@ -36,4 +36,15 @@ public interface BusinessDataFileMapper { @Param("newFileName") String newFileName, @Param("newFilePath") String newFilePath); +// // 批量更新文件路径 +// void updateFilePathByFolderId( +// @Param("folderId") Long folderId, +// @Param("newFolderPath") String newFolderPath, +// @Param("separator") String separator); + + // 批量更新子文件夹下文件的路径 + void updateSubFilePaths(@Param("oldParentPath1") String oldParentPath1, + @Param("newParentPath1") String newParentPath1, + @Param("oldParentPath2") String oldParentPath2 + ); } diff --git a/core/src/main/java/com/dite/znpt/mapper/BusinessDataMapper.java b/core/src/main/java/com/dite/znpt/mapper/BusinessDataMapper.java index b7e4bae..f8d2d80 100644 --- a/core/src/main/java/com/dite/znpt/mapper/BusinessDataMapper.java +++ b/core/src/main/java/com/dite/znpt/mapper/BusinessDataMapper.java @@ -29,4 +29,12 @@ public interface BusinessDataMapper { void reName(BusinessDataEntity businessDataEntity); public List ListWithCondition(@Param("folderName") String folderName); + + // 批量更新子文件夹路径 + void updateSubFolderPaths(@Param("oldParentPath1") String oldParentPath, + @Param("newParentPath1") String newParentPath, + @Param("processedOldParentPath") String processedOldParentPath, + @Param("processedNewParentPath") String processedNewParentPath, + @Param("folderId") Long folderId + ); } diff --git a/core/src/main/java/com/dite/znpt/mapper/ProjectTaskMapper.java b/core/src/main/java/com/dite/znpt/mapper/ProjectTaskMapper.java index afb1d09..4101f84 100644 --- a/core/src/main/java/com/dite/znpt/mapper/ProjectTaskMapper.java +++ b/core/src/main/java/com/dite/znpt/mapper/ProjectTaskMapper.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.dite.znpt.domain.entity.ProjectTaskEntity; import com.dite.znpt.domain.vo.ProjectTaskListReq; import com.dite.znpt.domain.vo.ProjectTaskResp; +import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -13,6 +14,7 @@ import java.util.List; * @date 2025/06/24 16:44 * @Description: 项目任务信息表数据库访问层 */ +@Mapper public interface ProjectTaskMapper extends BaseMapper { List queryBySelective(ProjectTaskListReq projectTaskReq); diff --git a/core/src/main/java/com/dite/znpt/service/BusinessDataFileService.java b/core/src/main/java/com/dite/znpt/service/BusinessDataFileService.java index b4af5dc..d82cb53 100644 --- a/core/src/main/java/com/dite/znpt/service/BusinessDataFileService.java +++ b/core/src/main/java/com/dite/znpt/service/BusinessDataFileService.java @@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; +import java.io.File; @ApiOperation("商务资料文件service") @Service @@ -40,4 +41,11 @@ public interface BusinessDataFileService { @ApiOperation("预览文件") void preview(Long fileId, HttpServletResponse response); + +// @ApiOperation("批量更新文件路径") +// public void updateFilePathByFolderId(Long folderId, String newFolderPath); + + @ApiOperation("批量更新子文件夹下文件的路径") + void updateSubFilePaths(String oldParentPath, String newParentPath); + } diff --git a/core/src/main/java/com/dite/znpt/service/BusinessDataService.java b/core/src/main/java/com/dite/znpt/service/BusinessDataService.java index f4a826c..90fabda 100644 --- a/core/src/main/java/com/dite/znpt/service/BusinessDataService.java +++ b/core/src/main/java/com/dite/znpt/service/BusinessDataService.java @@ -15,4 +15,6 @@ public interface BusinessDataService { Result delete(Long folderId); Result reName(Long folderId, String newName); + void updateSubFolderPaths(String oldParentPath1, String newParentPath1, Long folderId); + } diff --git a/core/src/main/java/com/dite/znpt/service/EquipmentService.java b/core/src/main/java/com/dite/znpt/service/EquipmentService.java index 0697362..dbded87 100644 --- a/core/src/main/java/com/dite/znpt/service/EquipmentService.java +++ b/core/src/main/java/com/dite/znpt/service/EquipmentService.java @@ -6,6 +6,7 @@ import com.dite.znpt.domain.entity.EquipmentEntity; import com.dite.znpt.domain.vo.EquipmentListReq; import com.dite.znpt.domain.vo.EquipmentReq; import com.dite.znpt.domain.vo.EquipmentResp; +import com.dite.znpt.domain.vo.ReceiptRequest; import java.util.List; import java.util.Map; @@ -53,6 +54,11 @@ public interface EquipmentService extends IService { */ Object getProcurementStats(); + /** + * 确认收货并自动入库 + */ + void receiveGoodsAndStockIn(String equipmentId, ReceiptRequest req); + /** * 导出采购记录 */ diff --git a/core/src/main/java/com/dite/znpt/service/GanttChartService.java b/core/src/main/java/com/dite/znpt/service/GanttChartService.java new file mode 100644 index 0000000..d3e1c26 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/service/GanttChartService.java @@ -0,0 +1,55 @@ +package com.dite.znpt.service; + +import com.dite.znpt.domain.vo.GanttChartReq; +import com.dite.znpt.domain.vo.GanttChartResp; + +import java.util.List; + +/** + * 甘特图服务接口 + */ +public interface GanttChartService { + + /** + * 获取项目甘特图数据 + * + * @param req 查询条件 + * @return 甘特图数据列表 + */ + List getGanttChartData(GanttChartReq req); + + /** + * 获取项目甘特图统计信息 + * + * @param projectId 项目ID + * @return 统计信息 + */ + Object getGanttChartStatistics(String projectId); + + /** + * 获取项目甘特图时间轴信息 + * + * @param projectId 项目ID + * @return 时间轴信息 + */ + Object getGanttChartTimeline(String projectId); + + /** + * 更新任务进度 + * + * @param taskId 任务ID + * @param progress 进度百分比 + * @return 是否成功 + */ + boolean updateTaskProgress(String taskId, Integer progress); + + /** + * 拖拽更新任务时间 + * + * @param taskId 任务ID + * @param startDate 开始时间 + * @param endDate 结束时间 + * @return 是否成功 + */ + boolean updateTaskTime(String taskId, String startDate, String endDate); +} diff --git a/core/src/main/java/com/dite/znpt/service/impl/BusinessDataFileServiceImpl.java b/core/src/main/java/com/dite/znpt/service/impl/BusinessDataFileServiceImpl.java index 6cfe2f6..0c6e2a9 100644 --- a/core/src/main/java/com/dite/znpt/service/impl/BusinessDataFileServiceImpl.java +++ b/core/src/main/java/com/dite/znpt/service/impl/BusinessDataFileServiceImpl.java @@ -81,7 +81,8 @@ public class BusinessDataFileServiceImpl implements BusinessDataFileService { } @ApiOperation("删除文件") public Result delete(Long fileId, Long folderId) { - //删除数据库数据 + //删除文件夹时候,调用这个方法,才会删除所有文件的数据库数据, + // 至于具体文件,不用在这个方法删除 if (folderId != null){ businessDataFileMapper.delete(null,folderId); return Result.okM("删除成功"); @@ -155,8 +156,11 @@ public class BusinessDataFileServiceImpl implements BusinessDataFileService { } // 构建新文件路径 + // 获取父目录 String parentPath = oldFile.getParent(); + // 获取文件扩展名 String fileExtension = ""; + // 获取文件名(不包含扩展名) String fileNameWithoutExt = newFileName; // 获取原文件扩展名 @@ -246,7 +250,7 @@ public class BusinessDataFileServiceImpl implements BusinessDataFileService { byte[] bytes = file.getBytes(); String uploadDir = businessDataService.getPath(folderId); - File uploadedFile = new File(uploadDir + "/" + file.getOriginalFilename()); + File uploadedFile = new File(uploadDir + File.separator + file.getOriginalFilename()); if (uploadedFile.exists()) { return Result.error("文件已存在"); } @@ -256,7 +260,7 @@ public class BusinessDataFileServiceImpl implements BusinessDataFileService { BusinessDataFileEntity fileEntity = new BusinessDataFileEntity(); fileEntity.setFolderId(folderId); fileEntity.setFileName(file.getOriginalFilename()); - fileEntity.setFilePath(uploadDir + "/" + file.getOriginalFilename()); + fileEntity.setFilePath(uploadDir + File.separator + file.getOriginalFilename()); fileEntity.setFileType(file.getContentType()); fileEntity.setFileSize(file.getSize()/1024); fileEntity.setUploadTime(new Date()); @@ -544,4 +548,21 @@ public class BusinessDataFileServiceImpl implements BusinessDataFileService { } } +// @ApiOperation("批量更新文件路径") +// @Override +// public void updateFilePathByFolderId(Long folderId, String newFolderPath) { +// businessDataFileMapper.updateFilePathByFolderId(folderId, newFolderPath, File.separator); +// } + + @ApiOperation("批量更新子文件夹下文件的路径") + @Override + public void updateSubFilePaths(String oldParentPath1, String newParentPath1) { + // 处理路径中的分隔符,如果是反斜杠则替换为双反斜杠 + String oldParentPath2 = oldParentPath1; + if ("\\".equals(File.separator)) { + oldParentPath2 = oldParentPath1.replace("\\", "\\\\"); + } + businessDataFileMapper.updateSubFilePaths(oldParentPath1, newParentPath1, oldParentPath2); + } + } diff --git a/core/src/main/java/com/dite/znpt/service/impl/BusinessDataServiceImpl.java b/core/src/main/java/com/dite/znpt/service/impl/BusinessDataServiceImpl.java index 2f17a2b..f4360cf 100644 --- a/core/src/main/java/com/dite/znpt/service/impl/BusinessDataServiceImpl.java +++ b/core/src/main/java/com/dite/znpt/service/impl/BusinessDataServiceImpl.java @@ -70,7 +70,7 @@ public class BusinessDataServiceImpl implements BusinessDataService { } // 文件夹名称前置一个/ - String folderName1 = "/" + folderName; + String folderName1 = File.separator + folderName; // 目标文件夹 File targetDir = Paths.get(businessDataPath, folderName1).toFile(); if (parentId != 0L) { @@ -147,23 +147,37 @@ public class BusinessDataServiceImpl implements BusinessDataService { } } + @ApiOperation("批量更新子文件夹路径") + @Override + public void updateSubFolderPaths(String oldParentPath1, String newParentPath1,Long folderId) { + // 处理路径中的分隔符,如果是反斜杠则替换为双反斜杠 + String processedOldParentPath = oldParentPath1; + String processedNewParentPath = newParentPath1; + if ("\\".equals(File.separator)) { + processedOldParentPath = oldParentPath1.replace("\\", "\\\\"); + processedNewParentPath = newParentPath1.replace("\\", "\\\\"); + } + + businessDataMapper.updateSubFolderPaths(oldParentPath1,newParentPath1,processedOldParentPath, processedNewParentPath, folderId); + } @ApiOperation("重命名文件夹") @Override public Result reName(Long folderId, String newName) { // 获取文件夹路径 String folderPath = businessDataMapper.getPath(folderId); - String newPath = folderPath.substring(0, folderPath.lastIndexOf('\\')) + "\\" + newName; - // - // //想命名的原文件的路径 - // File file = new File("f:/a/a.xlsx"); - // //将原文件更改为f:\a\b.xlsx,其中路径是必要的。注意 - // file.renameTo(new File("f:/a/b.xlsx")); - // 想命名的原文件夹的路径 + String newPath = folderPath.substring(0, folderPath.lastIndexOf(File.separator)) + File.separator + newName; + + // 重命名物理文件夹 File file1 = new File(folderPath); - // 将原文件夹更改为A,其中路径是必要的。注意 - file1.renameTo(new File(newPath)); + boolean renameSuccess = file1.renameTo(new File(newPath)); + + if (!renameSuccess) { + return Result.error("文件夹重命名失败"); + } + LocalDateTime now = LocalDateTime.now(); + // 更新文件夹信息 BusinessDataEntity businessDataEntity = new BusinessDataEntity( folderId, newName, @@ -174,6 +188,21 @@ public class BusinessDataServiceImpl implements BusinessDataService { null, newPath); businessDataMapper.reName(businessDataEntity); + +// // 批量更新该文件夹下所有文件的路径 +// businessDataFileService.updateFilePathByFolderId(folderId, newPath); + + + String folderPath1 = folderPath+File.separator; + String newPath1 = newPath+File.separator; + + // 批量更新子文件夹下所有文件的路径 + businessDataFileService.updateSubFilePaths(folderPath1, newPath1); + // 批量更新子文件夹的路径 + updateSubFolderPaths(folderPath1, newPath1,folderId); + return Result.okM("重命名成功"); } + + } diff --git a/core/src/main/java/com/dite/znpt/service/impl/EquipmentServiceImpl.java b/core/src/main/java/com/dite/znpt/service/impl/EquipmentServiceImpl.java index bcee3bb..9dcd42e 100644 --- a/core/src/main/java/com/dite/znpt/service/impl/EquipmentServiceImpl.java +++ b/core/src/main/java/com/dite/znpt/service/impl/EquipmentServiceImpl.java @@ -23,9 +23,13 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; +import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; +import com.dite.znpt.domain.vo.ReceiptRequest; +import cn.dev33.satoken.stp.StpUtil; +import org.springframework.beans.BeanUtils; /** * @author Bear.G @@ -474,6 +478,15 @@ public class EquipmentServiceImpl extends ServiceImpl getGanttChartData(GanttChartReq req) { + // 查询所有任务 + QueryWrapper queryWrapper = new QueryWrapper<>(); + + if (StrUtil.isNotBlank(req.getProjectId())) { + queryWrapper.eq("project_id", req.getProjectId()); + } + if (StrUtil.isNotBlank(req.getTaskGroupId())) { + queryWrapper.eq("task_group_id", req.getTaskGroupId()); + } + if (req.getStatus() != null) { + queryWrapper.eq("status", req.getStatus()); + } + if (StrUtil.isNotBlank(req.getMainUserId())) { + queryWrapper.eq("main_user_id", req.getMainUserId()); + } + if (req.getStartDateFrom() != null) { + queryWrapper.ge("plan_start_date", req.getStartDateFrom()); + } + if (req.getStartDateTo() != null) { + queryWrapper.le("plan_start_date", req.getStartDateTo()); + } + if (req.getEndDateFrom() != null) { + queryWrapper.ge("plan_end_date", req.getEndDateFrom()); + } + if (req.getEndDateTo() != null) { + queryWrapper.le("plan_end_date", req.getEndDateTo()); + } + if (req.getOverdueOnly() != null && req.getOverdueOnly()) { + queryWrapper.eq("overdue_status", 1); + } + if (req.getIncludeCompleted() != null && !req.getIncludeCompleted()) { + queryWrapper.ne("status", 2); + } + + queryWrapper.orderByAsc("plan_start_date"); + + List taskList = projectTaskMapper.selectList(queryWrapper); + + // 获取用户信息 + final Set userIds = new HashSet<>(); + taskList.forEach(task -> { + if (StrUtil.isNotBlank(task.getMainUserId())) { + userIds.add(task.getMainUserId()); + } + if (StrUtil.isNotBlank(task.getUserIds())) { + userIds.addAll(Arrays.asList(task.getUserIds().split(","))); + } + }); + + final Map userMap = new HashMap<>(); + if (CollUtil.isNotEmpty(userIds)) { + List users = userService.listByIds(userIds); + userMap.putAll(users.stream().collect(Collectors.toMap(UserEntity::getUserId, user -> user))); + } + + // 批量获取项目时间范围,避免重复查询 + final Map projectStartDates = new HashMap<>(); + if (StrUtil.isNotBlank(req.getProjectId())) { + // 如果指定了项目ID,直接获取该项目的时间范围 + LocalDate projectStart = getProjectStartDate(req.getProjectId()); + projectStartDates.put(req.getProjectId(), projectStart); + } else { + // 如果没有指定项目ID,获取所有相关项目的时间范围 + Set projectIds = taskList.stream() + .map(ProjectTaskEntity::getProjectId) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toSet()); + + for (String projectId : projectIds) { + LocalDate projectStart = getProjectStartDate(projectId); + projectStartDates.put(projectId, projectStart); + } + } + + // 转换为甘特图数据 + List ganttData = taskList.stream().map(task -> { + GanttChartResp resp = BeanUtil.copyProperties(task, GanttChartResp.class); + + // 设置状态描述 + switch (task.getStatus()) { + case 0: + resp.setStatusDesc("未开始"); + break; + case 1: + resp.setStatusDesc("进行中"); + break; + case 2: + resp.setStatusDesc("已结束"); + break; + default: + resp.setStatusDesc("未知"); + } + + // 设置负责人姓名 + if (StrUtil.isNotBlank(task.getMainUserId()) && userMap.containsKey(task.getMainUserId())) { + resp.setMainUserName(userMap.get(task.getMainUserId()).getName()); + } + + // 设置参与人姓名列表 + if (StrUtil.isNotBlank(task.getUserIds())) { + List participantNames = Arrays.stream(task.getUserIds().split(",")) + .filter(userId -> userMap.containsKey(userId)) + .map(userId -> userMap.get(userId).getName()) + .collect(Collectors.toList()); + resp.setParticipantNames(participantNames); + } + + // 计算进度(这里可以根据实际业务逻辑调整) + if (task.getStatus() == 2) { + resp.setProgress(100); + } else if (task.getStatus() == 1) { + resp.setProgress(50); // 默认进度,实际应该从数据库字段获取 + } else { + resp.setProgress(0); + } + + // 计算任务在时间轴上的位置和持续时间 + LocalDate projectStart = projectStartDates.get(task.getProjectId()); + if (projectStart != null && task.getPlanStartDate() != null) { + int position = (int) ChronoUnit.DAYS.between(projectStart, task.getPlanStartDate()); + resp.setPosition(position); + } + + // 计算任务持续时间 + if (task.getPlanStartDate() != null && task.getPlanEndDate() != null) { + int duration = (int) ChronoUnit.DAYS.between(task.getPlanStartDate(), task.getPlanEndDate()) + 1; + resp.setDuration(duration); + } else { + resp.setDuration(1); // 默认持续1天 + } + + return resp; + }).collect(Collectors.toList()); + + // 构建树形结构 + return buildTreeStructure(ganttData); + } + + @Override + public Object getGanttChartStatistics(String projectId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("project_id", projectId); + + List taskList = projectTaskMapper.selectList(queryWrapper); + + Map statistics = new HashMap<>(); + statistics.put("totalTasks", taskList.size()); + statistics.put("notStarted", (int) taskList.stream().filter(task -> task.getStatus() == 0).count()); + statistics.put("inProgress", (int) taskList.stream().filter(task -> task.getStatus() == 1).count()); + statistics.put("completed", (int) taskList.stream().filter(task -> task.getStatus() == 2).count()); + statistics.put("overdue", (int) taskList.stream().filter(task -> task.getOverdueStatus() == 1).count()); + + // 计算总体进度 + if (taskList.size() > 0) { + final double avgProgress = taskList.stream() + .mapToInt(task -> { + if (task.getStatus() == 2) return 100; + else if (task.getStatus() == 1) return 50; + else return 0; + }) + .average() + .orElse(0.0); + statistics.put("overallProgress", Math.round(avgProgress)); + } else { + statistics.put("overallProgress", 0); + } + + return statistics; + } + + @Override + public Object getGanttChartTimeline(String projectId) { + if (StrUtil.isBlank(projectId)) { + return null; + } + + LocalDate projectStartDate = getProjectStartDate(projectId); + LocalDate projectEndDate = getProjectEndDate(projectId); + + Map timeline = new HashMap<>(); + timeline.put("projectId", projectId); + timeline.put("startDate", projectStartDate); + timeline.put("endDate", projectEndDate); + timeline.put("totalDays", ChronoUnit.DAYS.between(projectStartDate, projectEndDate) + 1); + + // 计算时间轴上的关键时间点(比如每周、每月) + List> timePoints = new ArrayList<>(); + LocalDate currentDate = projectStartDate; + + while (!currentDate.isAfter(projectEndDate)) { + Map timePoint = new HashMap<>(); + timePoint.put("date", currentDate); + timePoint.put("dayOfWeek", currentDate.getDayOfWeek().getDisplayName(java.time.format.TextStyle.SHORT, java.util.Locale.CHINESE)); + timePoint.put("isWeekend", currentDate.getDayOfWeek().getValue() >= 6); + timePoints.add(timePoint); + + currentDate = currentDate.plusDays(1); + } + + timeline.put("timePoints", timePoints); + + return timeline; + } + + @Override + public boolean updateTaskProgress(String taskId, Integer progress) { + ProjectTaskEntity task = projectTaskMapper.selectById(taskId); + if (task == null) { + return false; + } + + // 更新进度 + // 这里需要根据实际业务逻辑添加进度字段 + // task.setProgress(progress); + + // 根据进度更新状态 + if (progress >= 100) { + task.setStatus(2); // 已完成 + task.setActualEndDate(LocalDate.now()); + } else if (progress > 0) { + task.setStatus(1); // 进行中 + if (task.getActualStartDate() == null) { + task.setActualStartDate(LocalDate.now()); + } + } + + return projectTaskMapper.updateById(task) > 0; + } + + @Override + public boolean updateTaskTime(String taskId, String startDate, String endDate) { + ProjectTaskEntity task = projectTaskMapper.selectById(taskId); + if (task == null) { + return false; + } + + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDate newStartDate = null; + LocalDate newEndDate = null; + + try { + if (StrUtil.isNotBlank(startDate)) { + newStartDate = LocalDate.parse(startDate, formatter); + } + if (StrUtil.isNotBlank(endDate)) { + newEndDate = LocalDate.parse(endDate, formatter); + } + } catch (DateTimeParseException e) { + return false; // 日期格式错误 + } + + // 验证时间约束 + if (!validateTaskTimeConstraints(task, newStartDate, newEndDate)) { + return false; + } + + // 更新任务时间 + if (newStartDate != null) { + task.setPlanStartDate(newStartDate); + } + if (newEndDate != null) { + task.setPlanEndDate(newEndDate); + } + + // 更新逾期状态 + updateOverdueStatus(task); + + return projectTaskMapper.updateById(task) > 0; + } + + /** + * 构建树形结构 + */ + private List buildTreeStructure(List allTasks) { + final Map taskMap = allTasks.stream() + .collect(Collectors.toMap(GanttChartResp::getTaskId, task -> task)); + + final List rootTasks = new ArrayList<>(); + + for (GanttChartResp task : allTasks) { + if (StrUtil.isBlank(task.getParentTaskId())) { + // 根任务 + task.setLevel(0); + rootTasks.add(task); + } else { + // 子任务 + GanttChartResp parentTask = taskMap.get(task.getParentTaskId()); + if (parentTask != null) { + task.setLevel(parentTask.getLevel() + 1); + if (parentTask.getChildren() == null) { + parentTask.setChildren(new ArrayList<>()); + } + parentTask.getChildren().add(task); + } + } + } + + return rootTasks; + } + + /** + * 获取项目开始时间 + * 从项目任务中计算最早的计划开始时间作为项目开始时间 + */ + private LocalDate getProjectStartDate(String projectId) { + if (StrUtil.isBlank(projectId)) { + return LocalDate.now().minusDays(30); // 默认值 + } + + // 查询项目中所有任务的计划开始时间,取最早的时间 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("project_id", projectId) + .isNotNull("plan_start_date") + .orderByAsc("plan_start_date") + .last("LIMIT 1"); + + ProjectTaskEntity earliestTask = projectTaskMapper.selectOne(queryWrapper); + + if (earliestTask != null && earliestTask.getPlanStartDate() != null) { + return earliestTask.getPlanStartDate(); + } + + // 如果没有找到有效的开始时间,返回当前时间减去30天作为默认值 + return LocalDate.now().minusDays(30); + } + + /** + * 获取项目结束时间 + * 从项目任务中计算最晚的计划结束时间作为项目结束时间 + */ + private LocalDate getProjectEndDate(String projectId) { + if (StrUtil.isBlank(projectId)) { + return LocalDate.now().plusDays(30); // 默认值 + } + + // 查询项目中所有任务的计划结束时间,取最晚的时间 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("project_id", projectId) + .isNotNull("plan_end_date") + .orderByDesc("plan_end_date") + .last("LIMIT 1"); + + ProjectTaskEntity latestTask = projectTaskMapper.selectOne(queryWrapper); + + if (latestTask != null && latestTask.getPlanEndDate() != null) { + return latestTask.getPlanEndDate(); + } + + // 如果没有找到有效的结束时间,返回当前时间加上30天作为默认值 + return LocalDate.now().plusDays(30); + } + + /** + * 获取项目时间范围 + * 返回项目的开始时间和结束时间 + */ + private Map getProjectTimeRange(String projectId) { + Map timeRange = new HashMap<>(); + timeRange.put("startDate", getProjectStartDate(projectId)); + timeRange.put("endDate", getProjectEndDate(projectId)); + return timeRange; + } + + /** + * 批量获取项目时间范围 + * 通过一次查询获取多个项目的时间范围,提高性能 + */ + private Map> getBatchProjectTimeRanges(Set projectIds) { + Map> timeRanges = new HashMap<>(); + + for (String projectId : projectIds) { + Map timeRange = getProjectTimeRange(projectId); + timeRanges.put(projectId, timeRange); + } + + return timeRanges; + } + + /** + * 计算任务进度 + */ + private Integer calculateProgress(ProjectTaskEntity task) { + if (task.getStatus() == 2) return 100; // 已完成 + else if (task.getStatus() == 1) return 50; // 进行中 + else return 0; // 未开始 + } + + /** + * 计算任务持续时间 + */ + private Integer calculateDuration(ProjectTaskEntity task) { + if (task.getPlanStartDate() != null && task.getPlanEndDate() != null) { + return (int) ChronoUnit.DAYS.between(task.getPlanStartDate(), task.getPlanEndDate()) + 1; + } + return 1; + } + + /** + * 计算任务在时间轴上的位置 + */ + private Integer calculatePosition(ProjectTaskEntity task) { + LocalDate projectStart = getProjectStartDate(task.getProjectId()); + if (task.getPlanStartDate() != null && projectStart != null) { + return (int) ChronoUnit.DAYS.between(projectStart, task.getPlanStartDate()); + } + return 0; + } + + /** + * 验证任务时间约束 + */ + private boolean validateTaskTimeConstraints(ProjectTaskEntity task, + LocalDate newStartDate, + LocalDate newEndDate) { + // 验证子任务不能早于父任务开始 + if (StrUtil.isNotBlank(task.getParentTaskId())) { + ProjectTaskEntity parentTask = projectTaskMapper.selectById(task.getParentTaskId()); + if (parentTask != null && newStartDate != null) { + if (newStartDate.isBefore(parentTask.getPlanStartDate())) { + return false; + } + } + } + + // 验证结束时间不能早于开始时间 + if (newStartDate != null && newEndDate != null) { + if (newEndDate.isBefore(newStartDate)) { + return false; + } + } + + return true; + } + + /** + * 更新逾期状态 + */ + private void updateOverdueStatus(ProjectTaskEntity task) { + if (task.getPlanEndDate() != null && + task.getPlanEndDate().isBefore(LocalDate.now()) && + task.getStatus() != 2) { + task.setOverdueStatus(1); // 标记为逾期 + } else { + task.setOverdueStatus(0); + } + } +} diff --git a/core/src/main/resources/mapper/BusinessDataFileMapper.xml b/core/src/main/resources/mapper/BusinessDataFileMapper.xml index c8216b4..62e2583 100644 --- a/core/src/main/resources/mapper/BusinessDataFileMapper.xml +++ b/core/src/main/resources/mapper/BusinessDataFileMapper.xml @@ -94,5 +94,20 @@ where file_id = #{fileId} + + + + + + + + + + + update business_data_part_file + set file_path = replace(file_path, #{oldParentPath1}, #{newParentPath1}) + where file_path like concat(#{oldParentPath2}, '%') + + diff --git a/core/src/main/resources/mapper/BusinessDataMapper.xml b/core/src/main/resources/mapper/BusinessDataMapper.xml index f714eae..e6d9332 100644 --- a/core/src/main/resources/mapper/BusinessDataMapper.xml +++ b/core/src/main/resources/mapper/BusinessDataMapper.xml @@ -51,5 +51,14 @@ + + + + update business_data_part + set folder_path = replace(folder_path, #{oldParentPath1}, #{newParentPath1}), + update_time = now() + where folder_path like concat(#{processedOldParentPath}, '%') + + diff --git a/web/src/main/java/com/dite/znpt/web/controller/EquipmentController.java b/web/src/main/java/com/dite/znpt/web/controller/EquipmentController.java index 8da84ae..1b8280c 100644 --- a/web/src/main/java/com/dite/znpt/web/controller/EquipmentController.java +++ b/web/src/main/java/com/dite/znpt/web/controller/EquipmentController.java @@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; +import com.dite.znpt.domain.vo.ReceiptRequest; /** * @author Bear.G @@ -139,4 +140,15 @@ public class EquipmentController { public Result getProcurementStats(){ return Result.ok(equipmentService.getProcurementStats()); } + + @ApiOperation(value = "确认收货并自动入库", httpMethod = "POST") + @PostMapping("/procurement/receipt/{equipmentId}") + public Result receiveGoods(@PathVariable String equipmentId, @Validated @RequestBody ReceiptRequest req) { + log.info("=== 设备收货接口被调用 ==="); + log.info("设备ID: {}", equipmentId); + log.info("收货数据: {}", req); + + equipmentService.receiveGoodsAndStockIn(equipmentId, req); + return Result.ok("收货成功,设备已自动入库"); + } } diff --git a/web/src/main/java/com/dite/znpt/web/controller/GanttChartController.java b/web/src/main/java/com/dite/znpt/web/controller/GanttChartController.java new file mode 100644 index 0000000..6da8f57 --- /dev/null +++ b/web/src/main/java/com/dite/znpt/web/controller/GanttChartController.java @@ -0,0 +1,61 @@ +package com.dite.znpt.web.controller; + +import com.dite.znpt.domain.Result; +import com.dite.znpt.domain.vo.GanttChartReq; +import com.dite.znpt.domain.vo.GanttChartResp; +import com.dite.znpt.service.GanttChartService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 甘特图控制器 + */ +@Api(tags = "甘特图管理") +@RestController +@RequestMapping("/gantt-chart") +public class GanttChartController { + + @Resource + private GanttChartService ganttChartService; + + @ApiOperation(value = "获取项目甘特图数据", httpMethod = "GET") + @GetMapping("/data") + public Result> getGanttChartData(GanttChartReq req) { + List data = ganttChartService.getGanttChartData(req); + return Result.ok(data); + } + + @ApiOperation(value = "获取项目甘特图统计信息", httpMethod = "GET") + @GetMapping("/statistics/{projectId}") + public Result getGanttChartStatistics(@PathVariable String projectId) { + Object statistics = ganttChartService.getGanttChartStatistics(projectId); + return Result.ok(statistics); + } + + @ApiOperation(value = "获取项目甘特图时间轴信息", httpMethod = "GET") + @GetMapping("/timeline/{projectId}") + public Result getGanttChartTimeline(@PathVariable String projectId) { + Object timeline = ganttChartService.getGanttChartTimeline(projectId); + return Result.ok(timeline); + } + + @ApiOperation(value = "更新任务进度", httpMethod = "PUT") + @PutMapping("/progress/{taskId}") + public Result updateTaskProgress(@PathVariable String taskId, @RequestParam Integer progress) { + boolean success = ganttChartService.updateTaskProgress(taskId, progress); + return Result.ok(success); + } + + @ApiOperation(value = "拖拽更新任务时间", httpMethod = "PUT") + @PutMapping("/time/{taskId}") + public Result updateTaskTime(@PathVariable String taskId, + @RequestParam(required = false) String startDate, + @RequestParam(required = false) String endDate) { + boolean success = ganttChartService.updateTaskTime(taskId, startDate, endDate); + return Result.ok(success); + } +} diff --git a/web/src/main/resources/application-dev.yml b/web/src/main/resources/application-dev.yml index 40e9bfb..155f1d2 100644 --- a/web/src/main/resources/application-dev.yml +++ b/web/src/main/resources/application-dev.yml @@ -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/znpt_dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + url: jdbc:mysql://39.99.201.243:3306/test01?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: BUw8YW6%@^8q druid: