新火炬后端单体项目初始化代码
refactor(cms): 优化刀具管理功能和性能
刀具报废功能 - 新增 提交(/subumit)接口
刀具报废功能 - 修改完善其删除功能,同时删除报废单和报废明细
刀具报废功能 - (/add)接口中增加逻辑判断禁制同一个刀具重复申请报废
刀具领用功能 - 完善刀具寿命计算
刀具领用功能 - 完善其删除功能,同时删除领用单和领用明细
刀具入库功能 - 完善其删除功能,同时删除入库单和入库明细
把刀具库存中的库存状态,从“正常”改为“在库”。
已修改12个文件
251 ■■■■■ 文件已修改
src/main/java/org/jeecg/modules/cms/controller/CuttingInboundController.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/controller/CuttingReceiveController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/controller/CuttingScrapController.java 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/entity/CuttingInventory.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/mapper/xml/CuttingReceiveMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/service/ICuttingReceiveService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/service/ICuttingScrapDetailService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/service/ICuttingScrapService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/service/impl/CuttingInboundServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/service/impl/CuttingInventoryServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/service/impl/CuttingReceiveServiceImpl.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/service/impl/CuttingScrapServiceImpl.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/org/jeecg/modules/cms/controller/CuttingInboundController.java
@@ -10,10 +10,7 @@
import io.micrometer.core.annotation.Timed;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.cms.entity.CuttingInbound;
import org.jeecg.modules.cms.entity.CuttingInboundDetail;
import org.jeecg.modules.cms.entity.CuttingInboundInventory;
import org.jeecg.modules.cms.entity.CuttingInventory;
import org.jeecg.modules.cms.entity.*;
import org.jeecg.modules.cms.mapper.CuttingInboundMapper;
import org.jeecg.modules.cms.service.ICuttingInboundDetailService;
import org.jeecg.modules.cms.service.ICuttingInboundInventoryService;
@@ -142,6 +139,9 @@
    @DeleteMapping(value = "/delete")
    public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
        cuttingInboundService.removeById(id);
        //删除刀具领用明细表的数据
        cuttingInboundDetailService.remove
                (new QueryWrapper<CuttingInboundDetail>().eq("order_id", id));
        return Result.OK("删除成功!");
    }
@@ -289,64 +289,7 @@
    @GetMapping("/submit")
    @Timed(value = "cutting.inbound.submit", description = "刀具入库提交耗时")
    public Result<?> submit(@RequestParam("orderId") String orderId) {
//        long startTime = System.currentTimeMillis();
//        try {
//            // 1. 更新入库单状态
//            CuttingInbound cuttingInbound = cuttingInboundService.getById(orderId);
//            if (cuttingInbound == null) {
//                return Result.error("未找到对应的入库单");
//            }
//            cuttingInbound.setOrderStatus("2");
//            cuttingInboundService.updateById(cuttingInbound);
//
//            // 2. 获取入库明细
//            List<CuttingInboundDetail> detailList = cuttingInboundDetailService.lambdaQuery()
//                    .eq(CuttingInboundDetail::getOrderId, orderId)
//                    .list();
//
//            // 3. 收集所有需要保存的数据
//            List<CuttingInventory> inventoryList = new ArrayList<>();
//            List<CuttingInboundInventory> inboundInventoryList = new ArrayList<>();
//
//            for (CuttingInboundDetail detail : detailList) {
//                int quantity = detail.getReceiveNumber() != null ? detail.getReceiveNumber().intValue() : 0;
//
//                for (int i = 0; i < quantity; i++) {
//                    // 生成库存记录
//                    CuttingInventory cuttingInventory = new CuttingInventory();
//                    cuttingInventory.setCuttingId(detail.getCuttingId());
//                    cuttingInventory.setCuttingBarcode(generateUniqueBarcode(detail.getCuttingId(), i));
//                    cuttingInventory.setInventoryStatus("正常");
//                    cuttingInventory.setCurrentLife(BigDecimal.valueOf(100));
//                    inventoryList.add(cuttingInventory);
//                }
//            }
//
//            // 4. 批量保存库存记录(一次性操作)
//            if (!inventoryList.isEmpty()) {
//                cuttingInventoryService.saveBatch(inventoryList);
//
//                // 5. 为每个保存的库存记录创建关联关系
//                for (CuttingInventory inventory : inventoryList) {
//                    CuttingInboundInventory cuttingInboundInventory = new CuttingInboundInventory();
//                    cuttingInboundInventory.setOrderId(orderId);
//                    cuttingInboundInventory.setInventoryId(inventory.getId());
//                    inboundInventoryList.add(cuttingInboundInventory);
//                }
//
//                // 6. 批量保存关联关系(一次性操作)
//                cuttingInboundInventoryService.saveBatch(inboundInventoryList);
//            }
//
//            long endTime = System.currentTimeMillis();
//            log.info("刀具入库提交完成,耗时: {} s", (endTime - startTime)/1000);
//            return Result.ok("提交成功");
//
//        } catch (Exception e) {
//            long endTime = System.currentTimeMillis();
//            log.error("提交入库单失败,orderId: " + orderId + ",耗时: " + (endTime - startTime) + " ms", e);
//            return Result.error("提交失败: " + e.getMessage());
//        }
        return cuttingInboundService.submit(orderId);
    }
}
src/main/java/org/jeecg/modules/cms/controller/CuttingReceiveController.java
@@ -159,6 +159,11 @@
            cuttingInventoryService.restoreStatus(inventoryIds);
        }
        //删除刀具领用明细表的数据
        cuttingReceiveDetailService.remove
                (new QueryWrapper<CuttingReceiveDetail>().eq("order_id", id));
        return Result.OK("删除成功!");
    }
