diff --git a/mes-framework/mes-common/src/main/java/com/chanko/yunxi/mes/framework/common/util/io/FileUtils.java b/mes-framework/mes-common/src/main/java/com/chanko/yunxi/mes/framework/common/util/io/FileUtils.java index 9f2929c8..bf6ba391 100644 --- a/mes-framework/mes-common/src/main/java/com/chanko/yunxi/mes/framework/common/util/io/FileUtils.java +++ b/mes-framework/mes-common/src/main/java/com/chanko/yunxi/mes/framework/common/util/io/FileUtils.java @@ -3,6 +3,7 @@ package com.chanko.yunxi.mes.framework.common.util.io; import cn.hutool.core.io.FileTypeUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.file.FileNameUtil; +import cn.hutool.core.lang.UUID; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.DigestUtil; @@ -64,7 +65,7 @@ public class FileUtils { } /** - * 生成文件路径 + * 生成文件路径(存在问题!慎用!同文件多处使用将致错乱) * * @param content 文件内容 * @param originalName 原始文件名 @@ -81,4 +82,20 @@ public class FileUtils { return sha256Hex + '.' + FileTypeUtil.getType(new ByteArrayInputStream(content)); } + /** + * 生成文件路径 uuid + * + * @param originalName 原始文件名 + * @return path,唯一不可重复 + */ + public static String generatePath(String originalName) { + String uuid = UUID.randomUUID().toString(true); + // 情况一:如果存在 name,则优先使用 name 的后缀 + if (StrUtil.isNotBlank(originalName)) { + String extName = FileNameUtil.extName(originalName); + return StrUtil.isBlank(extName) ? uuid : uuid + "." + extName; + } + return uuid; + } + } diff --git a/mes-module-heli/mes-module-heli-api/src/main/java/com/chanko/yunxi/mes/module/heli/enums/BusinesTypeEnum.java b/mes-module-heli/mes-module-heli-api/src/main/java/com/chanko/yunxi/mes/module/heli/enums/BusinesTypeEnum.java index d8650bfb..9bb966ae 100644 --- a/mes-module-heli/mes-module-heli-api/src/main/java/com/chanko/yunxi/mes/module/heli/enums/BusinesTypeEnum.java +++ b/mes-module-heli/mes-module-heli-api/src/main/java/com/chanko/yunxi/mes/module/heli/enums/BusinesTypeEnum.java @@ -10,7 +10,8 @@ import lombok.Getter; @Getter public enum BusinesTypeEnum { - PROJECT_ORDER("销售订单"); + PROJECT_ORDER("销售订单"), + PROJECT_ORDER_SNAPSHOT("销售订单快照"); private String description; diff --git a/mes-module-heli/mes-module-heli-api/src/main/java/com/chanko/yunxi/mes/module/heli/enums/ProjectOrderStatusEnum.java b/mes-module-heli/mes-module-heli-api/src/main/java/com/chanko/yunxi/mes/module/heli/enums/ProjectOrderStatusEnum.java index 2bb4c8e6..8109eb95 100644 --- a/mes-module-heli/mes-module-heli-api/src/main/java/com/chanko/yunxi/mes/module/heli/enums/ProjectOrderStatusEnum.java +++ b/mes-module-heli/mes-module-heli-api/src/main/java/com/chanko/yunxi/mes/module/heli/enums/ProjectOrderStatusEnum.java @@ -11,6 +11,7 @@ import lombok.Getter; public enum ProjectOrderStatusEnum { REPULSE(3, "已打回"), SAVE(4, "已保存"), + ALTER(8, "发起变更"), SUBMIT_AUDIT(8, "已送审"), AUDIT(16, "已审核"), APPROVE(32, "已启动"), diff --git a/mes-module-heli/mes-module-heli-biz/pom.xml b/mes-module-heli/mes-module-heli-biz/pom.xml index 556fb794..f6debc24 100644 --- a/mes-module-heli/mes-module-heli-biz/pom.xml +++ b/mes-module-heli/mes-module-heli-biz/pom.xml @@ -32,6 +32,11 @@ mes-module-system-biz ${revision} + + com.chanko.yunxi + mes-module-infra-biz + ${revision} + @@ -117,6 +122,12 @@ mes-spring-boot-starter-file + + com.github.dadiyang + equator + 1.0.4 + + diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/ProjectOrderController.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/ProjectOrderController.java index 6424d4e9..0b502e34 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/ProjectOrderController.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/ProjectOrderController.java @@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -67,6 +68,7 @@ public class ProjectOrderController { @Operation(summary = "操作项目订单") @PreAuthorize("@ss.hasPermission('heli:project-order:update')") @OperateLog(enable = false) + @Transactional(rollbackFor = Exception.class) public CommonResult operateProjectOrder(@Valid @RequestBody ProjectOrderSaveReqVO operateReqVO) { LocalDateTime startTime = LocalDateTime.now(); projectOrderService.operateProjectOrder(operateReqVO); @@ -78,6 +80,14 @@ public class ProjectOrderController { operateReqVO.getId(), OperateTypeEnum.valueOf(operateReqVO.getActive()).getType(), operateReqVO.getActiveOpinion()); + + // 批准、终止记录快照 + switch (OperateTypeEnum.valueOf(operateReqVO.getActive())){ + case APPROVE: + case TERMINATE: + projectOrderService.createProjectOrderSnapshot(operateReqVO); + break; + } return success(operateReqVO.getId()); } diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderPageReqVO.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderPageReqVO.java index 636198f6..bfadefcf 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderPageReqVO.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderPageReqVO.java @@ -113,4 +113,21 @@ public class ProjectOrderPageReqVO extends PageParam { @Schema(description = "客户名称") private String businessManName; + @Schema(description = "是否快照") + private Integer isSnapshot; + + @Schema(description = "快照原始id", example = "19436") + private Long snapshotId; + + @Schema(description = "快照原始单据号") + private String snapshotCode; + + @Schema(description = "单据日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] orderTime; + + @Schema(description = "快照原始单据日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] snapshotOrderTime; + } diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderRespVO.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderRespVO.java index 84ed2ae3..d808d2d6 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderRespVO.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderRespVO.java @@ -1,15 +1,15 @@ package com.chanko.yunxi.mes.module.heli.controller.admin.projectorder.vo; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.chanko.yunxi.mes.framework.excel.core.annotations.DictFormat; +import com.chanko.yunxi.mes.framework.excel.core.convert.DictConvert; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.util.*; -import java.util.*; +import lombok.Data; + import java.math.BigDecimal; -import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; -import com.alibaba.excel.annotation.*; -import com.chanko.yunxi.mes.framework.excel.core.annotations.DictFormat; -import com.chanko.yunxi.mes.framework.excel.core.convert.DictConvert; +import java.util.Set; @Schema(description = "管理后台 - 项目订单 Response VO") @Data @@ -152,4 +152,28 @@ public class ProjectOrderRespVO { @ExcelProperty("合同编号") private String contractNo; + @Schema(description = "是否快照", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "是否快照", converter = DictConvert.class) + @DictFormat("heli_common_is_or_not") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private Integer isSnapshot; + + @Schema(description = "快照原始id", example = "19436") + @ExcelProperty("快照原始id") + private Long snapshotId; + + @Schema(description = "快照原始单据号") + @ExcelProperty("快照原始单据号") + private String snapshotCode; + + @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("单据日期") + private LocalDateTime orderTime; + + @Schema(description = "快照原始单据日期") + @ExcelProperty("快照原始单据日期") + private LocalDateTime snapshotOrderTime; + + @Schema(description = "变更的字段列表") + private Set alterFieldNames; + } diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderSaveReqVO.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderSaveReqVO.java index 6cac2174..3431f4bf 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderSaveReqVO.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/controller/admin/projectorder/vo/ProjectOrderSaveReqVO.java @@ -102,7 +102,6 @@ public class ProjectOrderSaveReqVO { private Integer hasBlueprint; @Schema(description = "图纸/数模 说明", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜") - @NotEmpty(message = "图纸/数模 说明不能为空") private String blueprintRemark; @Schema(description = "状态,1表示正常,2表示禁用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @@ -126,4 +125,19 @@ public class ProjectOrderSaveReqVO { @Schema(description = "项目订单子项目列表") private List projectOrderSubs; + @Schema(description = "是否快照", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer isSnapshot; + + @Schema(description = "快照原始id", example = "19436") + private Long snapshotId; + + @Schema(description = "快照原始单据号") + private String snapshotCode; + + @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime orderTime; + + @Schema(description = "快照原始单据日期") + private LocalDateTime snapshotOrderTime; + } diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/dataobject/projectorder/ProjectOrderDO.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/dataobject/projectorder/ProjectOrderDO.java index 68af5f91..675bef61 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/dataobject/projectorder/ProjectOrderDO.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/dataobject/projectorder/ProjectOrderDO.java @@ -1,18 +1,18 @@ package com.chanko.yunxi.mes.module.heli.dal.dataobject.projectorder; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.chanko.yunxi.mes.framework.mybatis.core.dataobject.BaseDO; import com.chanko.yunxi.mes.framework.operatelog.core.enums.OperateTypeEnum; import com.chanko.yunxi.mes.module.heli.enums.ProjectOrderStatusEnum; import com.chanko.yunxi.mes.module.heli.enums.YesOrNoEnum; import lombok.*; -import java.util.*; + import java.math.BigDecimal; import java.time.LocalDateTime; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; -import com.chanko.yunxi.mes.framework.mybatis.core.dataobject.BaseDO; +import java.util.Set; /** * 项目订单 DO @@ -164,6 +164,28 @@ public class ProjectOrderDO extends BaseDO { * 合同编号 */ private String contractNo; + /** + * 是否快照 + * + * 枚举 {@link TODO heli_common_is_or_not 对应的类} + */ + private Integer isSnapshot; + /** + * 快照原始id + */ + private Long snapshotId; + /** + * 快照原始单据号 + */ + private String snapshotCode; + /** + * 单据日期 + */ + private LocalDateTime orderTime; + /** + * 快照原始单据日期 + */ + private LocalDateTime snapshotOrderTime; @TableField(exist = false) private String businessDeptName; @@ -174,6 +196,12 @@ public class ProjectOrderDO extends BaseDO { @TableField(exist = false) private String businessManName; + /** + * 变更的字段列表 + * */ + @TableField(exist = false) + private Set alterFieldNames; + public boolean canSave(){ return this.orderStatus.intValue() <= ProjectOrderStatusEnum.SAVE.getCode(); } diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/dataobject/projectorder/ProjectOrderSubDO.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/dataobject/projectorder/ProjectOrderSubDO.java index faba23f5..6e5325b2 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/dataobject/projectorder/ProjectOrderSubDO.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/dataobject/projectorder/ProjectOrderSubDO.java @@ -1,11 +1,13 @@ package com.chanko.yunxi.mes.module.heli.dal.dataobject.projectordersub; -import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; import com.chanko.yunxi.mes.framework.mybatis.core.dataobject.BaseDO; +import lombok.*; + +import java.util.Set; /** * 项目订单子项目 DO @@ -64,5 +66,10 @@ public class ProjectOrderSubDO extends BaseDO { * 删除 物理删除 */ private Boolean deleted; + /** + * 变更的字段列表 + * */ + @TableField(exist = false) + private Set alterFieldNames; } diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/mysql/projectorder/ProjectOrderMapper.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/mysql/projectorder/ProjectOrderMapper.java index 59cf77b2..a7ed8141 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/mysql/projectorder/ProjectOrderMapper.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/dal/mysql/projectorder/ProjectOrderMapper.java @@ -35,7 +35,10 @@ public interface ProjectOrderMapper extends BaseMapperX { .eq(reqVO.getHasPrice() != null, ProjectOrderDO::getHasPrice, reqVO.getHasPrice()) .eq(reqVO.getOrderStatus() != null, ProjectOrderDO::getOrderStatus, reqVO.getOrderStatus()) .eq(reqVO.getDeliveryStatus() != null, ProjectOrderDO::getDeliveryStatus, reqVO.getDeliveryStatus()) - .in(reqVO.getOrderStatusList() != null && !reqVO.getOrderStatusList().isEmpty(), ProjectOrderDO::getOrderStatus, reqVO.getOrderStatusList()); + .in(reqVO.getOrderStatusList() != null && !reqVO.getOrderStatusList().isEmpty(), ProjectOrderDO::getOrderStatus, reqVO.getOrderStatusList()) + .eq(reqVO.getIsSnapshot() != null, ProjectOrderDO::getIsSnapshot, reqVO.getIsSnapshot()) + .like(!StringUtils.isEmpty(reqVO.getSnapshotCode()), ProjectOrderDO::getSnapshotCode, reqVO.getSnapshotCode()); + ; return selectPage(reqVO, query); } diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/projectorder/ProjectOrderService.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/projectorder/ProjectOrderService.java index 0951e1de..5d53d67c 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/projectorder/ProjectOrderService.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/projectorder/ProjectOrderService.java @@ -68,4 +68,10 @@ public interface ProjectOrderService { * @param operateReqVO */ void operateProjectOrder(ProjectOrderSaveReqVO operateReqVO); + + /** + * 记录快照 + * @param operateReqVO + */ + void createProjectOrderSnapshot(ProjectOrderSaveReqVO operateReqVO); } diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/projectorder/ProjectOrderServiceImpl.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/projectorder/ProjectOrderServiceImpl.java index 5be8ba0b..f5a9f0db 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/projectorder/ProjectOrderServiceImpl.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/projectorder/ProjectOrderServiceImpl.java @@ -14,16 +14,24 @@ import com.chanko.yunxi.mes.module.heli.dal.mysql.projectorder.ProjectOrderMappe import com.chanko.yunxi.mes.module.heli.dal.mysql.projectorder.ProjectOrderSubMapper; import com.chanko.yunxi.mes.module.heli.enums.BusinesTypeEnum; import com.chanko.yunxi.mes.module.heli.enums.ProjectOrderStatusEnum; +import com.chanko.yunxi.mes.module.heli.enums.YesOrNoEnum; import com.chanko.yunxi.mes.module.heli.service.customer.CustomerService; import com.chanko.yunxi.mes.module.heli.service.serialnumber.SerialNumberService; +import com.chanko.yunxi.mes.module.infra.controller.admin.file.vo.file.FilePageReqVO; +import com.chanko.yunxi.mes.module.infra.dal.dataobject.file.FileDO; +import com.chanko.yunxi.mes.module.infra.service.file.FileService; +import com.github.dadiyang.equator.FieldInfo; +import com.github.dadiyang.equator.GetterBaseEquator; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; import static com.chanko.yunxi.mes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.chanko.yunxi.mes.module.heli.enums.CodeEnum.PROJECT_ORDER; @@ -35,10 +43,13 @@ import static com.chanko.yunxi.mes.module.heli.enums.ErrorCodeConstants.PROJECT_ * * @author 管理员 */ +@Slf4j @Service @Validated public class ProjectOrderServiceImpl implements ProjectOrderService { + private static final GetterBaseEquator FIELD_EQUATOR = new GetterBaseEquator(); + @Resource private ProjectOrderMapper projectOrderMapper; @Resource @@ -50,10 +61,14 @@ public class ProjectOrderServiceImpl implements ProjectOrderService { @Resource private CustomerService customerService; + @Resource + private FileService fileService; + @Override @Transactional(rollbackFor = Exception.class) public Long createProjectOrder(ProjectOrderSaveReqVO createReqVO) { // 插入 + createReqVO.setOrderTime(LocalDateTime.now()); ProjectOrderDO projectOrder = BeanUtils.toBean(createReqVO, ProjectOrderDO.class); // 月度流水号 SerialNumberDO serialNumberDO = serialNumberService.getSerialNumber(BusinesTypeEnum.PROJECT_ORDER.name(), new SimpleDateFormat("yyyyMM").format(new Date())); @@ -65,7 +80,7 @@ public class ProjectOrderServiceImpl implements ProjectOrderService { // 插入子表 createProjectOrderSubList(projectOrder.getId(), createReqVO.getProjectOrderSubs()); - createReqVO.setId(projectOrder.getId()); + createReqVO.setId(projectOrder.getId()).setCode(projectOrder.getCode()); // 回写序列记录 serialNumberService.updateSerialNumber(serialNumberDO); @@ -73,6 +88,44 @@ public class ProjectOrderServiceImpl implements ProjectOrderService { return projectOrder.getId(); } + @Override + @Transactional(rollbackFor = Exception.class) + public void createProjectOrderSnapshot(ProjectOrderSaveReqVO createReqVO) { + ProjectOrderDO projectOrder = BeanUtils.toBean(createReqVO, ProjectOrderDO.class); + // 快照流水号 + SerialNumberDO serialNumberDO = serialNumberService.getSerialNumber(BusinesTypeEnum.PROJECT_ORDER_SNAPSHOT.name(), projectOrder.getCode()); + serialNumberDO.setSerialNumber(serialNumberDO.getSerialNumber()+1); + projectOrder.setId(null) + .setIsSnapshot(YesOrNoEnum.YES.getCode()) + .setSnapshotId(createReqVO.getId()) + .setSnapshotCode(createReqVO.getCode()) + .setSnapshotOrderTime(createReqVO.getOrderTime()) + .setCode(String.format("%s-%s", createReqVO.getCode(), serialNumberDO.getSerialNumber().intValue())) + .setOrderTime(LocalDateTime.now()) + ; + projectOrderMapper.insert(projectOrder); + // 子项目 + createProjectOrderSubList(projectOrder.getId(), createReqVO.getProjectOrderSubs()); + // 附件 + PageResult filePage = fileService.getFilePage(new FilePageReqVO() {{ + setPageNo(1); + setPageSize(99); + setBusinessId(createReqVO.getId()); + setBusinessType(BusinesTypeEnum.PROJECT_ORDER.name()); + }}); + if(filePage.getTotal() > 0){ + List list = filePage.getList(); + list.forEach(fileDO -> { + fileDO.setId(null) + .setBusinessId(projectOrder.getId()) + .setBusinessType(BusinesTypeEnum.PROJECT_ORDER_SNAPSHOT.name()); + }); + fileService.insertBatch(list); + } + // 回写序列记录 + serialNumberService.updateSerialNumber(serialNumberDO); + } + @Override @Transactional(rollbackFor = Exception.class) public void updateProjectOrder(ProjectOrderSaveReqVO updateReqVO) { @@ -85,6 +138,7 @@ public class ProjectOrderServiceImpl implements ProjectOrderService { ProjectOrderDO updateObj = BeanUtils.toBean(updateReqVO, ProjectOrderDO.class); updateObj.setOrderStatus(ProjectOrderStatusEnum.valueOf(updateReqVO.getActive()).getCode()); projectOrderMapper.updateById(updateObj); + updateReqVO.setOrderStatus(updateObj.getOrderStatus()); // 更新子表 updateProjectOrderSubList(updateReqVO.getId(), updateReqVO.getProjectOrderSubs()); @@ -118,7 +172,55 @@ public class ProjectOrderServiceImpl implements ProjectOrderService { @Override public ProjectOrderDO getProjectOrder(Long id) { - return projectOrderMapper.selectById(id); + ProjectOrderDO projectOrderDO = projectOrderMapper.selectById(id); + // 查询最近归档历史并对比变化字段 + try { + ProjectOrderDO lastSnapshot = projectOrderMapper.selectOne(new LambdaQueryWrapper() {{ + eq(ProjectOrderDO::getSnapshotId, id); + orderByDesc(ProjectOrderDO::getId); + last("LIMIT 1"); + }}); + if(lastSnapshot != null){ + List diffFields = FIELD_EQUATOR.getDiffFields(projectOrderDO, lastSnapshot); + projectOrderDO.setAlterFieldNames(diffFields.stream().map(FieldInfo::getFieldName).collect(Collectors.toSet())); + + // 附件 + List fileList = new ArrayList<>(16); + PageResult filePage = fileService.getFilePage(new FilePageReqVO() {{ + setPageNo(1); + setPageSize(99); + setBusinessId(id); + setBusinessType(BusinesTypeEnum.PROJECT_ORDER.name()); + }}); + if(filePage.getTotal() > 0) { + fileList.addAll(filePage.getList()); + } + + List lastSnapshotFilelist = new ArrayList<>(16);; + PageResult lastSnapshotFilePage = fileService.getFilePage(new FilePageReqVO() {{ + setPageNo(1); + setPageSize(99); + setBusinessId(lastSnapshot.getId()); + setBusinessType(BusinesTypeEnum.PROJECT_ORDER_SNAPSHOT.name()); + }}); + if(lastSnapshotFilePage.getTotal() > 0) { + lastSnapshotFilelist.addAll(lastSnapshotFilePage.getList()); + } + if(fileList.size() != lastSnapshotFilelist.size()){ + projectOrderDO.getAlterFieldNames().add("attachments"); + }else{ + boolean allMatch = fileList.stream().allMatch(fileDO -> lastSnapshotFilelist.stream().anyMatch(sFile -> fileDO.getPath().equals(sFile.getPath()))); + if(!allMatch){ + projectOrderDO.getAlterFieldNames().add("attachments"); + } + } + } + }catch (Exception e){ + // do nothing + log.error("generate alterFieldNames error, id: {}, exception: {}", id, e.getMessage(), e); + } + + return projectOrderDO; } @Override @@ -130,7 +232,31 @@ public class ProjectOrderServiceImpl implements ProjectOrderService { @Override public List getProjectOrderSubListByProjectOrderId(Long projectOrderId) { - return projectOrderSubMapper.selectListByProjectOrderId(projectOrderId); + List projectOrderSubDOList = projectOrderSubMapper.selectListByProjectOrderId(projectOrderId); + if(!projectOrderSubDOList.isEmpty()){ + // 查询最近归档历史并对比变化字段 + try { + ProjectOrderDO lastSnapshot = projectOrderMapper.selectOne(new LambdaQueryWrapper() {{ + eq(ProjectOrderDO::getSnapshotId, projectOrderId); + orderByDesc(ProjectOrderDO::getId); + last("LIMIT 1"); + }}); + if(lastSnapshot != null){ + List lastSnapshotSubDOList = projectOrderSubMapper.selectList(ProjectOrderSubDO::getProjectOrderId, lastSnapshot.getId()); + Map> nameGroups = lastSnapshotSubDOList.stream().collect(Collectors.groupingBy(ProjectOrderSubDO::getName)); + projectOrderSubDOList.forEach(projectOrderSubDO -> { + List lastSnapshotSubs = nameGroups.get(projectOrderSubDO.getName()); + if(lastSnapshotSubs.isEmpty()) return; + List diffFields = FIELD_EQUATOR.getDiffFields(projectOrderSubDO, lastSnapshotSubs.get(0)); + projectOrderSubDO.setAlterFieldNames(diffFields.stream().map(FieldInfo::getFieldName).collect(Collectors.toSet())); + }); + } + }catch (Exception e){ + log.error("generate sub alterFieldNames error, id: {}, exception: {}", projectOrderId, e.getMessage(), e); + } + + } + return projectOrderSubDOList; } @Override @@ -144,7 +270,7 @@ public class ProjectOrderServiceImpl implements ProjectOrderService { } private void createProjectOrderSubList(Long projectOrderId, List list) { - list.forEach(o -> o.setProjectOrderId(projectOrderId)); + list.forEach(o -> o.setId(null).setProjectOrderId(projectOrderId)); projectOrderSubMapper.insertBatch(list); } diff --git a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/serialnumber/SerialNumberServiceImpl.java b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/serialnumber/SerialNumberServiceImpl.java index eed81ac9..b8d68ced 100644 --- a/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/serialnumber/SerialNumberServiceImpl.java +++ b/mes-module-heli/mes-module-heli-biz/src/main/java/com/chanko/yunxi/mes/module/heli/service/serialnumber/SerialNumberServiceImpl.java @@ -83,7 +83,7 @@ public class SerialNumberServiceImpl implements SerialNumberService { @Transactional(rollbackFor = Exception.class) public SerialNumberDO getSerialNumber(String businessType, String segment) { LambdaQueryWrapperX query = new LambdaQueryWrapperX() {{ - eq(SerialNumberDO::getBusinessType, BusinesTypeEnum.PROJECT_ORDER.name()); + eq(SerialNumberDO::getBusinessType, businessType); eq(SerialNumberDO::getSegment, segment); last("LIMIT 1 FOR UPDATE"); }}; diff --git a/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/controller/admin/file/FileController.java b/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/controller/admin/file/FileController.java index 4c8a792d..d6bc4909 100644 --- a/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/controller/admin/file/FileController.java +++ b/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/controller/admin/file/FileController.java @@ -71,6 +71,15 @@ public class FileController { return success(true); } + @DeleteMapping("/deleteLogic") + @Operation(summary = "删除文件(逻辑删除)") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('infra:file:delete')") + public CommonResult deleteFileLogic(@RequestParam("id") Long id) throws Exception { + fileService.deleteFileLogic(id); + return success(true); + } + @GetMapping("/{configId}/get/**") @PermitAll @Operation(summary = "下载文件") diff --git a/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/service/file/FileService.java b/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/service/file/FileService.java index 7caf5d11..dd56ec2e 100644 --- a/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/service/file/FileService.java +++ b/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/service/file/FileService.java @@ -4,6 +4,8 @@ import com.chanko.yunxi.mes.framework.common.pojo.PageResult; import com.chanko.yunxi.mes.module.infra.controller.admin.file.vo.file.FilePageReqVO; import com.chanko.yunxi.mes.module.infra.dal.dataobject.file.FileDO; +import java.util.List; + /** * 文件 Service 接口 * @@ -48,4 +50,15 @@ public interface FileService { */ byte[] getFileContent(Long configId, String path) throws Exception; + /** + * 删除文件(逻辑删除) + * @param id + */ + void deleteFileLogic(Long id); + + /** + * 批量插入 + * @param fileDOList + */ + void insertBatch(List fileDOList); } diff --git a/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/service/file/FileServiceImpl.java b/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/service/file/FileServiceImpl.java index 2d28d3ff..398429e1 100644 --- a/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/service/file/FileServiceImpl.java +++ b/mes-module-infra/mes-module-infra-biz/src/main/java/com/chanko/yunxi/mes/module/infra/service/file/FileServiceImpl.java @@ -14,6 +14,8 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.util.List; + import static com.chanko.yunxi.mes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.chanko.yunxi.mes.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS; @@ -42,7 +44,7 @@ public class FileServiceImpl implements FileService { // 计算默认的 path 名 String type = FileTypeUtils.getMineType(content, name); if (StrUtil.isEmpty(path)) { - path = FileUtils.generatePath(content, name); + path = FileUtils.generatePath(name); } // 如果 name 为空,则使用 path 填充 if (StrUtil.isEmpty(name)) { @@ -98,4 +100,17 @@ public class FileServiceImpl implements FileService { return client.getContent(path); } + @Override + public void deleteFileLogic(Long id) { + // 校验存在 + validateFileExists(id); + // 删除记录 + fileMapper.deleteById(id); + } + + @Override + public void insertBatch(List fileDOList){ + fileMapper.insertBatch(fileDOList); + } + } diff --git a/mes-server/pom.xml b/mes-server/pom.xml index 9caac39b..4b66340c 100644 --- a/mes-server/pom.xml +++ b/mes-server/pom.xml @@ -20,6 +20,18 @@ + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.jupiter + junit-jupiter + 5.4.0 + test + + com.chanko.yunxi mes-module-system-biz @@ -39,11 +51,6 @@ mes-module-heli-biz ${revision} - - com.github.dadiyang - equator - 1.0.4 - diff --git a/mes-ui/mes-ui-admin-vue3/src/api/heli/projectorder/index.ts b/mes-ui/mes-ui-admin-vue3/src/api/heli/projectorder/index.ts index c7c13d71..b95f811e 100644 --- a/mes-ui/mes-ui-admin-vue3/src/api/heli/projectorder/index.ts +++ b/mes-ui/mes-ui-admin-vue3/src/api/heli/projectorder/index.ts @@ -32,7 +32,11 @@ export interface ProjectOrderVO { active: string activeOpinion: string projectOrderSubs: any - + isSnapshot: number + snapshotId: number + snapshotCode: string + orderTime: Date + snapshotOrderTime: Date } // 查询项目订单分页 diff --git a/mes-ui/mes-ui-admin-vue3/src/api/infra/file/index.ts b/mes-ui/mes-ui-admin-vue3/src/api/infra/file/index.ts index fe59446c..478fb9fd 100644 --- a/mes-ui/mes-ui-admin-vue3/src/api/infra/file/index.ts +++ b/mes-ui/mes-ui-admin-vue3/src/api/infra/file/index.ts @@ -23,3 +23,8 @@ export const deleteFile = (id: number) => { export const downloadFile = async (url) => { return await request.download({ url: url }) } + +// 删除文件 +export const deleteFileLogic = (id: number) => { + return request.delete({ url: '/infra/file/deleteLogic?id=' + id }) +} diff --git a/mes-ui/mes-ui-admin-vue3/src/locales/en.ts b/mes-ui/mes-ui-admin-vue3/src/locales/en.ts index 9b62d174..fe33c512 100644 --- a/mes-ui/mes-ui-admin-vue3/src/locales/en.ts +++ b/mes-ui/mes-ui-admin-vue3/src/locales/en.ts @@ -300,6 +300,8 @@ export default { audit: 'Audit', approve: 'Approve', terminate: 'Terminate', + detailArchive: 'Detail', + alter: 'Alter', typeCreate: 'Dict Type Create', typeUpdate: 'Dict Type Eidt', dataCreate: 'Dict Data Create', diff --git a/mes-ui/mes-ui-admin-vue3/src/locales/zh-CN.ts b/mes-ui/mes-ui-admin-vue3/src/locales/zh-CN.ts index e9267503..c439d10d 100644 --- a/mes-ui/mes-ui-admin-vue3/src/locales/zh-CN.ts +++ b/mes-ui/mes-ui-admin-vue3/src/locales/zh-CN.ts @@ -301,6 +301,8 @@ export default { audit: '审核', approve: '批准', terminate: '终止', + detailArchive: '详情', + alter: '变更', typeCreate: '字典类型新增', typeUpdate: '字典类型编辑', dataCreate: '字典数据新增', diff --git a/mes-ui/mes-ui-admin-vue3/src/utils/dict.ts b/mes-ui/mes-ui-admin-vue3/src/utils/dict.ts index 8e1e5b29..9807eddb 100644 --- a/mes-ui/mes-ui-admin-vue3/src/utils/dict.ts +++ b/mes-ui/mes-ui-admin-vue3/src/utils/dict.ts @@ -232,4 +232,5 @@ export enum DICT_TYPE { HELI_PROJECT_ORDER_SUB_UNIT = 'heli_project_order_sub_unit', // 子项目单位 HELI_PROJECT_ORDER_AUDIT_STATUS = 'heli_project_order_audit_status', // 项目单据审核页状态 HELI_PROJECT_ORDER_APPROVE_STATUS = 'heli_project_order_approve_status', // 项目单据批准页状态 + HELI_PROJECT_ORDER_ALTER_STATUS = 'heli_project_order_alter_status', // 项目单据变更页状态 } diff --git a/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/approve.vue b/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/approve.vue index 567a9bc5..9429104f 100644 --- a/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/approve.vue +++ b/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/approve.vue @@ -123,7 +123,7 @@ fixed label="订单日期" align="center" - prop="createTime" + prop="orderTime" :formatter="dateFormatter2" width="180" /> @@ -263,6 +263,11 @@ const queryParams = reactive({ status: undefined, createTime: [], businessManName: undefined, + isSnapshot: 0, + snapshotId: undefined, + snapshotCode: undefined, + orderTime: [], + snapshotOrderTime: [], }) const queryFormRef = ref() // 搜索的表单 const exportLoading = ref(false) // 导出的加载中 diff --git a/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/archive.vue b/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/archive.vue new file mode 100644 index 00000000..ab51e611 --- /dev/null +++ b/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/archive.vue @@ -0,0 +1,338 @@ + + + + + diff --git a/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/audit.vue b/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/audit.vue index 1c769661..c07f0a80 100644 --- a/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/audit.vue +++ b/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/audit.vue @@ -123,7 +123,7 @@ fixed label="订单日期" align="center" - prop="createTime" + prop="orderTime" :formatter="dateFormatter2" width="180" /> @@ -255,6 +255,11 @@ const queryParams = reactive({ status: undefined, createTime: [], businessManName: undefined, + isSnapshot: 0, + snapshotId: undefined, + snapshotCode: undefined, + orderTime: [], + snapshotOrderTime: [], }) const queryFormRef = ref() // 搜索的表单 const exportLoading = ref(false) // 导出的加载中 diff --git a/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/detail.vue b/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/detail.vue index e52c03b8..2d8bc82c 100644 --- a/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/detail.vue +++ b/mes-ui/mes-ui-admin-vue3/src/views/heli/projectorder/detail.vue @@ -7,7 +7,7 @@ -
+
已发货
@@ -27,9 +27,9 @@ >距交货还有{{ betweenDay(new Date(), new Date(formData.projectEndTime)) + 1 }}天
- -
+ + + @@ -101,7 +109,6 @@ @@ -134,6 +142,7 @@ placeholder="请输入检验要求" show-word-limit maxlength="200" + :class="{'alter-class': fieldHasAlter('referenceTechnology')}" /> @@ -143,7 +152,7 @@ - {{ formatDate(formData.orderTime, 'YYYY-MM-DD') }} + {{ query.active != 'detailArchive' ? formatDate(formData.orderTime, 'YYYY-MM-DD') : formatDate(formData.snapshotOrderTime, 'YYYY-MM-DD')}} @@ -190,6 +199,7 @@ - + - + @@ -350,12 +365,14 @@ :min="0" :precision="6" style="width: 150px" + :class="{'alter-class': fieldHasAlter('price')}" /> - + - + - + @@ -455,7 +480,7 @@ - + 新增 @@ -477,7 +502,7 @@ class="mb-0px!" > @@ -492,7 +517,7 @@ class="mb-0px!" > @@ -512,6 +537,7 @@ placeholder="请输入数量" :min="0" :precision="0" + :class="{'alter-class': fieldHasAlterInRow('amount', row)}" /> @@ -527,6 +553,7 @@ :disabled="detailDisabled" v-model="row.unit" placeholder="请选择单位" + :class="{'alter-class': fieldHasAlterInRow('unit', row)}" > @@ -603,11 +632,15 @@ - + - + @@ -707,7 +740,7 @@ label="操作时间" align="center" prop="startTime" - width="180" + width="220" :formatter="dateFormatter" /> @@ -752,7 +785,7 @@ @click="submitForm('ALTER')" type="danger" size="large" - >确定变更发起变更 @@ -196,7 +196,7 @@ > 编辑 - + 更多 @@ -205,9 +205,9 @@ @@ -271,6 +271,11 @@ const queryParams = reactive({ status: undefined, createTime: [], businessManName: undefined, + isSnapshot: 0, + snapshotId: undefined, + snapshotCode: undefined, + orderTime: [], + snapshotOrderTime: [], }) const queryFormRef = ref() // 搜索的表单 const exportLoading = ref(false) // 导出的加载中 @@ -338,11 +343,28 @@ const handleExport = async () => { } } -const handleCommand = async (command, id) => { +const handleCommand = async (command, id, code) => { switch (command){ case 'detail': openDetail('detail', id); break; + case 'printProject': + // TODO + break; + case 'alter': + openDetail('alter', id); + break; + case 'viewArchive': + router.push({ + name: 'ProjectOrderArchive', + query: { + code: code + } + }) + break; + case 'delivery': + // TODO + break; } } diff --git a/sql/v1.1.0/heli.sql b/sql/v1.1.0/heli.sql index e7e08261..ce0e4d78 100644 --- a/sql/v1.1.0/heli.sql +++ b/sql/v1.1.0/heli.sql @@ -118,12 +118,17 @@ CREATE TABLE `project_order_sub` ( ALTER TABLE project_order ADD COLUMN `contract_no` VARCHAR ( 128 ) COMMENT '模具名称' AFTER customer_id; ALTER TABLE project_order_sub ADD COLUMN `unit` CHAR ( 1 ) NOT NULL COMMENT '单位' AFTER amount; +ALTER TABLE project_order ADD COLUMN `order_time` datetime NOT NULL COMMENT '单据日期' AFTER order_status; +ALTER TABLE project_order ADD COLUMN `snapshot_order_time` datetime COMMENT '快照原始单据日期' AFTER blueprint_remark; +ALTER TABLE project_order ADD COLUMN `snapshot_code` VARCHAR ( 64 ) COMMENT '快照原始单据号' AFTER blueprint_remark; +ALTER TABLE project_order ADD COLUMN `snapshot_id` BIGINT ( 20 ) COMMENT '快照原始id' AFTER blueprint_remark; +ALTER TABLE project_order ADD COLUMN `is_snapshot` TINYINT ( 1 ) NOT NULL DEFAULT '0' COMMENT '是否快照' AFTER blueprint_remark; DROP TABLE IF EXISTS `base_serial_number`; CREATE TABLE `base_serial_number` ( `id` BIGINT ( 20 ) NOT NULL AUTO_INCREMENT COMMENT '自增字段,唯一', `business_type` VARCHAR ( 32 ) NOT NULL COMMENT '业务类型 用于业务关联', - `segment` VARCHAR ( 16 ) NOT NULL COMMENT '序列参考段', + `segment` VARCHAR ( 64 ) NOT NULL COMMENT '序列参考段', `serial_number` BIGINT ( 20 ) NOT NULL DEFAULT '0' COMMENT '序列号', `status` TINYINT ( 1 ) NOT NULL DEFAULT '1' COMMENT '状态,1表示正常,2表示禁用', `creator` VARCHAR ( 64 ) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',