@@ -171,7 +176,6 @@
    @DeleteMapping(value = "/deleteBatch")
    public Result<String> deleteBatch(@RequestParam(name = "ids") String ids) {
        this.cuttingReceiveService.removeByIds(Arrays.asList(ids.split(",")));
        //FIXME: 批量删除时,库存状态未恢复。也需要批量恢复库存状态。
        return Result.OK("批量删除成功!");
    }
src/main/java/org/jeecg/modules/cms/controller/CuttingScrapController.java
@@ -107,25 +107,40 @@
        JSONArray jsonArray = jSONObject.getJSONArray("detailData");
        List<CuttingScrapDetail> list = jsonArray.toJavaList(CuttingScrapDetail.class);
        //做判断,申请报废的时候一个刀具只能申请一次
        for (CuttingScrapDetail temp : list) {
            //判断刀具是否已经申请报废
            QueryWrapper<CuttingScrapDetail> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("inventory_id", temp.getInventoryId());
            // 检查数据库中是否已存在相同inventoryId的报废申请
            if (cuttingScrapDetailService.count(queryWrapper) > 0) {
                cuttingScrapService.removeById(cuttingScrap.getId());//同时删除本表单
                return Result.error("刀具" + temp.getInventoryId() + "已经申请报废,请不要重复申请");
            }
        }
        // 所有检查通过后,保存所有明细数据
        for (CuttingScrapDetail temp : list) {
            temp.setOrderId(cuttingScrap.getId());
            cuttingScrapDetailService.save(temp);
        }
        // 更新库存刀具状态为"已出库"
        if (!list.isEmpty()) {
            // 收集所有需要更新状态的库存ID
            List<String> inventoryIds = list.stream()
                    .map(CuttingScrapDetail::getInventoryId) // 假设CuttingScrapDetail中有inventoryId字段
                    .filter(id -> id != null && !id.isEmpty())
                    .collect(Collectors.toList());
            if (!inventoryIds.isEmpty()) {
                // 更新库存状态为"已出库"
                cuttingInventoryService.updateStatus(inventoryIds, "待报废");
            }
        }
        return Result.OK("添加成功!");
//        // 更新库存刀具状态为"待报废"
//        if (!list.isEmpty()) {
//            // 收集所有需要更新状态的库存ID
//            List<String> inventoryIds = list.stream()
//                    .map(CuttingScrapDetail::getInventoryId) // 假设CuttingScrapDetail中有inventoryId字段
//                    .filter(id -> id != null && !id.isEmpty())
//                    .collect(Collectors.toList());
//
//            if (!inventoryIds.isEmpty()) {
//                // 更新库存状态为"待报废"
//                cuttingInventoryService.updateStatus(inventoryIds, "待报废");
//            }
//        }
    }
    /**
@@ -154,7 +169,10 @@
    //@RequiresPermissions("org.jeecg.modules:cms_cutting_scrap:delete")
    @DeleteMapping(value = "/delete")
    public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
        cuttingScrapService.removeById(id);
        cuttingScrapService.removeById(id);//删除主表数据
        //删除刀具报废明细表的数据
        cuttingScrapDetailService.remove
                (new QueryWrapper<CuttingScrapDetail>().eq("order_id", id));
        return Result.OK("删除成功!");
    }
@@ -238,4 +256,9 @@
        return Result.ok(inventoryTooList);
    }
    @GetMapping("/submit")
    public Result<?> submit(@RequestParam("orderId") String orderId) {
        return cuttingScrapService.submit(orderId);
    }
}
src/main/java/org/jeecg/modules/cms/entity/CuttingInventory.java
@@ -78,8 +78,8 @@
    @TableField(exist = false) // 表示这不是数据库字段
    private String cuttingBarcodeSearch;
    @TableField(exist = false) // 表示这不是数据库字段
    private String workpieceMaterial;
//    @TableField(exist = false) // 表示这不是数据库字段
//    private String workpieceMaterial;
    @TableField(exist = false) // 表示这不是数据库字段
    private BigDecimal ratedLife;
src/main/java/org/jeecg/modules/cms/mapper/xml/CuttingReceiveMapper.xml
@@ -15,7 +15,7 @@
        FROM cms_cutting_inventory t1
        LEFT JOIN cms_cutting_tool t2 ON t1.cutting_id = t2.id
        LEFT JOIN (select * from v_sys_dict where dict_code = 'cutting_category') t3 on t3.item_value = t2.cutting_category
        WHERE t1.inventory_status = '正常'
        WHERE t1.inventory_status = '在库'
        AND t2.del_flag = 0
    </select>
src/main/java/org/jeecg/modules/cms/service/ICuttingReceiveService.java
@@ -16,6 +16,7 @@
public interface ICuttingReceiveService extends IService<CuttingReceive> {
    IPage<Map<String, Object>> getInventoryToolList(Integer pageNo, Integer pageSize, Map<String, Object> params);
    Result<?> submit(String orderId);
    Result<?> handleBack(String orderId);
src/main/java/org/jeecg/modules/cms/service/ICuttingScrapDetailService.java
@@ -1,8 +1,10 @@
package org.jeecg.modules.cms.service;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.jeecg.modules.cms.entity.CuttingScrapDetail;
import com.baomidou.mybatisplus.extension.service.IService;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
@@ -15,4 +17,5 @@
public interface ICuttingScrapDetailService extends IService<CuttingScrapDetail> {
    public List<Map<String, Object>> detailList(String orderId);
}
src/main/java/org/jeecg/modules/cms/service/ICuttingScrapService.java
@@ -1,6 +1,7 @@
package org.jeecg.modules.cms.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.cms.entity.CuttingScrap;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -15,5 +16,6 @@
public interface ICuttingScrapService extends IService<CuttingScrap> {
    IPage<Map<String, Object>> getInventoryToolList(Integer pageNo, Integer pageSize, Map<String, Object> params);
    Result<?> submit(String orderId);
}
src/main/java/org/jeecg/modules/cms/service/impl/CuttingInboundServiceImpl.java
@@ -135,7 +135,7 @@
                    CuttingInventory cuttingInventory = new CuttingInventory();
                    cuttingInventory.setCuttingId(detail.getCuttingId());
                    cuttingInventory.setCuttingBarcode(generateUniqueBarcode(detail.getCuttingId(), i));
                    cuttingInventory.setInventoryStatus("正常");
                    cuttingInventory.setInventoryStatus("在库");
                    cuttingInventory.setCurrentLife(BigDecimal.valueOf(100));
                    inventoryList.add(cuttingInventory);
                }
src/main/java/org/jeecg/modules/cms/service/impl/CuttingInventoryServiceImpl.java
@@ -67,14 +67,13 @@
            // 方式1: 查询当前状态并根据状态决定恢复到哪个状态
            List<CuttingInventory> inventoryList = this.listByIds(ids);
            List<String> toRestoreIds = inventoryList.stream()
                    .filter(inv -> "待出库".equals(inv.getInventoryStatus())) // 只处理"待出库"状态的
                    .filter(inv -> "待出库".equals(inv.getInventoryStatus())) // 出库单作废的情况下,只会有待出库退回正常状态的情况。
                    .map(CuttingInventory::getId)
                    .collect(Collectors.toList());
            //FIXME:在报废前有多个状态,如果报废作废,刀具库存状态如何退回原来的状态。
            if (!toRestoreIds.isEmpty()) {
                UpdateWrapper<CuttingInventory> updateWrapper = new UpdateWrapper<>();
                updateWrapper.in("id", toRestoreIds);
                updateWrapper.set("inventory_status", "正常");
                updateWrapper.set("inventory_status", "在库");
                updateWrapper.set("update_time", new Date());
                updateWrapper.set("update_by", username);
                this.update(updateWrapper);
src/main/java/org/jeecg/modules/cms/service/impl/CuttingReceiveServiceImpl.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.micrometer.core.annotation.Timed;
import liquibase.pro.packaged.C;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.cms.entity.CuttingInventory;
@@ -20,6 +21,7 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -95,8 +97,10 @@
        }
    }
    @Override
    public synchronized Result<?> handleBack(String orderId) {
        //FIXME:刀具归还 目前设计的是以领用单为维度进行还库;若是需要以刀具为维度进行归还的则需要另行设计
        long startTime = System.currentTimeMillis();
        try {
            // 1. 更新领用单状态为已归还
@@ -129,32 +133,35 @@
                }
            }
            // 4. 批量更新库存状态为"正常"
            if (!inventoryIds.isEmpty()) {
                cuttingInventoryService.updateStatus(inventoryIds, "正常");
            }
            // 5. 寿命扣减
            // 4. 寿命扣减
            for (CuttingReceiveDetail detail : detailList) {
                if (detail.getInventoryId() != null && !detail.getInventoryId().isEmpty()) {
                    CuttingReceiveDetail cuttingReceiveDetail = cuttingReceiveDetailService.getById(detail.getInventoryId());
                    CuttingInventory inventory = cuttingInventoryService.getById(detail.getInventoryId());
                    //FIXME:ratedLife空指针
                    RatedLife ratedLife = ratedLifeService.lambdaQuery() //额定寿命
                            .eq(RatedLife::getCuttingId, inventory.getCuttingId())
                            .eq(RatedLife::getWorkpieceMaterial, inventory.getWorkpieceMaterial())
                            .one();
                    BigDecimal currentLife = inventory.getCurrentLife().divide(BigDecimal.valueOf(100),java.math.RoundingMode.HALF_UP);//当前寿命百分比
                    RatedLife ratedLife = ratedLifeService.lambdaQuery()
                            .eq(RatedLife::getCuttingId, detail.getCuttingId())
                            .eq(RatedLife::getWorkpieceMaterial, detail.getWorkpieceMaterial())
                            .one();//额定寿命
                    Integer useLife = detail.getUsedLife();//使用寿命
                    //计算公式: (ratedLife * currentLife - useLife) * 100
                    BigDecimal newLife = ratedLife.getRatedLife()
                            .multiply(currentLife)
                            .subtract(BigDecimal.valueOf(useLife))
                            .multiply(BigDecimal.valueOf(100));
                    //优化:(1-使用寿命/额定寿命)*100
                    BigDecimal usageRatio = BigDecimal.valueOf(useLife).divide(ratedLife.getRatedLife(), 4, RoundingMode.HALF_UP);
                    BigDecimal newLife = BigDecimal.valueOf(1)
                            .subtract(usageRatio)
                            .multiply(BigDecimal.valueOf(100))
                            .setScale(2, RoundingMode.HALF_UP);
                    // 更新库存寿命
                    inventory.setCurrentLife(newLife);
                    cuttingInventoryService.updateById(inventory);
                }
            }
            // 5. 批量更新库存状态为"正常"
            if (!inventoryIds.isEmpty()) {
                cuttingInventoryService.updateStatus(inventoryIds, "在库");
            }
            long endTime = System.currentTimeMillis();
            log.info("刀具归还处理完成,耗时: {} ms", (endTime - startTime));
            return Result.ok("归还成功");
src/main/java/org/jeecg/modules/cms/service/impl/CuttingScrapServiceImpl.java
@@ -2,13 +2,22 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.jeecg.modules.cms.entity.CuttingScrap;
import io.micrometer.core.annotation.Timed;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.cms.entity.*;
import org.jeecg.modules.cms.mapper.CuttingScrapMapper;
import org.jeecg.modules.cms.service.ICuttingInventoryService;
import org.jeecg.modules.cms.service.ICuttingScrapDetailService;
import org.jeecg.modules.cms.service.ICuttingScrapService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
@@ -17,12 +26,70 @@
 * @Date:   2025-07-28
 * @Version: V1.0
 */
@Slf4j
@Service
public class CuttingScrapServiceImpl extends ServiceImpl<CuttingScrapMapper, CuttingScrap> implements ICuttingScrapService {
    @Autowired
    private ICuttingScrapDetailService cuttingScarpDetailService;
    @Autowired
    private ICuttingInventoryService cuttingInventoryService;
    @Override
    public IPage<Map<String, Object>> getInventoryToolList(Integer pageNo, Integer pageSize, Map<String, Object> params) {
        IPage<Map> pageData = new Page<Map>(pageNo, pageSize);
        return super.getBaseMapper().getInventoryToolList(pageData,params);
    }
    @Override
    @Timed(value = "cutting.scrap.submit", description = "刀具领用提交耗时")
    public synchronized Result<?> submit(String orderId) {
        long startTime = System.currentTimeMillis();
        try {
            // 1. 更新领用单状态
            CuttingScrap cuttingScrap = this.getById(orderId);
            if (cuttingScrap == null) {
                return Result.error("未找到对应的领用单");
            }
            // 检查领用单状态,只允许状态为"1"的领用单提交
            if (!"1".equals(cuttingScrap.getOrderStatus())) {
                return Result.error("只有状态为未提交的领用单才能执行提交操作");
            }
            cuttingScrap.setOrderStatus("2"); // 报废申请单变为 已提交 状态
            boolean updateResult = this.updateById(cuttingScrap);
            if (!updateResult) {
                return Result.error("更新领用单状态失败,可能已被其他用户处理");
            }
            // 2. 获取领用明细
            List<CuttingScrapDetail> detailList = cuttingScarpDetailService.lambdaQuery()
                    .eq(CuttingScrapDetail::getOrderId, orderId)
                    .list();
            // 3. 收集所有需要更新状态的库存ID
            List<String> inventoryIds = new ArrayList<>();
            for (CuttingScrapDetail detail : detailList) {
                if (detail.getInventoryId() != null && !detail.getInventoryId().isEmpty()) {
                    inventoryIds.add(detail.getInventoryId());
                }
            }
            // 4. 批量更新库存状态为"已报废"
            if (!inventoryIds.isEmpty()) {
                cuttingInventoryService.updateStatus(inventoryIds, "已报废");
            }
            long endTime = System.currentTimeMillis();
            log.info("刀具领用提交完成,耗时: {} ms", (endTime - startTime));
            return Result.ok("提交成功");
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("提交领用单失败,orderId: " + orderId + ",耗时: " + (endTime - startTime) + " ms", e);
            return Result.error("提交失败: " + e.getMessage());
        }
    }
}